From a382238b1f0029db5d01385704ca2c191bd1c653 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Wed, 23 Oct 2024 02:35:01 +0900 Subject: [PATCH 01/17] fix: bug where parsing assistant thread message event fails for beta feature enabled apps (#2298) --- src/Assistant.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Assistant.ts b/src/Assistant.ts index 15e37aa07..da84f5cbd 100644 --- a/src/Assistant.ts +++ b/src/Assistant.ts @@ -375,7 +375,11 @@ export function extractThreadInfo(payload: AllAssistantMiddlewareArgs['payload'] let context: AssistantThreadContext = {}; // assistant_thread_started, asssistant_thread_context_changed - if ('assistant_thread' in payload) { + if ( + 'assistant_thread' in payload && + 'channel_id' in payload.assistant_thread && + 'thread_ts' in payload.assistant_thread + ) { channelId = payload.assistant_thread.channel_id; threadTs = payload.assistant_thread.thread_ts; context = payload.assistant_thread.context; From 198d7c317f901f051c636cf6786fa5633038c2c2 Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Tue, 22 Oct 2024 14:20:18 -0400 Subject: [PATCH 02/17] Publish `@slack/bolt@4.0.1` (#2299) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dbe421d9c..9362c268b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@slack/bolt", - "version": "4.0.0", + "version": "4.0.1", "description": "A framework for building Slack apps, fast.", "author": "Slack Technologies, LLC", "license": "MIT", From b671add27188f9ce1e898bf96b40d3a9860d67cd Mon Sep 17 00:00:00 2001 From: Alissa Renz Date: Fri, 25 Oct 2024 14:23:45 -0700 Subject: [PATCH 03/17] [FIX]: Include metadata with Assistant `say` util (#2300) --- src/Assistant.ts | 13 ++++++-- test/unit/Assistant.spec.ts | 62 +++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/Assistant.ts b/src/Assistant.ts index da84f5cbd..ddcc44c27 100644 --- a/src/Assistant.ts +++ b/src/Assistant.ts @@ -3,6 +3,7 @@ import type { AssistantThreadsSetSuggestedPromptsResponse, AssistantThreadsSetTitleResponse, ChatPostMessageArguments, + MessageMetadataEventPayloadObject, } from '@slack/web-api'; import { type AssistantThreadContext, @@ -301,12 +302,20 @@ export async function processAssistantMiddleware( */ function createSay(args: AllAssistantMiddlewareArgs): SayFn { const { client, payload } = args; - const { channelId: channel, threadTs: thread_ts } = extractThreadInfo(payload); + const { channelId: channel, threadTs: thread_ts, context } = extractThreadInfo(payload); - return (message: Parameters[0]) => { + return async (message: Parameters[0]) => { + const threadContext = context.channel_id ? context : await args.getThreadContext(args); const postMessageArgument: ChatPostMessageArguments = typeof message === 'string' ? { text: message, channel, thread_ts } : { ...message, channel, thread_ts }; + if (threadContext) { + postMessageArgument.metadata = { + event_type: 'assistant_thread_context', + event_payload: threadContext as MessageMetadataEventPayloadObject, + }; + } + return client.chat.postMessage(postMessageArgument); }; } diff --git a/test/unit/Assistant.spec.ts b/test/unit/Assistant.spec.ts index bbd52f8f6..61071f832 100644 --- a/test/unit/Assistant.spec.ts +++ b/test/unit/Assistant.spec.ts @@ -208,7 +208,9 @@ describe('Assistant class', () => { const mockThreadContextStore = createMockThreadContextStore(); const { enrichAssistantArgs } = await importAssistant(); // TODO: enrichAssistantArgs likely needs a different argument type, as AssistantMiddlewareArgs type already has the assistant utility enrichments present. - const assistantArgs = enrichAssistantArgs(mockThreadContextStore, { payload } as AllAssistantMiddlewareArgs); + const assistantArgs = enrichAssistantArgs(mockThreadContextStore, { + payload, + } as AllAssistantMiddlewareArgs); assert.exists(assistantArgs.say); assert.exists(assistantArgs.setStatus); @@ -221,7 +223,9 @@ describe('Assistant class', () => { const mockThreadContextStore = createMockThreadContextStore(); const { enrichAssistantArgs } = await importAssistant(); // TODO: enrichAssistantArgs likely needs a different argument type, as AssistantMiddlewareArgs type already has the assistant utility enrichments present. - const assistantArgs = enrichAssistantArgs(mockThreadContextStore, { payload } as AllAssistantMiddlewareArgs); + const assistantArgs = enrichAssistantArgs(mockThreadContextStore, { + payload, + } as AllAssistantMiddlewareArgs); assert.exists(assistantArgs.say); assert.exists(assistantArgs.setStatus); @@ -234,7 +238,9 @@ describe('Assistant class', () => { const mockThreadContextStore = createMockThreadContextStore(); const { enrichAssistantArgs } = await importAssistant(); // TODO: enrichAssistantArgs likely needs a different argument type, as AssistantMiddlewareArgs type already has the assistant utility enrichments present. - const assistantArgs = enrichAssistantArgs(mockThreadContextStore, { payload } as AllAssistantMiddlewareArgs); + const assistantArgs = enrichAssistantArgs(mockThreadContextStore, { + payload, + } as AllAssistantMiddlewareArgs); assert.exists(assistantArgs.say); assert.exists(assistantArgs.setStatus); @@ -306,6 +312,56 @@ describe('Assistant class', () => { sinon.assert.called(fakeClient.chat.postMessage); }); + it('say should be called with message_metadata that includes thread context', async () => { + const mockThreadStartedArgs = wrapMiddleware(createDummyAssistantThreadStartedEventMiddlewareArgs()); + + const fakeClient = { chat: { postMessage: sinon.spy() } }; + mockThreadStartedArgs.client = fakeClient as unknown as WebClient; + const mockThreadContextStore = createMockThreadContextStore(); + + const { enrichAssistantArgs } = await importAssistant(); + const threadStartedArgs = enrichAssistantArgs(mockThreadContextStore, mockThreadStartedArgs); + + await threadStartedArgs.say('Say called!'); + + const { + payload: { + assistant_thread: { channel_id, thread_ts, context }, + }, + } = mockThreadStartedArgs; + + const expectedParams = { + text: 'Say called!', + channel: channel_id, + thread_ts, + metadata: { + event_type: 'assistant_thread_context', + event_payload: context, + }, + }; + + sinon.assert.calledWith(fakeClient.chat.postMessage, expectedParams); + }); + + it('say should get context from store if no thread context is included in event', async () => { + const mockThreadStartedArgs = wrapMiddleware(createDummyAssistantThreadStartedEventMiddlewareArgs()); + mockThreadStartedArgs.payload.assistant_thread.context = {}; + + const fakeClient = { chat: { postMessage: sinon.spy() } }; + mockThreadStartedArgs.client = fakeClient as unknown as WebClient; + const mockThreadContextStore = { save: sinon.spy(), get: sinon.spy() }; + + const { enrichAssistantArgs } = await importAssistant(); + const threadStartedArgs = enrichAssistantArgs(mockThreadContextStore, mockThreadStartedArgs); + + // Verify that get is not called prior to say being used + sinon.assert.notCalled(mockThreadContextStore.get); + + await threadStartedArgs.say('Say called!'); + + sinon.assert.calledOnce(mockThreadContextStore.get); + }); + it('setStatus should call assistant.threads.setStatus', async () => { const mockThreadStartedArgs = wrapMiddleware(createDummyAssistantThreadStartedEventMiddlewareArgs()); From 94c3e71ebff19a62fa465ca2fda611e38f2ef73e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:05:00 -0400 Subject: [PATCH 04/17] chore(deps): bump http-proxy-middleware from 2.0.6 to 2.0.7 in /docs (#2304) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package-lock.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index fdd0d3fc7..913b4c790 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -7594,8 +7594,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "license": "MIT", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", From 0aa69adf85f82dd9d139f44c88f70d9ec389292e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:09:30 -0400 Subject: [PATCH 05/17] chore(deps-dev): bump @types/node from 22.7.7 to 22.8.1 (#2306) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9362c268b..7f23f3186 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@tsconfig/node18": "^18.2.4", "@types/chai": "^4.1.7", "@types/mocha": "^10.0.1", - "@types/node": "22.7.7", + "@types/node": "22.8.1", "@types/sinon": "^7.0.11", "@types/tsscmp": "^1.0.0", "c8": "^10.1.2", From e51960bd8058527e44af713c753534723dd15ba9 Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Tue, 29 Oct 2024 09:48:48 -0400 Subject: [PATCH 06/17] chore: remove old inapplicable gemfile from docs (#2305) Co-authored-by: Luke Russell <31357343+lukegalbraithrussell@users.noreply.github.com> --- docs/.gitignore | 3 - docs/Gemfile.lock | 285 ---------------------------------------------- 2 files changed, 288 deletions(-) delete mode 100644 docs/Gemfile.lock diff --git a/docs/.gitignore b/docs/.gitignore index 7f541635e..5a5087045 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -2,6 +2,3 @@ node_modules/ .docusaurus .DS_Store build/ -.stylelintrc.json -_site -Gemfile.lock diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock deleted file mode 100644 index 5d66e4afa..000000000 --- a/docs/Gemfile.lock +++ /dev/null @@ -1,285 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - activesupport (6.0.4.7) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.11.1) - colorator (1.1.0) - commonmarker (0.23.4) - concurrent-ruby (1.1.10) - dnsruby (1.61.9) - simpleidn (~> 0.1) - dotenv (2.7.6) - em-websocket (0.5.3) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0) - ethon (0.15.0) - ffi (>= 1.15.0) - eventmachine (1.2.7) - execjs (2.8.1) - faraday (1.10.0) - faraday-em_http (~> 1.0) - faraday-em_synchrony (~> 1.0) - faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0) - faraday-multipart (~> 1.0) - faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.0) - faraday-patron (~> 1.0) - faraday-rack (~> 1.0) - faraday-retry (~> 1.0) - ruby2_keywords (>= 0.0.4) - faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) - faraday-excon (1.1.0) - faraday-httpclient (1.0.1) - faraday-multipart (1.0.3) - multipart-post (>= 1.2, < 3) - faraday-net_http (1.0.1) - faraday-net_http_persistent (1.2.0) - faraday-patron (1.0.0) - faraday-rack (1.0.0) - faraday-retry (1.0.3) - ffi (1.15.5) - forwardable-extended (2.6.0) - gemoji (3.0.1) - github-pages (225) - github-pages-health-check (= 1.17.9) - jekyll (= 3.9.0) - jekyll-avatar (= 0.7.0) - jekyll-coffeescript (= 1.1.1) - jekyll-commonmark-ghpages (= 0.2.0) - jekyll-default-layout (= 0.1.4) - jekyll-feed (= 0.15.1) - jekyll-gist (= 1.5.0) - jekyll-github-metadata (= 2.13.0) - jekyll-include-cache (= 0.2.1) - jekyll-mentions (= 1.6.0) - jekyll-optional-front-matter (= 0.3.2) - jekyll-paginate (= 1.1.0) - jekyll-readme-index (= 0.3.0) - jekyll-redirect-from (= 0.16.0) - jekyll-relative-links (= 0.6.1) - jekyll-remote-theme (= 0.4.3) - jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.8.0) - jekyll-sitemap (= 1.4.0) - jekyll-swiss (= 1.0.0) - jekyll-theme-architect (= 0.2.0) - jekyll-theme-cayman (= 0.2.0) - jekyll-theme-dinky (= 0.2.0) - jekyll-theme-hacker (= 0.2.0) - jekyll-theme-leap-day (= 0.2.0) - jekyll-theme-merlot (= 0.2.0) - jekyll-theme-midnight (= 0.2.0) - jekyll-theme-minimal (= 0.2.0) - jekyll-theme-modernist (= 0.2.0) - jekyll-theme-primer (= 0.6.0) - jekyll-theme-slate (= 0.2.0) - jekyll-theme-tactile (= 0.2.0) - jekyll-theme-time-machine (= 0.2.0) - jekyll-titles-from-headings (= 0.5.3) - jemoji (= 0.12.0) - kramdown (= 2.3.1) - kramdown-parser-gfm (= 1.1.0) - liquid (= 4.0.3) - mercenary (~> 0.3) - minima (= 2.5.1) - nokogiri (>= 1.12.5, < 2.0) - rouge (= 3.26.0) - terminal-table (~> 1.4) - github-pages-health-check (1.17.9) - addressable (~> 2.3) - dnsruby (~> 1.60) - octokit (~> 4.0) - public_suffix (>= 3.0, < 5.0) - typhoeus (~> 1.3) - html-pipeline (2.14.1) - activesupport (>= 2) - nokogiri (>= 1.4) - http_parser.rb (0.8.0) - i18n (0.9.5) - concurrent-ruby (~> 1.0) - jekyll (3.9.0) - addressable (~> 2.4) - colorator (~> 1.0) - em-websocket (~> 0.5) - i18n (~> 0.7) - jekyll-sass-converter (~> 1.0) - jekyll-watch (~> 2.0) - kramdown (>= 1.17, < 3) - liquid (~> 4.0) - mercenary (~> 0.3.3) - pathutil (~> 0.9) - rouge (>= 1.7, < 4) - safe_yaml (~> 1.0) - jekyll-avatar (0.7.0) - jekyll (>= 3.0, < 5.0) - jekyll-coffeescript (1.1.1) - coffee-script (~> 2.2) - coffee-script-source (~> 1.11.1) - jekyll-commonmark (1.4.0) - commonmarker (~> 0.22) - jekyll-commonmark-ghpages (0.2.0) - commonmarker (~> 0.23.4) - jekyll (~> 3.9.0) - jekyll-commonmark (~> 1.4.0) - rouge (>= 2.0, < 4.0) - jekyll-default-layout (0.1.4) - jekyll (~> 3.0) - jekyll-feed (0.15.1) - jekyll (>= 3.7, < 5.0) - jekyll-gist (1.5.0) - octokit (~> 4.2) - jekyll-github-metadata (2.13.0) - jekyll (>= 3.4, < 5.0) - octokit (~> 4.0, != 4.4.0) - jekyll-include-cache (0.2.1) - jekyll (>= 3.7, < 5.0) - jekyll-mentions (1.6.0) - html-pipeline (~> 2.3) - jekyll (>= 3.7, < 5.0) - jekyll-optional-front-matter (0.3.2) - jekyll (>= 3.0, < 5.0) - jekyll-paginate (1.1.0) - jekyll-readme-index (0.3.0) - jekyll (>= 3.0, < 5.0) - jekyll-redirect-from (0.16.0) - jekyll (>= 3.3, < 5.0) - jekyll-relative-links (0.6.1) - jekyll (>= 3.3, < 5.0) - jekyll-remote-theme (0.4.3) - addressable (~> 2.0) - jekyll (>= 3.5, < 5.0) - jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) - rubyzip (>= 1.3.0, < 3.0) - jekyll-sass-converter (1.5.2) - sass (~> 3.4) - jekyll-seo-tag (2.8.0) - jekyll (>= 3.8, < 5.0) - jekyll-sitemap (1.4.0) - jekyll (>= 3.7, < 5.0) - jekyll-swiss (1.0.0) - jekyll-theme-architect (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.6.0) - jekyll (> 3.5, < 5.0) - jekyll-github-metadata (~> 2.9) - jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-titles-from-headings (0.5.3) - jekyll (>= 3.3, < 5.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - jemoji (0.12.0) - gemoji (~> 3.0) - html-pipeline (~> 2.2) - jekyll (>= 3.0, < 5.0) - kramdown (2.3.1) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.3) - listen (3.7.1) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - mercenary (0.3.6) - mini_portile2 (2.8.0) - minima (2.5.1) - jekyll (>= 3.5, < 5.0) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) - minitest (5.15.0) - multipart-post (2.1.1) - nokogiri (1.13.4) - mini_portile2 (~> 2.8.0) - racc (~> 1.4) - octokit (4.22.0) - faraday (>= 0.9) - sawyer (~> 0.8.0, >= 0.5.3) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (4.0.7) - racc (1.6.0) - rb-fsevent (0.11.1) - rb-inotify (0.10.1) - ffi (~> 1.0) - rexml (3.2.5) - rouge (3.26.0) - ruby2_keywords (0.0.5) - rubyzip (2.3.2) - safe_yaml (1.0.5) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.8.2) - addressable (>= 2.3.5) - faraday (> 0.8, < 2.0) - simpleidn (0.2.1) - unf (~> 0.1.4) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - thread_safe (0.3.6) - typhoeus (1.4.0) - ethon (>= 0.9.0) - tzinfo (1.2.9) - thread_safe (~> 0.1) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.1) - unicode-display_width (1.8.0) - zeitwerk (2.5.4) - -PLATFORMS - ruby - -DEPENDENCIES - dotenv - github-pages - -BUNDLED WITH - 2.1.4 From d3fe549b6c83dd1cf9e32c0fffcb2868f2388b2f Mon Sep 17 00:00:00 2001 From: Luke Russell <31357343+lukegalbraithrussell@users.noreply.github.com> Date: Tue, 29 Oct 2024 08:23:43 -0700 Subject: [PATCH 07/17] docs: concept focused nav (#2302) Co-authored-by: Kazuhiro Sera --- docs/content/basic/action-respond.md | 36 -- docs/content/basic/event-listening.md | 53 --- docs/content/basic/message-listening.md | 41 --- .../{basic => concepts}/acknowledge.md | 0 .../actions.md} | 49 ++- .../authenticating-oauth.md | 0 .../{advanced => concepts}/authorization.md | 0 docs/content/{basic => concepts}/commands.md | 4 +- .../content/{advanced => concepts}/context.md | 0 .../{basic => concepts}/creating-modals.md | 0 .../{advanced => concepts}/custom-routes.md | 0 .../{basic => concepts}/custom-steps.md | 6 +- .../deferring-initialization.md | 0 .../{advanced => concepts}/error-handling.md | 0 docs/content/concepts/event-listening.md | 28 ++ .../global-middleware.md | 0 .../listener-middleware.md | 0 .../content/{advanced => concepts}/logging.md | 0 docs/content/concepts/message-listening.md | 56 +++ .../{basic => concepts}/message-sending.md | 0 .../{basic => concepts}/publishing-views.md | 0 .../{advanced => concepts}/receiver.md | 0 .../select-menu-options.md} | 4 +- docs/content/{basic => concepts}/shortcuts.md | 2 +- .../{basic => concepts}/socket-mode.md | 0 .../{advanced => concepts}/token-rotation.md | 0 .../updating-pushing-views.md | 2 +- .../{basic => concepts}/view-submissions.md | 0 docs/content/{basic => concepts}/web-api.md | 2 +- ...getting-started.md => getting-started.mdx} | 211 +++++++++++- .../conversation-store.md | 0 .../{tutorial => legacy}/hubot-migration.md | 4 +- docs/content/legacy/steps-from-apps.md | 198 +++++++++++ .../{tutorial => migration}/migration-v2.md | 4 +- .../{tutorial => migration}/migration-v3.md | 2 +- .../{tutorial => migration}/migration-v4.md | 4 +- docs/content/reference.md | 4 +- docs/content/steps/adding-editing-steps.md | 70 ---- docs/content/steps/creating-steps.md | 42 --- docs/content/steps/executing-steps.md | 49 --- docs/content/steps/saving-steps.md | 60 ---- docs/content/steps/steps.md | 29 -- docs/content/tutorial/getting-started-http.md | 326 ------------------ docs/docusaurus.config.js | 18 +- docs/i18n/ja-jp/README.md | 2 +- .../current.json | 56 ++- .../current/basic/action-respond.md | 37 -- .../current/basic/custom-steps.md | 167 --------- .../{basic => concepts}/acknowledge.md | 0 .../actions.md} | 40 ++- .../authenticating-oauth.md | 0 .../{advanced => concepts}/authorization.md | 0 .../current/{basic => concepts}/commands.md | 2 +- .../current/{advanced => concepts}/context.md | 0 .../{basic => concepts}/creating-modals.md | 0 .../{advanced => concepts}/custom-routes.md | 0 .../deferring-initialization.md | 0 .../{advanced => concepts}/error-handling.md | 0 .../{basic => concepts}/event-listening.md | 27 +- .../global-middleware.md | 0 .../listener-middleware.md | 0 .../current/{advanced => concepts}/logging.md | 0 .../{basic => concepts}/message-listening.md | 27 +- .../{basic => concepts}/message-sending.md | 0 .../{basic => concepts}/publishing-views.md | 0 .../{advanced => concepts}/receiver.md | 0 .../select-menu-options.md} | 2 +- .../current/{basic => concepts}/shortcuts.md | 0 .../{basic => concepts}/socket-mode.md | 0 .../{advanced => concepts}/token-rotation.md | 0 .../updating-pushing-views.md | 0 .../{basic => concepts}/view-submissions.md | 0 .../current/{basic => concepts}/web-api.md | 0 ...getting-started.md => getting-started.mdx} | 213 +++++++++++- .../conversation-store.md | 0 .../{tutorials => legacy}/hubot-migration.md | 2 +- .../current/legacy/steps-from-apps.md | 194 +++++++++++ .../{tutorials => migration}/migration-v2.md | 4 +- .../{tutorials => migration}/migration-v3.md | 2 +- .../current/reference.md | 16 +- .../current/steps/adding-editing-steps.md | 60 ---- .../current/steps/creating-steps.md | 33 -- .../current/steps/executing-steps.md | 37 -- .../current/steps/saving-steps.md | 50 --- .../current/steps/steps.md | 17 - .../current/tutorials/getting-started-http.md | 324 ----------------- .../docusaurus-theme-classic/navbar.json | 4 + docs/sidebars.js | 156 ++++----- docs/src/css/custom.css | 6 + 89 files changed, 1134 insertions(+), 1648 deletions(-) delete mode 100644 docs/content/basic/action-respond.md delete mode 100644 docs/content/basic/event-listening.md delete mode 100644 docs/content/basic/message-listening.md rename docs/content/{basic => concepts}/acknowledge.md (100%) rename docs/content/{basic/action-listening.md => concepts/actions.md} (53%) rename docs/content/{basic => concepts}/authenticating-oauth.md (100%) rename docs/content/{advanced => concepts}/authorization.md (100%) rename docs/content/{basic => concepts}/commands.md (93%) rename docs/content/{advanced => concepts}/context.md (100%) rename docs/content/{basic => concepts}/creating-modals.md (100%) rename docs/content/{advanced => concepts}/custom-routes.md (100%) rename docs/content/{basic => concepts}/custom-steps.md (97%) rename docs/content/{advanced => concepts}/deferring-initialization.md (100%) rename docs/content/{advanced => concepts}/error-handling.md (100%) create mode 100644 docs/content/concepts/event-listening.md rename docs/content/{advanced => concepts}/global-middleware.md (100%) rename docs/content/{advanced => concepts}/listener-middleware.md (100%) rename docs/content/{advanced => concepts}/logging.md (100%) create mode 100644 docs/content/concepts/message-listening.md rename docs/content/{basic => concepts}/message-sending.md (100%) rename docs/content/{basic => concepts}/publishing-views.md (100%) rename docs/content/{advanced => concepts}/receiver.md (100%) rename docs/content/{basic/options.md => concepts/select-menu-options.md} (91%) rename docs/content/{basic => concepts}/shortcuts.md (99%) rename docs/content/{basic => concepts}/socket-mode.md (100%) rename docs/content/{advanced => concepts}/token-rotation.md (100%) rename docs/content/{basic => concepts}/updating-pushing-views.md (98%) rename docs/content/{basic => concepts}/view-submissions.md (100%) rename docs/content/{basic => concepts}/web-api.md (96%) rename docs/content/{getting-started.md => getting-started.mdx} (68%) rename docs/content/{advanced => legacy}/conversation-store.md (100%) rename docs/content/{tutorial => legacy}/hubot-migration.md (99%) create mode 100644 docs/content/legacy/steps-from-apps.md rename docs/content/{tutorial => migration}/migration-v2.md (99%) rename docs/content/{tutorial => migration}/migration-v3.md (99%) rename docs/content/{tutorial => migration}/migration-v4.md (96%) delete mode 100644 docs/content/steps/adding-editing-steps.md delete mode 100644 docs/content/steps/creating-steps.md delete mode 100644 docs/content/steps/executing-steps.md delete mode 100644 docs/content/steps/saving-steps.md delete mode 100644 docs/content/steps/steps.md delete mode 100644 docs/content/tutorial/getting-started-http.md delete mode 100644 docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/action-respond.md delete mode 100644 docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/custom-steps.md rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/acknowledge.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic/action-listening.md => concepts/actions.md} (60%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/authenticating-oauth.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => concepts}/authorization.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/commands.md (94%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => concepts}/context.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/creating-modals.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => concepts}/custom-routes.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => concepts}/deferring-initialization.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => concepts}/error-handling.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/event-listening.md (51%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => concepts}/global-middleware.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => concepts}/listener-middleware.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => concepts}/logging.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/message-listening.md (54%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/message-sending.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/publishing-views.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => concepts}/receiver.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic/options.md => concepts/select-menu-options.md} (92%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/shortcuts.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/socket-mode.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => concepts}/token-rotation.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/updating-pushing-views.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/view-submissions.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{basic => concepts}/web-api.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{getting-started.md => getting-started.mdx} (70%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{advanced => legacy}/conversation-store.md (100%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{tutorials => legacy}/hubot-migration.md (97%) create mode 100644 docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/steps-from-apps.md rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{tutorials => migration}/migration-v2.md (96%) rename docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/{tutorials => migration}/migration-v3.md (99%) delete mode 100644 docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/adding-editing-steps.md delete mode 100644 docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/creating-steps.md delete mode 100644 docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/executing-steps.md delete mode 100644 docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/saving-steps.md delete mode 100644 docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/steps.md delete mode 100644 docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/getting-started-http.md diff --git a/docs/content/basic/action-respond.md b/docs/content/basic/action-respond.md deleted file mode 100644 index 958471935..000000000 --- a/docs/content/basic/action-respond.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: Responding to actions -lang: en -slug: /concepts/action-respond ---- - -There are two main ways to respond to actions. The first (and most common) way is to use the `say` function. The `say` function sends a message back to the conversation where the incoming request took place. - -The second way to respond to actions is using `respond()`, which is a simple utility to use the `response_url` associated with an action. - -```javascript -// 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 👍'); -}); -``` - -
- -Using `respond()` - - -Since `respond()` is a utility for calling the `response_url`, it behaves in the same way. You can pass a JSON object with a new message payload that will be published back to the source of the original interaction with optional properties like `response_type` (which has a value of `in_channel` or `ephemeral`), `replace_original`, and `delete_original`. - -```javascript -// Listens to actions triggered with action_id of “user_select” -app.action('user_select', async ({ action, ack, respond }) => { - await ack(); - if (action.type === 'users_select') { - await respond(`You selected <@${action.selected_user}>`); - } -}); -``` -
diff --git a/docs/content/basic/event-listening.md b/docs/content/basic/event-listening.md deleted file mode 100644 index b71ad2298..000000000 --- a/docs/content/basic/event-listening.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Listening to events -lang: en -slug: /concepts/event-listening ---- - -You can listen to [any Events API event](https://api.slack.com/events) using the `event()` method after subscribing to it in your app configuration. This allows your app to take action when something happens in Slack, like a user reacting to a message or joining a channel. - -The `event()` method requires an `eventType` of type string. - -```javascript -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, logger }) => { - try { - // Call chat.postMessage with the built-in client - const result = await client.chat.postMessage({ - channel: welcomeChannelId, - text: `Welcome to the team, <@${event.user.id}>! 🎉 You can introduce yourself in this channel.` - }); - logger.info(result); - } - catch (error) { - logger.error(error); - } -}); -``` - -
- -Filtering on message subtypes - - -A `message()` listener is equivalent to `event('message')` - -You can filter on subtypes of events by using the built-in `subtype()` middleware. Common message subtypes like `message_changed` and `message_replied` can be found [on the message event page](https://api.slack.com/events/message#message_subtypes). - -```javascript -// Import subtype from the package -const { App, subtype } = require('@slack/bolt'); - -// Matches all message changes from users -app.message(subtype('message_changed'), ({ event, logger }) => { - // This if statement is required in TypeScript code - if (event.subtype === 'message_changed' - && !event.message.subtype - && !event.previous_message.subtype) { - logger.info(`The user ${event.message.user} changed their message from ${event.previous_message.text} to ${event.message.text}`); - } -}); -``` -
\ No newline at end of file diff --git a/docs/content/basic/message-listening.md b/docs/content/basic/message-listening.md deleted file mode 100644 index 8a8b6f479..000000000 --- a/docs/content/basic/message-listening.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: Listening to messages -lang: en -slug: /concepts/message-listening ---- - -To listen to messages that [your app has access to receive](https://api.slack.com/messaging/retrieving#permissions), you can use the `message()` method which filters out events that aren’t of type `message`. - -`message()` accepts an optional `pattern` parameter of type `string` or `RegExp` object which filters out any messages that don’t match the pattern. - -```javascript -// This will match any message that contains 👋 -app.message(':wave:', async ({ message, say }) => { - // Handle only newly posted messages here - if (message.subtype === undefined - || message.subtype === 'bot_message' - || message.subtype === 'file_share' - || message.subtype === 'thread_broadcast') { - await say(`Hello, <@${message.user}>`); - } -}); -``` - -
- -Using a RegExp pattern - - -A RegExp pattern can be used instead of a string for more granular matching. - -All of the results of the RegExp match will be in `context.matches`. - -```javascript -app.message(/^(hi|hello|hey).*/, async ({ context, say }) => { - // RegExp matches are inside of context.matches - const greeting = context.matches[0]; - - await say(`${greeting}, how are you?`); -}); -``` -
\ No newline at end of file diff --git a/docs/content/basic/acknowledge.md b/docs/content/concepts/acknowledge.md similarity index 100% rename from docs/content/basic/acknowledge.md rename to docs/content/concepts/acknowledge.md diff --git a/docs/content/basic/action-listening.md b/docs/content/concepts/actions.md similarity index 53% rename from docs/content/basic/action-listening.md rename to docs/content/concepts/actions.md index e61b50c32..d64cfc780 100644 --- a/docs/content/basic/action-listening.md +++ b/docs/content/concepts/actions.md @@ -1,21 +1,17 @@ --- -title: Listening to actions +title: Listening & responding to actions lang: en -slug: /concepts/action-listening +slug: /concepts/actions --- -Your app can listen to user actions like button clicks, and menu selects, using the `action` method. +Your app can listen and respond to user actions like button clicks, and menu selects, using the `action` method. + +## Listening to actions Actions can be filtered on an `action_id` of type string or RegExp object. `action_id`s act as unique identifiers for interactive components on the Slack platform. You’ll notice in all `action()` examples, `ack()` is used. It is required to call the `ack()` function within an action listener to acknowledge that the request was received from Slack. This is discussed in the [acknowledging requests section](/concepts/acknowledge). -:::info - -Since v2, message shortcuts (previously message actions) now use the `shortcut()` method instead of the `action()` method. View the [migration guide for V2](/tutorial/migration-v2) to learn about the changes. - -::: - View more information about the `block_actions` payload within the [relevant API documentation page](https://api.slack.com/reference/interaction-payloads). To access the full payload of a view from within a listener, reference the `body` argument within your callback function. ```javascript @@ -26,10 +22,7 @@ app.action('approve_button', async ({ ack }) => { }); ``` -
- -Listening to actions using a constraint object - +### Listening to actions using a constraint object You can use a constraints object to listen to `callback_id`s, `block_id`s, and `action_id`s (or any combination of them). Constraints in the object can be of type string or RegExp object. @@ -56,4 +49,32 @@ app.action({ action_id: 'select_user', block_id: 'assign_ticket' }, }); ``` -
\ No newline at end of file +## Responding to actions + +There are two main ways to respond to actions. The first (and most common) way is to use the `say` function. The `say` function sends a message back to the conversation where the incoming request took place. + +The second way to respond to actions is using `respond()`, which is a simple utility to use the `response_url` associated with an action. + +```javascript +// 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 👍'); +}); +``` + + +### Using the `respond()` utility + +Since `respond()` is a utility for calling the `response_url`, it behaves in the same way. You can pass a JSON object with a new message payload that will be published back to the source of the original interaction with optional properties like `response_type` (which has a value of `in_channel` or `ephemeral`), `replace_original`, and `delete_original`. + +```javascript +// Listens to actions triggered with action_id of “user_select” +app.action('user_select', async ({ action, ack, respond }) => { + await ack(); + if (action.type === 'users_select') { + await respond(`You selected <@${action.selected_user}>`); + } +}); +``` \ No newline at end of file diff --git a/docs/content/basic/authenticating-oauth.md b/docs/content/concepts/authenticating-oauth.md similarity index 100% rename from docs/content/basic/authenticating-oauth.md rename to docs/content/concepts/authenticating-oauth.md diff --git a/docs/content/advanced/authorization.md b/docs/content/concepts/authorization.md similarity index 100% rename from docs/content/advanced/authorization.md rename to docs/content/concepts/authorization.md diff --git a/docs/content/basic/commands.md b/docs/content/concepts/commands.md similarity index 93% rename from docs/content/basic/commands.md rename to docs/content/concepts/commands.md index c16d8ad89..9a173efdf 100644 --- a/docs/content/basic/commands.md +++ b/docs/content/concepts/commands.md @@ -1,5 +1,5 @@ --- -title: Listening and responding to commands +title: Listening & responding to commands lang: en slug: /concepts/commands --- @@ -14,7 +14,7 @@ If you use `command()` multiple times with overlapping RegExp matches, _all_ mat Commands must be acknowledged with `ack()` to inform Slack your app has received the request. -There are two ways to respond to slash commands. The first way is to use `say()`, which accepts a string or JSON payload. The second is `respond()` which is a utility for the `response_url`. These are explained in more depth in the [responding to actions](/concepts/action-respond) section. +There are two ways to respond to slash commands. The first way is to use `say()`, which accepts a string or JSON payload. The second is `respond()` which is a utility for the `response_url`. These are explained in more depth in the [responding to actions](/concepts/actions) section. When configuring commands within your app configuration, you'll continue to append `/slack/events` to your request URL. diff --git a/docs/content/advanced/context.md b/docs/content/concepts/context.md similarity index 100% rename from docs/content/advanced/context.md rename to docs/content/concepts/context.md diff --git a/docs/content/basic/creating-modals.md b/docs/content/concepts/creating-modals.md similarity index 100% rename from docs/content/basic/creating-modals.md rename to docs/content/concepts/creating-modals.md diff --git a/docs/content/advanced/custom-routes.md b/docs/content/concepts/custom-routes.md similarity index 100% rename from docs/content/advanced/custom-routes.md rename to docs/content/concepts/custom-routes.md diff --git a/docs/content/basic/custom-steps.md b/docs/content/concepts/custom-steps.md similarity index 97% rename from docs/content/basic/custom-steps.md rename to docs/content/concepts/custom-steps.md index 495745551..f54c01cd1 100644 --- a/docs/content/basic/custom-steps.md +++ b/docs/content/concepts/custom-steps.md @@ -1,5 +1,5 @@ --- -title: Listening and responding to custom steps +title: Custom Steps lang: en slug: /concepts/custom-steps --- @@ -64,11 +64,11 @@ Example app manifest definition --- -### Listening to custom step interactivity events +## Listening to custom step interactivity events Your app's custom steps may create interactivity points for users, for example: Post a message with a button -If such interaction points originate from a custom step execution, the events sent to your app representing the end-user interaction with these points are considered to be _function-scoped interactivity events_. These interactivity events can be handled by your app using the same concepts we covered earlier, such as [Listening to actions](/concepts/action-listening). +If such interaction points originate from a custom step execution, the events sent to your app representing the end-user interaction with these points are considered to be _function-scoped interactivity events_. These interactivity events can be handled by your app using the same concepts we covered earlier, such as [Listening to actions](/concepts/actions). _function-scoped interactivity events_ will contain data related to the custom step (`function_executed` event) they were spawned from, such as custom step `inputs` and access to `complete()` and `fail()` listener arguments. diff --git a/docs/content/advanced/deferring-initialization.md b/docs/content/concepts/deferring-initialization.md similarity index 100% rename from docs/content/advanced/deferring-initialization.md rename to docs/content/concepts/deferring-initialization.md diff --git a/docs/content/advanced/error-handling.md b/docs/content/concepts/error-handling.md similarity index 100% rename from docs/content/advanced/error-handling.md rename to docs/content/concepts/error-handling.md diff --git a/docs/content/concepts/event-listening.md b/docs/content/concepts/event-listening.md new file mode 100644 index 000000000..92d4025c7 --- /dev/null +++ b/docs/content/concepts/event-listening.md @@ -0,0 +1,28 @@ +--- +title: Listening to events +lang: en +slug: /concepts/event-listening +--- + +You can listen to any [Events API event](https://api.slack.com/events) using the `event()` method after subscribing to it in your app configuration. This allows your app to take action when something happens in Slack, like a user reacting to a message or joining a channel. + +The `event()` method requires an `eventType` of type string. + +```javascript +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, logger }) => { + try { + // Call chat.postMessage with the built-in client + const result = await client.chat.postMessage({ + channel: welcomeChannelId, + text: `Welcome to the team, <@${event.user.id}>! 🎉 You can introduce yourself in this channel.` + }); + logger.info(result); + } + catch (error) { + logger.error(error); + } +}); +``` \ No newline at end of file diff --git a/docs/content/advanced/global-middleware.md b/docs/content/concepts/global-middleware.md similarity index 100% rename from docs/content/advanced/global-middleware.md rename to docs/content/concepts/global-middleware.md diff --git a/docs/content/advanced/listener-middleware.md b/docs/content/concepts/listener-middleware.md similarity index 100% rename from docs/content/advanced/listener-middleware.md rename to docs/content/concepts/listener-middleware.md diff --git a/docs/content/advanced/logging.md b/docs/content/concepts/logging.md similarity index 100% rename from docs/content/advanced/logging.md rename to docs/content/concepts/logging.md diff --git a/docs/content/concepts/message-listening.md b/docs/content/concepts/message-listening.md new file mode 100644 index 000000000..77b2b2914 --- /dev/null +++ b/docs/content/concepts/message-listening.md @@ -0,0 +1,56 @@ +--- +title: Listening to messages +lang: en +slug: /concepts/message-listening +--- + +To listen to messages that [your app has access to receive](https://api.slack.com/messaging/retrieving#permissions), you can use the `message()` method which filters out events that aren’t of type `message` .A `message()` listener is equivalent to `event('message')` + +The `message()` listener accepts an optional `pattern` parameter of type `string` or `RegExp` object which filters out any messages that don’t match the pattern. + +```javascript +// This will match any message that contains 👋 +app.message(':wave:', async ({ message, say }) => { + // Handle only newly posted messages here + if (message.subtype === undefined + || message.subtype === 'bot_message' + || message.subtype === 'file_share' + || message.subtype === 'thread_broadcast') { + await say(`Hello, <@${message.user}>`); + } +}); +``` + +## Using a RegExp pattern {#using-regexp} + +A RegExp pattern can be used instead of a string for more granular matching. + +All of the results of the RegExp match will be in `context.matches`. + +```javascript +app.message(/^(hi|hello|hey).*/, async ({ context, say }) => { + // RegExp matches are inside of context.matches + const greeting = context.matches[0]; + + await say(`${greeting}, how are you?`); +}); +``` + +## Filtering on event subtypes {#filtering-event-subtypes} + +You can filter on subtypes of events by using the built-in `subtype()` middleware. Common message subtypes like `message_changed` and `message_replied` can be found [on the message event page](https://api.slack.com/events/message#message_subtypes). + +```javascript +// Import subtype from the package +const { App, subtype } = require('@slack/bolt'); + +// Matches all message changes from users +app.message(subtype('message_changed'), ({ event, logger }) => { + // This if statement is required in TypeScript code + if (event.subtype === 'message_changed' + && !event.message.subtype + && !event.previous_message.subtype) { + logger.info(`The user ${event.message.user} changed their message from ${event.previous_message.text} to ${event.message.text}`); + } +}); +``` diff --git a/docs/content/basic/message-sending.md b/docs/content/concepts/message-sending.md similarity index 100% rename from docs/content/basic/message-sending.md rename to docs/content/concepts/message-sending.md diff --git a/docs/content/basic/publishing-views.md b/docs/content/concepts/publishing-views.md similarity index 100% rename from docs/content/basic/publishing-views.md rename to docs/content/concepts/publishing-views.md diff --git a/docs/content/advanced/receiver.md b/docs/content/concepts/receiver.md similarity index 100% rename from docs/content/advanced/receiver.md rename to docs/content/concepts/receiver.md diff --git a/docs/content/basic/options.md b/docs/content/concepts/select-menu-options.md similarity index 91% rename from docs/content/basic/options.md rename to docs/content/concepts/select-menu-options.md index 475e554e5..6589cd3d4 100644 --- a/docs/content/basic/options.md +++ b/docs/content/concepts/select-menu-options.md @@ -1,10 +1,10 @@ --- -title: Listening and responding to options +title: Listening & responding to select menu options lang: en slug: /concepts/options --- -The `options()` method listens for incoming option request payloads from Slack. [Similar to `action()`](/concepts/action-listening), +The `options()` method listens for incoming option request payloads from Slack. [Similar to `action()`](/concepts/actions), an `action_id` or constraints object is required. While it's recommended to use `action_id` for `external_select` menus, dialogs do not yet support Block Kit so you'll have to diff --git a/docs/content/basic/shortcuts.md b/docs/content/concepts/shortcuts.md similarity index 99% rename from docs/content/basic/shortcuts.md rename to docs/content/concepts/shortcuts.md index 4ff2bcf6c..0c57d792e 100644 --- a/docs/content/basic/shortcuts.md +++ b/docs/content/concepts/shortcuts.md @@ -1,5 +1,5 @@ --- -title: Listening and responding to shortcuts +title: Listening & responding to shortcuts lang: en slug: /concepts/shortcuts --- diff --git a/docs/content/basic/socket-mode.md b/docs/content/concepts/socket-mode.md similarity index 100% rename from docs/content/basic/socket-mode.md rename to docs/content/concepts/socket-mode.md diff --git a/docs/content/advanced/token-rotation.md b/docs/content/concepts/token-rotation.md similarity index 100% rename from docs/content/advanced/token-rotation.md rename to docs/content/concepts/token-rotation.md diff --git a/docs/content/basic/updating-pushing-views.md b/docs/content/concepts/updating-pushing-views.md similarity index 98% rename from docs/content/basic/updating-pushing-views.md rename to docs/content/concepts/updating-pushing-views.md index 485678af1..3ccf4f14a 100644 --- a/docs/content/basic/updating-pushing-views.md +++ b/docs/content/concepts/updating-pushing-views.md @@ -1,5 +1,5 @@ --- -title: Updating and pushing views +title: Updating & pushing views lang: en slug: /concepts/updating-pushing-views --- diff --git a/docs/content/basic/view-submissions.md b/docs/content/concepts/view-submissions.md similarity index 100% rename from docs/content/basic/view-submissions.md rename to docs/content/concepts/view-submissions.md diff --git a/docs/content/basic/web-api.md b/docs/content/concepts/web-api.md similarity index 96% rename from docs/content/basic/web-api.md rename to docs/content/concepts/web-api.md index c6c2f27cd..0e1b3cdbe 100644 --- a/docs/content/basic/web-api.md +++ b/docs/content/concepts/web-api.md @@ -4,7 +4,7 @@ lang: en slug: /concepts/web-api --- -You can call [any Web API method](https://api.slack.com/methods) using the [`WebClient`](https://tools.slack.dev/node-slack-sdk/web-api) provided to your app's listeners as `client`. This uses either the token that initialized your app **or** the token that is returned from the [`authorize`](/concepts/authorization) function for the incoming event. The built-in [OAuth support](/concepts/authenticating-oauth) handles the second case by default. +You can call any [Web API method](https://api.slack.com/methods) using the [`WebClient`](https://tools.slack.dev/node-slack-sdk/web-api) provided to your app's listeners as `client`. This uses either the token that initialized your app **or** the token that is returned from the [`authorize`](/concepts/authorization) function for the incoming event. The built-in [OAuth support](/concepts/authenticating-oauth) handles the second case by default. Your Bolt app also has a top-level `app.client` which you can manually pass the `token` parameter. If the incoming request is not authorized or you're calling a method from outside of a listener, use the top-level `app.client`. diff --git a/docs/content/getting-started.md b/docs/content/getting-started.mdx similarity index 68% rename from docs/content/getting-started.md rename to docs/content/getting-started.mdx index be5d6f037..af9bfa0a7 100644 --- a/docs/content/getting-started.md +++ b/docs/content/getting-started.mdx @@ -1,6 +1,6 @@ --- title: Getting started with Bolt for JavaScript -sidebar_label: Getting started +sidebar_label: Getting Started --- This guide is meant to walk you through getting up and running with a Slack app using Bolt for JavaScript. Along the way, we’ll create a new Slack app, set up your local environment, and develop an app that listens and responds to messages from a Slack workspace. @@ -40,7 +40,7 @@ We're going to use bot and app tokens for this guide. 1. Navigate to the **OAuth & Permissions** on the left sidebar and scroll down to the **Bot Token Scopes** section. Click **Add an OAuth Scope**. -2. For now, we'll just add one scope: [`chat:write`](https://api.slack.com/scopes/chat:write). This grants your app the permission to post messages in channels it's a member of. +2. For now, we'll just add one scope: [`chat:write`](https://api.slack.com/scopes/chat:write). This scope grants your app the permission to post messages in channels it's a member of. 3. Scroll up to the top of the OAuth & Permissions page and click **Install App to Workspace**. You'll be led through Slack's OAuth UI, where you should allow your app to be installed to your development workspace. @@ -72,6 +72,7 @@ You’ll be prompted with a series of questions to describe your new project (yo Before we install the Bolt for JavaScript package to your new project, let's save the **bot token** and **Signing Secret** that were generated when you configured your app. 1. **Copy your Signing Secret from the Basic Information page** and then store it in a new environment variable. The following example works on Linux and macOS; but [similar commands are available on Windows](https://superuser.com/questions/212150/how-to-set-env-variable-in-windows-cmd-line/212153#212153). + ```shell export SLACK_SIGNING_SECRET= ``` @@ -126,15 +127,19 @@ Your app should let you know that it's up and running. 🎉 ## Setting up events {#setting-up-events} Your app behaves similarly to people on your team — it can post messages, add emoji reactions, and listen and respond to events. -To listen for events happening in a Slack workspace (like when a message is posted or when a reaction is posted to a message) you'll use the [Events API to subscribe to event types](https://api.slack.com/events-api). For this guide, we are going to be using [Socket Mode](https://api.slack.com/apis/connections/socket), our recommended option for those just getting started and building something for their team. +To listen for events happening in a Slack workspace (like when a message is posted or when a reaction is posted to a message) you'll use the [Events API to subscribe to event types](https://api.slack.com/events-api). -:::tip +For those just starting, we recommend using [Socket Mode](https://api.slack.com/apis/connections/socket). Socket Mode allows your app to use the Events API and interactive features without exposing a public HTTP Request URL. This can be helpful during development, or if you're receiving requests from behind a firewall. -Socket Mode lets apps use the Events API and interactive components without exposing a public HTTP endpoint. This can be helpful during development, or if you're receiving requests from behind a firewall. HTTP is more useful for apps being deployed to hosting environments (like [AWS](/deployments/aws-lambda) or [Heroku](/deployments/heroku)), or apps intended for distribution via the Slack App Directory. To continue this setting up guide with HTTP, head over [here](/tutorial/getting-started-http#setting-up-events-with-http). +That being said, you're welcome to set up an app with a public HTTP Request URL. HTTP is more useful for apps being deployed to hosting environments (like [AWS](/deployments/aws-lambda) or [Heroku](/deployments/heroku) to stably respond within a large corporate Slack workspaces/organization, or apps intended for distribution via the Slack Martketplace. -::: +We've provided instructions for both ways in this guide. -Okay, let's enable Socket Mode: +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + 1. Head to your app's configuration page (click on the app [from your app management page](https://api.slack.com/apps)). Navigate to **Socket Mode** on the left side menu and toggle to enable. @@ -144,6 +149,23 @@ Finally, it's time to tell Slack what events we'd like to listen for. Under **Ev When an event occurs, Slack will send your app information about the event, like the user that triggered it and the channel it occurred in. Your app will process the details and can respond accordingly. + + + +1. Go back to your app configuration page (click on the app from your [app management page](https://api.slack.com/apps)). Click **Event Subscriptions** on the left sidebar. Toggle the switch labeled **Enable Events**. + +2. Add your Request URL. Slack will send HTTP POST requests corresponding to events to this [Request URL](https://api.slack.com/apis/connections/events-api#the-events-api__subscribing-to-event-types__events-api-request-urls) endpoint. Bolt uses the `/slack/events` path to listen to all incoming requests (whether shortcuts, events, or interactivity payloads). When configuring your Request URL within your app configuration, you'll append `/slack/events`, e.g. `https:///slack/events`. 💡 + +:::info + +For local development, you can use a proxy service like [ngrok](https://ngrok.com/) to create a public URL and tunnel requests to your development environment. Refer to [ngrok's getting started guide](https://ngrok.com/docs#getting-started-expose) on how to create this tunnel. + +::: + + + + + Scroll down to **Subscribe to Bot Events**. There are four events related to messages: - [`message.channels`](https://api.slack.com/events/message.channels) listens for messages in public channels that your app is added to @@ -153,13 +175,17 @@ Scroll down to **Subscribe to Bot Events**. There are four events related to mes If you want your bot to listen to messages from everywhere it is added to, choose all four message events. After you’ve selected the events you want your bot to listen to, click the green **Save Changes** button. + + + + Back in your project, make sure to store the `xapp` token you saved earlier in your environment. ```shell export SLACK_APP_TOKEN=xapp- ``` -Make a simple change to your Bolt initialization code and restart the app. +Change your Bolt initialization code and restart the app. ```javascript // Initializes your app in socket mode with your app token and signing secret @@ -171,6 +197,14 @@ const app = new App({ }); ``` + + + +Carry on! + + + + --- ## Listening and responding to a message {#listening-and-responding-to-a-message} @@ -178,6 +212,10 @@ Your app is now ready for some logic. Let's start by using the `message()` metho The following example listens and responds to all messages in channels/DMs where your app has been added that contain the word "hello": + + + + ```javascript const { App } = require('@slack/bolt'); @@ -205,6 +243,34 @@ app.message('hello', async ({ message, say }) => { })(); ``` + + + +```javascript +const { App } = require('@slack/bolt'); + +const app = new App({ + token: process.env.SLACK_BOT_TOKEN, + signingSecret: process.env.SLACK_SIGNING_SECRET, +}); + +// Listens to incoming messages that contain "hello" +app.message('hello', async ({ message, say }) => { + // say() sends a message to the channel where the event was triggered + await say(`Hey there <@${message.user}>!`); +}); + +(async () => { + // Start your app + await app.start(process.env.PORT || 3000); + + console.log('⚡️ Bolt app is running!'); +})(); +``` + + + + If you restart your app, so long as your bot user has been added to the channel/DM, when you send any message that contains "hello", it will respond. This is a basic example, but it gives you a place to start customizing your app based on your own goals. Let's try something a little more interactive by sending a button rather than plain text. @@ -215,11 +281,22 @@ This is a basic example, but it gives you a place to start customizing your app To use features like buttons, select menus, datepickers, modals, and shortcuts, you’ll need to enable interactivity. Head over to **Interactivity & Shortcuts** in your app configuration. -:::tip -You'll notice that with Socket Mode on, basic interactivity is enabled for us by default, so no further action here is needed. If you're using HTTP, you'll need to supply a [Request URL](https://api.slack.com/apis/connections/events-api#the-events-api__subscribing-to-event-types__events-api-request-urls) for Slack to send events to. + + + +With Socket Mode on, basic interactivity is enabled for us by default, so no further action here is needed + + + + +Similar to events, you'll need to specify a Request URL for Slack to send the action (such as *user clicked a button*). -::: + +By default, Bolt uses the same endpoint for interactive components that it uses for events, so use the same request URL as above (in the example, it was `https://8e8ec2d7.ngrok.io/slack/events`). Press the **Save Changes** button in the lower right hand corner, and that's it. Your app is set up to handle interactivity! + + + When interactivity is enabled, interactions with shortcuts, modals, or interactive components (such as buttons, select menus, and datepickers) will be sent to your app as events. @@ -229,6 +306,9 @@ Now, let’s go back to your app’s code and add logic to handle those events: Below, the code from the last section is modified to send a message containing a button rather than just a string: + + + ```javascript const { App } = require('@slack/bolt'); @@ -275,6 +355,53 @@ app.message('hello', async ({ message, say }) => { })(); ``` + + + +```javascript +const { App } = require('@slack/bolt'); + +const app = new App({ + token: process.env.SLACK_BOT_TOKEN, + signingSecret: process.env.SLACK_SIGNING_SECRET +}); + +// Listens to incoming messages that contain "hello" +app.message('hello', async ({ message, say }) => { + // 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}>!` + }); +}); + +(async () => { + // Start your app + await app.start(process.env.PORT || 3000); + + console.log('⚡️ Bolt app is running!'); +})(); +``` + + + + The value inside of `say()` is now an object that contains an array of `blocks`. Blocks are the building components of a Slack message and can range from text to images to datepickers. In this case, your app will respond with a section block that includes a button as an accessory. Since we're using `blocks`, the `text` is a fallback for notifications and accessibility. You'll notice in the button `accessory` object, there is an `action_id`. This will act as a unique identifier for the button so your app can specify what action it wants to respond to. @@ -289,23 +416,79 @@ Now, if you restart your app and say "hello" in a channel your app is in, you'll Let's add a handler to send a followup message when someone clicks the button: + + + ```js reference https://github.com/slackapi/bolt-js-getting-started-app/blob/main/app.js ``` + + + + ```javascript +const { App } = require('@slack/bolt'); + +const app = new App({ + token: process.env.SLACK_BOT_TOKEN, + signingSecret: process.env.SLACK_SIGNING_SECRET +}); + +// Listens to incoming messages that contain "hello" +app.message('hello', async ({ message, say }) => { + // 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(process.env.PORT || 3000); + + console.log('⚡️ Bolt app is running!'); +})(); +``` + + + + You can see that we used `app.action()` to listen for the `action_id` that we named `sample_button`. If you restart your app and click the button, you'll see a new message from your app that says you clicked the button. --- ## Next steps {#next-steps} -You just built your first [Bolt for JavaScript app](https://github.com/slackapi/bolt-js-getting-started-app) with Socket Mode! 🎉 +You just built your first [Bolt for JavaScript app](https://github.com/slackapi/bolt-js-getting-started-app)! 🎉 Now that you have a basic app up and running, you can start exploring how to make your Bolt app stand out. Here are some ideas about what to explore next: -* Read through the basic concepts pages to learn about the different methods and features your Bolt app has access to. +* Read through the concepts pages to learn about the different methods and features your Bolt app has access to. * Explore the different events your bot can listen to with the [`events()`](/concepts/event-listening) method. All of the events are listed [on the API site](https://api.slack.com/events). * Bolt allows you to [call Web API methods](/concepts/web-api) with the client attached to your app. There are [over 200 methods](https://api.slack.com/methods) on our API site. -* Learn more about the different token types [on our API site](https://api.slack.com/docs/token-types). Your app may need different tokens depending on the actions you want it to perform. For apps that do not use Socket Mode, typically only a bot (`xoxb`) token is required. For example of this, see [Getting Started with HTTP](/tutorial/getting-started-http). \ No newline at end of file +* Learn more about the different token types [on our API site](https://api.slack.com/docs/token-types). Your app may need different tokens depending on the actions you want it to perform. \ No newline at end of file diff --git a/docs/content/advanced/conversation-store.md b/docs/content/legacy/conversation-store.md similarity index 100% rename from docs/content/advanced/conversation-store.md rename to docs/content/legacy/conversation-store.md diff --git a/docs/content/tutorial/hubot-migration.md b/docs/content/legacy/hubot-migration.md similarity index 99% rename from docs/content/tutorial/hubot-migration.md rename to docs/content/legacy/hubot-migration.md index 3f2ef5b2e..2aa2a1c33 100644 --- a/docs/content/tutorial/hubot-migration.md +++ b/docs/content/legacy/hubot-migration.md @@ -1,15 +1,13 @@ --- title: Migrating apps from Hubot to Bolt for JavaScript -slug: hubot-migration +slug: /tutorial/hubot-migration lang: en -layout: tutorial --- Bolt was created to reduce the time and complexity it takes to build Slack apps. It provides Slack developers a single interface to build using modern features and best practices. This guide is meant to step you through the process of migrating your app from using [Hubot](https://hubot.github.com/docs/) to Bolt for JavaScript. If you already have an [app with a bot user](https://api.slack.com/bot-users#getting-started) or if you’re looking for code samples that translate Hubot code to Bolt for JavaScript code, you may find it valuable to start by reading through the [example script in the Bolt for JavaScript repository](https://github.com/slackapi/bolt-js/blob/master/examples/hubot-example/script.js). - --- ### Setting the stage {#setting-the-stage} diff --git a/docs/content/legacy/steps-from-apps.md b/docs/content/legacy/steps-from-apps.md new file mode 100644 index 000000000..659786c2d --- /dev/null +++ b/docs/content/legacy/steps-from-apps.md @@ -0,0 +1,198 @@ +--- +title: Steps from Apps +lang: en +slug: /concepts/steps-from-apps +--- + +:::danger + +Steps from Apps is a deprecated feature. + +Steps from Apps are different than, and not interchangeable with, Slack automation workflows. We encourage those who are currently publishing steps from apps to consider the new [Slack automation features](https://api.slack.com/automation), such as [custom steps for Bolt](https://api.slack.com/automation/functions/custom-bolt). + +Please [read the Slack API changelog entry](https://api.slack.com/changelog/2023-08-workflow-steps-from-apps-step-back) for more information. + +::: + +Steps from apps allow your app to create and process steps that users can add using [Workflow Builder](https://api.slack.com/workflows). + +A step from app is made up of three distinct user events: + +- Adding or editing the step in a Workflow +- Saving or updating the step's configuration +- The end user's execution of the step + +All three events must be handled for a step from app to function. + +Read more about steps from apps in the [API documentation](https://api.slack.com/legacy/workflows/steps). + +--- + +## Creating steps from apps + +To create a step from app, Bolt provides the `WorkflowStep` class. + +When instantiating a new `WorkflowStep`, pass in the step's `callback_id` and a configuration object. + +The configuration object contains three properties: `edit`, `save`, and `execute`. Each of these properties must be a single callback or an array of callbacks. All callbacks have access to a `step` object that contains information about the step from app event. + +After instantiating a `WorkflowStep`, you can pass it into `app.step()`. Behind the scenes, your app will listen and respond to the step’s events using the callbacks provided in the configuration object. + +```javascript +const { App, WorkflowStep } = require('@slack/bolt'); + +// Initiate the Bolt app as you normally would +const app = new App({ + signingSecret: process.env.SLACK_SIGNING_SECRET, + token: process.env.SLACK_BOT_TOKEN, +}); + +// Create a new WorkflowStep instance +const ws = new WorkflowStep('add_task', { + edit: async ({ ack, step, configure }) => {}, + save: async ({ ack, step, update }) => {}, + execute: async ({ step, complete, fail }) => {}, +}); + +app.step(ws); +``` + +## Adding or editing steps from apps + +When a builder adds (or later edits) your step in their workflow, your app will receive a [`workflow_step_edit` event](https://api.slack.com/reference/workflows/workflow_step_edit). The `edit` callback in your `WorkflowStep` configuration will be run when this event is received. + +Whether a builder is adding or editing a step, you need to send them a [step from app configuration modal](https://api.slack.com/reference/workflows/configuration-view). This modal is where step-specific settings are chosen, and it has more restrictions than typical modals—most notably, it cannot include `title​`, `submit​`, or `close`​ properties. By default, the configuration modal's `callback_id` will be the same as the step from app. + +Within the `edit` callback, the `configure()` utility can be used to easily open your step's configuration modal by passing in an object with your view's `blocks`. To disable saving the configuration before certain conditions are met, pass in `submit_disabled` with a value of `true`. + +To learn more about opening configuration modals, [read the documentation](https://api.slack.com/workflows/steps#handle_config_view). + +```javascript +const ws = new WorkflowStep('add_task', { + edit: async ({ ack, step, configure }) => { + await ack(); + + const blocks = [ + { + type: 'input', + block_id: 'task_name_input', + element: { + type: 'plain_text_input', + action_id: 'name', + placeholder: { + type: 'plain_text', + text: 'Add a task name', + }, + }, + label: { + type: 'plain_text', + text: 'Task name', + }, + }, + { + type: 'input', + block_id: 'task_description_input', + element: { + type: 'plain_text_input', + action_id: 'description', + placeholder: { + type: 'plain_text', + text: 'Add a task description', + }, + }, + label: { + type: 'plain_text', + text: 'Task description', + }, + }, + ]; + + await configure({ blocks }); + }, + save: async ({ ack, step, update }) => {}, + execute: async ({ step, complete, fail }) => {}, +}); +``` + +## Saving step configurations + +After the configuration modal is opened, your app will listen for the `view_submission` event. The `save` callback in your `WorkflowStep` configuration will be run when this event is received. + +Within the `save` callback, the `update()` method can be used to save the builder's step configuration by passing in the following arguments: + +- `inputs` is an object representing the data your app expects to receive from the user upon step from app execution. +- `outputs` is an array of objects containing data that your app will provide upon the step's completion. Outputs can then be used in subsequent steps of the workflow. +- `step_name` overrides the default Step name +- `step_image_url` overrides the default Step image + +To learn more about how to structure these parameters, [read the documentation](https://api.slack.com/reference/workflows/workflow_step). + +```javascript +const ws = new WorkflowStep('add_task', { + edit: async ({ ack, step, configure }) => {}, + save: async ({ ack, step, view, update }) => { + await ack(); + + const { values } = view.state; + const taskName = values.task_name_input.name; + const taskDescription = values.task_description_input.description; + + const inputs = { + taskName: { value: taskName.value }, + taskDescription: { value: taskDescription.value } + }; + + const outputs = [ + { + type: 'text', + name: 'taskName', + label: 'Task name', + }, + { + type: 'text', + name: 'taskDescription', + label: 'Task description', + } + ]; + + await update({ inputs, outputs }); + }, + execute: async ({ step, complete, fail }) => {}, +}); +``` + +## Executing steps from apps + +When your step from app is executed by an end user, your app will receive a [`workflow_step_execute` event](https://api.slack.com/events/workflow_step_execute). The `execute` callback in your `WorkflowStep` configuration will be run when this event is received. + +Using the `inputs` from the `save` callback, this is where you can make third-party API calls, save information to a database, update the user's Home tab, or decide the outputs that will be available to subsequent steps by mapping values to the `outputs` object. + +Within the `execute` callback, your app must either call `complete()` to indicate that the step's execution was successful, or `fail()` to indicate that the step's execution failed. + +```javascript +const ws = new WorkflowStep('add_task', { + edit: async ({ ack, step, configure }) => {}, + save: async ({ ack, step, update }) => {}, + execute: async ({ step, complete, fail }) => { + const { inputs } = step; + + const outputs = { + taskName: inputs.taskName.value, + taskDescription: inputs.taskDescription.value, + }; + + // signal back to Slack that everything was successful + await complete({ outputs }); + // NOTE: If you run your app with processBeforeResponse: true option, + // `await complete()` is not recommended because of the slow response of the API endpoint + // which could result in not responding to the Slack Events API within the required 3 seconds + // instead, use: + // complete({ outputs }).then(() => { console.log('step from app execution complete registered'); }); + + // let Slack know if something went wrong + // await fail({ error: { message: "Just testing step failure!" } }); + // NOTE: If you run your app with processBeforeResponse: true, use this instead: + // fail({ error: { message: "Just testing step failure!" } }).then(() => { console.log('step from app execution failure registered'); }); + }, +}); +``` diff --git a/docs/content/tutorial/migration-v2.md b/docs/content/migration/migration-v2.md similarity index 99% rename from docs/content/tutorial/migration-v2.md rename to docs/content/migration/migration-v2.md index 32b851037..f7b5b2dff 100644 --- a/docs/content/tutorial/migration-v2.md +++ b/docs/content/migration/migration-v2.md @@ -1,7 +1,7 @@ --- title: Migrating to V2 -slug: migration-v2 -lang: en--- +slug: /tutorial/migration-v2 +lang: en --- This guide will walk you through the process of updating your app from using `@slack/bolt@1.x` to `@slack/bolt@2.x`. There are a few changes you'll need to make but for most apps, these changes can be applied in 5 - 15 minutes. diff --git a/docs/content/tutorial/migration-v3.md b/docs/content/migration/migration-v3.md similarity index 99% rename from docs/content/tutorial/migration-v3.md rename to docs/content/migration/migration-v3.md index 73aa4c6b6..b453984a2 100644 --- a/docs/content/tutorial/migration-v3.md +++ b/docs/content/migration/migration-v3.md @@ -1,6 +1,6 @@ --- title: Migrating to V3 -slug: migration-v3 +slug: /tutorial/migration-v3 lang: en --- diff --git a/docs/content/tutorial/migration-v4.md b/docs/content/migration/migration-v4.md similarity index 96% rename from docs/content/tutorial/migration-v4.md rename to docs/content/migration/migration-v4.md index 75097bf84..cadc5233d 100644 --- a/docs/content/tutorial/migration-v4.md +++ b/docs/content/migration/migration-v4.md @@ -1,6 +1,6 @@ --- title: Migrating to V4 -slug: migration-v4 +slug: /tutorial/migration-v4 lang: en --- @@ -94,7 +94,7 @@ import { defaultProcessEventHandler } from '@slack/bolt'; ### 🏭 Built-in middleware changes {#built-in-middleware-changes} -Two [built-in middlewares](../reference#built-in-listener-middleware-functions), `ignoreSelf` and `directMention`, previously needed to be invoked as a function in order to _return_ a middleware. These two built-in middlewares were not parameterized in the sense that they should just be used directly; as a result, you no longer should invoke them and instead pass them directly. +Two [built-in middlewares](../reference#built-in-middleware-functions), `ignoreSelf` and `directMention`, previously needed to be invoked as a function in order to _return_ a middleware. These two built-in middlewares were not parameterized in the sense that they should just be used directly; as a result, you no longer should invoke them and instead pass them directly. As an example, previously you may have leveraged `directMention` like this: diff --git a/docs/content/reference.md b/docs/content/reference.md index 44e9f1fec..a71dab74b 100644 --- a/docs/content/reference.md +++ b/docs/content/reference.md @@ -22,7 +22,7 @@ Below is the current list of methods that accept listener functions. These metho | `app.action(actionId, fn);` | Listens for an action event from a Block Kit element, such as a user interaction with a button, select menu, or datepicker. The `actionId` identifier is a `string` that should match the unique `action_id` included when your app sends the element to a view. Note that a view can be a message, modal, or app home. Note that action elements included in an `input` block do not trigger any events. | `app.shortcut(callbackId, fn);` | Listens for global or message shortcut invocation. The `callbackId` is a `string` or `RegExp` that must match a shortcut `callback_id` specified within your app's configuration. | `app.view(callbackId, fn);` | Listens for `view_submission` and `view_closed` events. `view_submission` events are sent when a user submits a modal that your app opened. `view_closed` events are sent when a user closes the modal rather than submits it. -| `app.step(workflowStep)` | Listen and responds to steps from apps events using the callbacks passed in an instance of `WorkflowStep`. Callbacks include three callbacks: `edit`, `save`, and `execute`. More information on steps from apps can be found [in the documentation](/concepts/adding-editing-steps). +| `app.step(workflowStep)` | Listen and responds to steps from apps events using the callbacks passed in an instance of `WorkflowStep`. Callbacks include three callbacks: `edit`, `save`, and `execute`. More information on steps from apps can be found [in the documentation](/concepts/steps-from-apps). | `app.command(commandName, fn);` | Listens for slash command invocations. The `commandName` is a `string` that must match a slash command specified in your app's configuration. Slash command names should be prefaced with a `/` (ex: `/helpdesk`). | `app.options(actionId, fn);` | Listens for options requests (from select menus with an external data source). This isn't often used, and shouldn't be mistaken with `app.action`. The `actionId` identifier is a `string` that matches the unique `action_id` included when you app sends a [select with an external data source](https://api.slack.com/reference/block-kit/block-elements#external_select). @@ -162,7 +162,7 @@ Bolt includes a set of error types to make errors easier to handle, with more sp | `ReceiverMultipleAckError` | Error thrown within Receiver when your app calls `ack()` when that request has previously been acknowledged. Currently only used in the default `HTTPReceiver`. | | `ReceiverAuthenticityError` | Error thrown when your app's request signature could not be verified. The error includes information on why it failed, such as an invalid timestamp, missing headers, or invalid signing secret. | `MultipleListenerError` | Thrown when multiple errors occur when processing multiple listeners for a single event. Includes an `originals` property with an array of the individual errors. | -| `WorkflowStepInitializationError` | Error thrown when configuration options are invalid or missing when instantiating a new `WorkflowStep` instance. This could be scenarios like not including a `callback_id`, or not including a configuration object. More information on steps from apps [can be found in the documentation](/concepts/steps). | +| `WorkflowStepInitializationError` | Error thrown when configuration options are invalid or missing when instantiating a new `WorkflowStep` instance. This could be scenarios like not including a `callback_id`, or not including a configuration object. More information on steps from apps [can be found in the documentation](/concepts/steps-from-apps). | | `UnknownError` | An error that was thrown inside the framework but does not have a specified error code. Contains an `original` property with more details. | :::info diff --git a/docs/content/steps/adding-editing-steps.md b/docs/content/steps/adding-editing-steps.md deleted file mode 100644 index 0622d17a4..000000000 --- a/docs/content/steps/adding-editing-steps.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: Adding or editing steps from apps -lang: en -slug: /concepts/adding-editing-steps ---- - -:::danger - -Steps from Apps are a deprecated feature. - -Steps from Apps are different than, and not interchangeable with, Slack automation workflows. We encourage those who are currently publishing steps from apps to consider the new [Slack automation features](https://api.slack.com/automation), such as [custom steps for Bolt](https://api.slack.com/automation/functions/custom-bolt). - -Please [read the Slack API changelog entry](https://api.slack.com/changelog/2023-08-workflow-steps-from-apps-step-back) for more information. - -::: - -When a builder adds (or later edits) your step in their workflow, your app will receive a [`workflow_step_edit` event](https://api.slack.com/reference/workflows/workflow_step_edit). The `edit` callback in your `WorkflowStep` configuration will be run when this event is received. - -Whether a builder is adding or editing a step, you need to send them a [step from app configuration modal](https://api.slack.com/reference/workflows/configuration-view). This modal is where step-specific settings are chosen, and it has more restrictions than typical modals—most notably, it cannot include `title​`, `submit​`, or `close`​ properties. By default, the configuration modal's `callback_id` will be the same as the step from app. - -Within the `edit` callback, the `configure()` utility can be used to easily open your step's configuration modal by passing in an object with your view's `blocks`. To disable saving the configuration before certain conditions are met, pass in `submit_disabled` with a value of `true`. - -To learn more about opening configuration modals, [read the documentation](https://api.slack.com/workflows/steps#handle_config_view). - -```javascript -const ws = new WorkflowStep('add_task', { - edit: async ({ ack, step, configure }) => { - await ack(); - - const blocks = [ - { - type: 'input', - block_id: 'task_name_input', - element: { - type: 'plain_text_input', - action_id: 'name', - placeholder: { - type: 'plain_text', - text: 'Add a task name', - }, - }, - label: { - type: 'plain_text', - text: 'Task name', - }, - }, - { - type: 'input', - block_id: 'task_description_input', - element: { - type: 'plain_text_input', - action_id: 'description', - placeholder: { - type: 'plain_text', - text: 'Add a task description', - }, - }, - label: { - type: 'plain_text', - text: 'Task description', - }, - }, - ]; - - await configure({ blocks }); - }, - save: async ({ ack, step, update }) => {}, - execute: async ({ step, complete, fail }) => {}, -}); -``` diff --git a/docs/content/steps/creating-steps.md b/docs/content/steps/creating-steps.md deleted file mode 100644 index f39714ede..000000000 --- a/docs/content/steps/creating-steps.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Creating steps from apps -lang: en -slug: /concepts/creating-steps ---- - -:::danger - -Steps from Apps are a deprecated feature. - -Steps from Apps are different than, and not interchangeable with, Slack automation workflows. We encourage those who are currently publishing steps from apps to consider the new [Slack automation features](https://api.slack.com/automation), such as [custom steps for Bolt](https://api.slack.com/automation/functions/custom-bolt). - -Please [read the Slack API changelog entry](https://api.slack.com/changelog/2023-08-workflow-steps-from-apps-step-back) for more information. - -::: - -To create a step from app, Bolt provides the `WorkflowStep` class. - -When instantiating a new `WorkflowStep`, pass in the step's `callback_id` and a configuration object. - -The configuration object contains three properties: `edit`, `save`, and `execute`. Each of these properties must be a single callback or an array of callbacks. All callbacks have access to a `step` object that contains information about the step from app event. - -After instantiating a `WorkflowStep`, you can pass it into `app.step()`. Behind the scenes, your app will listen and respond to the step’s events using the callbacks provided in the configuration object. - -```javascript -const { App, WorkflowStep } = require('@slack/bolt'); - -// Initiate the Bolt app as you normally would -const app = new App({ - signingSecret: process.env.SLACK_SIGNING_SECRET, - token: process.env.SLACK_BOT_TOKEN, -}); - -// Create a new WorkflowStep instance -const ws = new WorkflowStep('add_task', { - edit: async ({ ack, step, configure }) => {}, - save: async ({ ack, step, update }) => {}, - execute: async ({ step, complete, fail }) => {}, -}); - -app.step(ws); -``` diff --git a/docs/content/steps/executing-steps.md b/docs/content/steps/executing-steps.md deleted file mode 100644 index 55194cecb..000000000 --- a/docs/content/steps/executing-steps.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: Executing steps from apps -lang: en -slug: /concepts/executing-steps ---- - -:::danger - -Steps from Apps are a deprecated feature. - -Steps from Apps are different than, and not interchangeable with, Slack automation workflows. We encourage those who are currently publishing steps from apps to consider the new [Slack automation features](https://api.slack.com/automation), such as [custom steps for Bolt](https://api.slack.com/automation/functions/custom-bolt). - -Please [read the Slack API changelog entry](https://api.slack.com/changelog/2023-08-workflow-steps-from-apps-step-back) for more information. - -::: - -When your step from app is executed by an end user, your app will receive a [`workflow_step_execute` event](https://api.slack.com/events/workflow_step_execute). The `execute` callback in your `WorkflowStep` configuration will be run when this event is received. - -Using the `inputs` from the `save` callback, this is where you can make third-party API calls, save information to a database, update the user's Home tab, or decide the outputs that will be available to subsequent steps by mapping values to the `outputs` object. - -Within the `execute` callback, your app must either call `complete()` to indicate that the step's execution was successful, or `fail()` to indicate that the step's execution failed. - -```javascript -const ws = new WorkflowStep('add_task', { - edit: async ({ ack, step, configure }) => {}, - save: async ({ ack, step, update }) => {}, - execute: async ({ step, complete, fail }) => { - const { inputs } = step; - - const outputs = { - taskName: inputs.taskName.value, - taskDescription: inputs.taskDescription.value, - }; - - // signal back to Slack that everything was successful - await complete({ outputs }); - // NOTE: If you run your app with processBeforeResponse: true option, - // `await complete()` is not recommended because of the slow response of the API endpoint - // which could result in not responding to the Slack Events API within the required 3 seconds - // instead, use: - // complete({ outputs }).then(() => { console.log('step from app execution complete registered'); }); - - // let Slack know if something went wrong - // await fail({ error: { message: "Just testing step failure!" } }); - // NOTE: If you run your app with processBeforeResponse: true, use this instead: - // fail({ error: { message: "Just testing step failure!" } }).then(() => { console.log('step from app execution failure registered'); }); - }, -}); -``` diff --git a/docs/content/steps/saving-steps.md b/docs/content/steps/saving-steps.md deleted file mode 100644 index 5f3e4a4ba..000000000 --- a/docs/content/steps/saving-steps.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Saving step configurations -lang: en -slug: /concepts/saving-steps ---- - -:::danger - -Steps from Apps are a deprecated feature. - -Steps from Apps are different than, and not interchangeable with, Slack automation workflows. We encourage those who are currently publishing steps from apps to consider the new [Slack automation features](https://api.slack.com/automation), such as [custom steps for Bolt](https://api.slack.com/automation/functions/custom-bolt). - -Please [read the Slack API changelog entry](https://api.slack.com/changelog/2023-08-workflow-steps-from-apps-step-back) for more information. - -::: - -After the configuration modal is opened, your app will listen for the `view_submission` event. The `save` callback in your `WorkflowStep` configuration will be run when this event is received. - -Within the `save` callback, the `update()` method can be used to save the builder's step configuration by passing in the following arguments: - -- `inputs` is an object representing the data your app expects to receive from the user upon step from app execution. -- `outputs` is an array of objects containing data that your app will provide upon the step's completion. Outputs can then be used in subsequent steps of the workflow. -- `step_name` overrides the default Step name -- `step_image_url` overrides the default Step image - -To learn more about how to structure these parameters, [read the documentation](https://api.slack.com/reference/workflows/workflow_step). - -```javascript -const ws = new WorkflowStep('add_task', { - edit: async ({ ack, step, configure }) => {}, - save: async ({ ack, step, view, update }) => { - await ack(); - - const { values } = view.state; - const taskName = values.task_name_input.name; - const taskDescription = values.task_description_input.description; - - const inputs = { - taskName: { value: taskName.value }, - taskDescription: { value: taskDescription.value } - }; - - const outputs = [ - { - type: 'text', - name: 'taskName', - label: 'Task name', - }, - { - type: 'text', - name: 'taskDescription', - label: 'Task description', - } - ]; - - await update({ inputs, outputs }); - }, - execute: async ({ step, complete, fail }) => {}, -}); -``` diff --git a/docs/content/steps/steps.md b/docs/content/steps/steps.md deleted file mode 100644 index f344894f3..000000000 --- a/docs/content/steps/steps.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Overview of steps from apps -lang: en -slug: /concepts/steps ---- - -:::danger - -Steps from Apps are a deprecated feature. - -Steps from Apps are different than, and not interchangeable with, Slack automation workflows. We encourage those who are currently publishing steps from apps to consider the new [Slack automation features](https://api.slack.com/automation), such as [custom steps for Bolt](https://api.slack.com/automation/functions/custom-bolt). - -Please [read the Slack API changelog entry](https://api.slack.com/changelog/2023-08-workflow-steps-from-apps-step-back) for more information. - -::: - ---- - -Steps from apps allow your app to create and process steps that users can add using [Workflow Builder](https://api.slack.com/workflows). - -A step from app is made up of three distinct user events: - -- Adding or editing the step in a Workflow -- Saving or updating the step's configuration -- The end user's execution of the step - -All three events must be handled for a step from app to function. - -Read more about steps from apps in the [API documentation](https://api.slack.com/legacy/workflows/steps). diff --git a/docs/content/tutorial/getting-started-http.md b/docs/content/tutorial/getting-started-http.md deleted file mode 100644 index 8be737eb3..000000000 --- a/docs/content/tutorial/getting-started-http.md +++ /dev/null @@ -1,326 +0,0 @@ ---- -title: Getting started with Bolt for JavaScript and HTTP -slug: getting-started-http -lang: en ---- - -This guide is meant to walk you through getting up and running with a Slack app using Bolt for JavaScript. Along the way, we’ll create a new Slack app, set up your local environment, and develop an app that listens and responds to messages from a Slack workspace. - -When you’re finished, you’ll have this ⚡️[Getting Started app](https://github.com/slackapi/bolt-js-getting-started-app) to run, modify, and make your own. - ---- - -### Create an app {#create-an-app} -First thing's first: before you start developing with Bolt, you'll want to [create a Slack app](https://api.slack.com/apps/new). - -:::tip - -We recommend using a workspace where you won't disrupt real work getting done — [you can create a new one for free](https://slack.com/get-started#create). - -::: - -After you fill out an app name (_you can change it later_) and pick a workspace to install it to, hit the `Create App` button and you'll land on your app's **Basic Information** page. - -This page contains an overview of your app in addition to important credentials you'll need later, like the `Signing Secret` under the **App Credentials** header. - -![Basic Information page](/img/basic-information-page.png "Basic Information page") - -Look around, add an app icon and description, and then let's start configuring your app. 🔩 - ---- - -### Tokens and installing apps {#tokens-and-installing-apps} -Slack apps use [OAuth to manage access to Slack's APIs](https://api.slack.com/docs/oauth). When an app is installed, you'll receive a token that the app can use to call API methods. - -There are three main token types available to a Slack app: user (`xoxp`), bot (`xoxb`), and app (`xapp`) tokens. -- [User tokens](https://api.slack.com/authentication/token-types#user) allow you to call API methods on behalf of users after they install or authenticate the app. There may be several user tokens for a single workspace. -- [Bot tokens](https://api.slack.com/authentication/token-types#bot) are associated with bot users, and are only granted once in a workspace where someone installs the app. The bot token your app uses will be the same no matter which user performed the installation. Bot tokens are the token type that _most_ apps use. -- [App-level tokens](https://api.slack.com/authentication/token-types#app) represent your app across organizations, including installations by all individual users on all workspaces in a given organization and are commonly used for creating websocket connections to your app. - -For brevity, we're going to use bot tokens for this guide. - -1. Navigate to the **OAuth & Permissions** on the left sidebar and scroll down to the **Bot Token Scopes** section. Click **Add an OAuth Scope**. - -2. For now, we'll just add one scope: [`chat:write`](https://api.slack.com/scopes/chat:write). This grants your app the permission to post messages in channels it's a member of. - -3. Scroll up to the top of the OAuth & Permissions page and click **Install App to Workspace**. You'll be led through Slack's OAuth UI, where you should allow your app to be installed to your development workspace. - -4. Once you authorize the installation, you'll land on the **OAuth & Permissions** page and see a **Bot User OAuth Access Token**. - -![OAuth Tokens](/img/bot-token.png "Bot OAuth Token") - -:::tip - -Treat your token like a password and [keep it safe](https://api.slack.com/docs/oauth-safety). Your app uses it to post and retrieve information from Slack workspaces. - -::: - ---- - -### Setting up your project {#setting-up-your-project} -With the initial configuration handled, it's time to set up a new Bolt project. This is where you'll write the code that handles the logic for your app. - -If you don’t already have a project, let’s create a new one. Create an empty directory and initialize a new project: - -```shell -mkdir first-bolt-app -cd first-bolt-app -npm init -``` - -You’ll be prompted with a series of questions to describe your new project (you can accept the defaults by hitting Enter on each prompt if you aren’t picky). After you’re done, you’ll have a new `package.json` file in your directory. - -Before we install the Bolt for JavaScript package to your new project, let's save the **bot token** and **Signing Secret** that were generated when you configured your app. - -1. **Copy your Signing Secret from the Basic Information page** and then store it in a new environment variable. The following example works on Linux and macOS; but [similar commands are available on Windows](https://superuser.com/questions/212150/how-to-set-env-variable-in-windows-cmd-line/212153#212153). - -```shell -export SLACK_SIGNING_SECRET= -``` - -2. **Copy your bot (xoxb) token from the OAuth & Permissions page** and store it in another environment variable. -```shell -export SLACK_BOT_TOKEN=xoxb- -``` - -:::warning - -Remember to keep your token and signing secret secure. At a minimum, you should avoid checking them into public version control, and access them via environment variables as we've done above. Checkout the API documentation for more on [best practices for app security](https://api.slack.com/authentication/best-practices). - -::: - -Now, let's create your app. Install the `@slack/bolt` package and save it to your `package.json` dependencies using the following command: - -```shell -npm install @slack/bolt -``` - -Create a new entrypoint file called `app.js` in this directory and add the following code: - -```javascript -const { App } = require('@slack/bolt'); - -// Initializes your app with your bot token and signing secret -const app = new App({ - token: process.env.SLACK_BOT_TOKEN, - signingSecret: process.env.SLACK_SIGNING_SECRET -}); - -(async () => { - // Start your app - await app.start(process.env.PORT || 3000); - - console.log('⚡️ Bolt app is running!'); -})(); -``` - -Save your `app.js` file, then on the command line run the following: - -```script -node app.js -``` - -Your app should let you know that it's up and running. 🎉 - ---- - -### Setting up events with HTTP {#setting-up-events-with-http} -Your app behaves similarly to people on your team — it can post messages, add emoji reactions, and listen and respond to events. - -To listen for events happening in a Slack workspace (like when a message is posted or when a reaction is posted to a message) you'll use the [Events API to subscribe to event types](https://api.slack.com/events-api). - -Let's enable events for your app: - -1. Go back to your app configuration page (click on the app from your [app management page](https://api.slack.com/apps)). Click **Event Subscriptions** on the left sidebar. Toggle the switch labeled **Enable Events**. - -2. Add your Request URL. Slack will send HTTP POST requests corresponding to events to this [Request URL](https://api.slack.com/apis/connections/events-api#the-events-api__subscribing-to-event-types__events-api-request-urls) endpoint. Bolt uses the `/slack/events` path to listen to all incoming requests (whether shortcuts, events, or interactivity payloads). When configuring your Request URL within your app configuration, you'll append `/slack/events`, e.g. `https:///slack/events`. 💡 - -:::info - -For local development, you can use a proxy service like [ngrok](https://ngrok.com/) to create a public URL and tunnel requests to your development environment. Refer to [ngrok's getting started guide](https://ngrok.com/docs#getting-started-expose) on how to create this tunnel. - -::: - - -Finally, it's time to tell Slack what events we'd like to listen for. Under **Event Subscriptions**, toggle the switch labeled **Enable Events**. - -When an event occurs, Slack will send your app information about the event, like the user that triggered it and the channel it occurred in. Your app will process the details and can respond accordingly. - -Scroll down to **Subscribe to Bot Events**. There are four events related to messages: -- [`message.channels`](https://api.slack.com/events/message.channels) listens for messages in public channels that your app is added to -- [`message.groups`](https://api.slack.com/events/message.groups) listens for messages in 🔒 private channels that your app is added to -- [`message.im`](https://api.slack.com/events/message.im) listens for messages in your app's DMs with users -- [`message.mpim`](https://api.slack.com/events/message.mpim) listens for messages in multi-person DMs that your app is added to - -If you want your bot to listen to messages from everywhere it is added to, choose all four message events. After you’ve selected the events you want your bot to listen to, click the green **Save Changes** button. - ---- -### Listening and responding to a message {#listening-and-responding-to-a-message} -Your app is now ready for some logic. Let's start by using the `message()` method to attach a listener for messages. - -The following example listens and responds to all messages in channels/DMs where your app has been added that contain the word "hello": - -```javascript -const { App } = require('@slack/bolt'); - -const app = new App({ - token: process.env.SLACK_BOT_TOKEN, - signingSecret: process.env.SLACK_SIGNING_SECRET, -}); - -// Listens to incoming messages that contain "hello" -app.message('hello', async ({ message, say }) => { - // say() sends a message to the channel where the event was triggered - await say(`Hey there <@${message.user}>!`); -}); - -(async () => { - // Start your app - await app.start(process.env.PORT || 3000); - - console.log('⚡️ Bolt app is running!'); -})(); -``` - -If you restart your app, so long as your bot user has been added to the channel/DM, when you send any message that contains "hello", it will respond. - -This is a basic example, but it gives you a place to start customizing your app based on your own goals. Let's try something a little more interactive by sending a button rather than plain text. - ---- - -### Sending and responding to actions {#sending-and-responding-to-actions} - -To use features like buttons, select menus, datepickers, modals, and shortcuts, you’ll need to enable interactivity. Similar to events, you'll need to specify a Request URL for Slack to send the action (such as *user clicked a button*). Head over to **Interactivity & Shortcuts** in your app configuration. - -:::info - -By default, Bolt uses the same endpoint for interactive components that it uses for events, so use the same request URL as above (in the example, it was `https://8e8ec2d7.ngrok.io/slack/events`). Press the **Save Changes** button in the lower right hand corner, and that's it. Your app is set up to handle interactivity! - -::: - -When interactivity is enabled, interactions with shortcuts, modals, or interactive components (such as buttons, select menus, and datepickers) will be sent to your app as events. - -Now, let’s go back to your app’s code and add logic to handle those events: -- First, we'll send a message that contains an interactive component (in this case a button). -- Next, we'll listen for the action of a user clicking the button before responding - -Below, the code from the last section is modified to send a message containing a button rather than just a string: - -```javascript -const { App } = require('@slack/bolt'); - -const app = new App({ - token: process.env.SLACK_BOT_TOKEN, - signingSecret: process.env.SLACK_SIGNING_SECRET -}); - -// Listens to incoming messages that contain "hello" -app.message('hello', async ({ message, say }) => { - // 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}>!` - }); -}); - -(async () => { - // Start your app - await app.start(process.env.PORT || 3000); - - console.log('⚡️ Bolt app is running!'); -})(); -``` - -The value inside of `say()` is now an object that contains an array of `blocks`. Blocks are the building components of a Slack message and can range from text to images to datepickers. In this case, your app will respond with a section block that includes a button as an accessory. Since we're using `blocks`, the `text` is a fallback for notifications and accessibility. - -You'll notice in the button `accessory` object, there is an `action_id`. This will act as a unique identifier for the button so your app can specify what action it wants to respond to. - -:::tip - -The [Block Kit Builder](https://app.slack.com/block-kit-builder) is a simple way to prototype your interactive messages. The builder lets you (or anyone on your team) mockup messages and generates the corresponding JSON that you can paste directly in your app. - -::: - -Now, if you restart your app and say "hello" in a channel your app is in, you'll see a message with a button. But if you click the button, nothing happens (*yet!*). - -Let's add a handler to send a followup message when someone clicks the button: - -```javascript -const { App } = require('@slack/bolt'); - -const app = new App({ - token: process.env.SLACK_BOT_TOKEN, - signingSecret: process.env.SLACK_SIGNING_SECRET -}); - -// Listens to incoming messages that contain "hello" -app.message('hello', async ({ message, say }) => { - // 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(process.env.PORT || 3000); - - console.log('⚡️ Bolt app is running!'); -})(); -``` - -You can see that we used `app.action()` to listen for the `action_id` that we named `button_click`. If you restart your app and click the button, you'll see a new message from your app that says you clicked the button. - ---- - -### Next steps {#next-steps} -You just built your first [Bolt for JavaScript app](https://github.com/slackapi/bolt-js-getting-started-app)! 🎉 - -Now that you have a basic app up and running, you can start exploring how to make your Bolt app stand out. Here are some ideas about what to explore next: - -* Read through the Basic concepts to learn about the different methods and features your Bolt app has access to. - -* Explore the different events your bot can listen to with the [`events()` method](/concepts/event-listening). All of the events are listed [on the API site](https://api.slack.com/events). - -* Bolt allows you to [call Web API methods](/concepts/web-api) with the client attached to your app. There are [over 200 methods](https://api.slack.com/methods) on our API site. - -* Learn more about the different token types [on our API site](https://api.slack.com/docs/token-types). Your app may need different tokens depending on the actions you want it to perform. If you are using [Socket Mode](/getting-started) instead of HTTP, an additional (`xapp`) token with `connections:write` scopes is required. diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 81c195376..14963051a 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -57,7 +57,23 @@ const config = { redirects: [ { to: '/getting-started', - from: ['/tutorial/getting-started'], + from: ['/tutorial/getting-started','/tutorial/getting-started-http'], + }, + { + to: '/concepts/steps-from-apps', + from: [ + '/concepts/creating-steps', + '/concepts/adding-editing-steps', + '/concepts/saving-steps', + '/concepts/executing-steps' + ], + }, + { + to: '/concepts/actions', + from: [ + '/concepts/action-listening', + '/concepts/action-responding' + ], }, { to: '/', diff --git a/docs/i18n/ja-jp/README.md b/docs/i18n/ja-jp/README.md index 5acce6f8d..c5f04de1a 100644 --- a/docs/i18n/ja-jp/README.md +++ b/docs/i18n/ja-jp/README.md @@ -2,7 +2,7 @@ This README describes how the Japanese documentation is created. Please read the [/docs README](./docs/README) for information on _all_ the documentation. -[Docusaurus](https://docusaurus.io) supports using different languages. Each language is a different version of the same site. The English site is the default. The English page will be viewable if the page is not translated into Japanese. +[Docusaurus](https://docusaurus.io) supports using different languages. Each language is a different version of the same site. The English site is the default. The English page will be viewable if the page is not translated into Japanese. You do not need to place the English page on the Japanese side of the site though! It is automatically pulled during the build process. There will be English pages on the Japanese site of the pages are not translated yet. Japanese readers will not miss any content, but they may be confused seeing English and Japanese mixed together. Please give us your thoughts on this setup. diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current.json b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current.json index c5794d3d0..aa7410656 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current.json +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current.json @@ -3,26 +3,10 @@ "message": "Next", "description": "The label for version current" }, - "sidebar.sidebarJSBolt.category.Basic concepts": { - "message": "基本的な概念", - "description": "The label for category Basic concepts in sidebar sidebarJSBolt" - }, - "sidebar.sidebarJSBolt.category.Advanced concepts": { - "message": "応用コンセプト", - "description": "The label for category Advanced concepts in sidebar sidebarJSBolt" - }, "sidebar.sidebarJSBolt.category.Deployments": { "message": "Deployments", "description": "The label for category Deployments in sidebar sidebarJSBolt" }, - "sidebar.sidebarJSBolt.category.Custom functions (Beta)": { - "message": "Custom functions (Beta)", - "description": "The label for category Custom functions (Beta) in sidebar sidebarJSBolt" - }, - "sidebar.sidebarJSBolt.category.Workflow steps (Deprecated)": { - "message": "ワークフローステップ 非推奨", - "description": "The label for category Workflow steps (Deprecated) in sidebar sidebarJSBolt" - }, "sidebar.sidebarJSBolt.category.Tutorials": { "message": "チュートリアル", "description": "The label for category Tutorials in sidebar sidebarJSBolt" @@ -34,5 +18,45 @@ "sidebar.sidebarJSBolt.link.Contributors Guide": { "message": "貢献", "description": "The label for link Contributors Guide in sidebar sidebarJSBolt, linking to https://github.com/SlackAPI/bolt-js/blob/main/.github/contributing.md" + }, + "sidebar.sidebarJSBolt.category.Slack API calls": { + "message": "Slack API コール", + "description": "The label for category Slack API calls in sidebar sidebarJSBolt" + }, + "sidebar.sidebarJSBolt.category.Events": { + "message": "イベント API", + "description": "The label for category Events in sidebar sidebarJSBolt" + }, + "sidebar.sidebarJSBolt.category.App UI & Interactivity": { + "message": "インタラクティビティ & ショートカット", + "description": "The label for category Interactivity & Shortcuts in sidebar sidebarJSBolt" + }, + "sidebar.sidebarJSBolt.category.App Configuration": { + "message": "App の設定", + "description": "The label for category App Configuration in sidebar sidebarJSBolt" + }, + "sidebar.sidebarJSBolt.category.Middleware & Context": { + "message": "ミドルウェア & コンテキスト", + "description": "The label for category Middleware & Context in sidebar sidebarJSBolt" + }, + "sidebar.sidebarJSBolt.category.Authorization & Security": { + "message": "認可 & セキュリティ", + "description": "The label for category Authorization & Security in sidebar sidebarJSBolt" + }, + "sidebar.sidebarJSBolt.category.Migration Guides": { + "message": "マイグレーションガイド", + "description": "The label for category Migration Guides in sidebar sidebarJSBolt" + }, + "sidebar.sidebarJSBolt.category.Legacy": { + "message": "レガシー(非推奨)", + "description": "The label for category Legacy in sidebar sidebarJSBolt" + }, + "sidebar.sidebarJSBolt.link.Release notes": { + "message": "リリースノート", + "description": "The label for link Release notes in sidebar sidebarJSBolt, linking to https://github.com/slackapi/bolt-js/releases" + }, + "sidebar.sidebarJSBolt.doc.Bolt for JavaScript": { + "message": "Bolt for JavaScript", + "description": "The label for the doc item Bolt for JavaScript in sidebar sidebarJSBolt, linking to the doc index" } } diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/action-respond.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/action-respond.md deleted file mode 100644 index 75d1e3a6d..000000000 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/action-respond.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: アクションへの応答 -lang: ja-jp -slug: /concepts/action-respond ---- - -アクションへの応答には、主に 2 つのやり方があります。1 つ目の (最も一般的な) やり方は `say` 関数の利用です。 `say` 関数は、Slack 内のリクエストが発生した会話(チャンネルや DM)へメッセージを返します。 - -アクションに応答する 2 つ目の方法は `respond()` です。これはアクションに紐付けられている `response_url` を用いたメッセージの送信をシンプルに行うためのユーティリティです。 - -```javascript -// action_id が "approve_button" のインタラクティブコンポーネントがトリガーされる毎にミドルウェアが呼び出される -app.action('approve_button', async ({ ack, say }) => { - // アクションリクエストの確認 - await ack(); - await say('Request approved 👍'); -}); -``` - -
- -`respond()` の使用 - - -`respond()` は `response_url` を呼び出すためのユーティリティであるため、それを直接使うときと同様に動作します。新しいメッセージのペイロードと、オプショナルな引数である `response_type` (値は `in_channel` または `ephemeral` )、 `replace_original` 、 `delete_original` を含む JSON オブジェクトを渡すことができます。 - -```javascript -// "user_select" の action_id がトリガーされたアクションをリッスン -app.action('user_select', async ({ action, ack, respond }) => { - await ack(); - if (action.type === 'users_select') { - await respond(`You selected <@${action.selected_user}>`); - } -}); -``` - -
diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/custom-steps.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/custom-steps.md deleted file mode 100644 index aa4f344cc..000000000 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/custom-steps.md +++ /dev/null @@ -1,167 +0,0 @@ ---- -title: Listening and responding to custom steps -lang: ja-jp -slug: /concepts/custom-steps ---- - -Your app can use the `function()` method to listen to incoming [custom step requests](https://api.slack.com/automation/functions/custom-bolt). Custom steps are used in Workflow Builder to build workflows. The method requires a step `callback_id` of type string. This `callback_id` must also be defined in your [Function](https://api.slack.com/concepts/manifests#functions) definition. Custom steps must be finalized using the `complete()` or `fail()` listener arguments to notify Slack that your app has processed the request. - -* `complete()` requires one argument: an `outputs` object. It ends your custom step **successfully** and provides an object containing the outputs of your custom step as per its definition. -* `fail()` requires **one** argument: `error` of type string. It ends your custom step **unsuccessfully** and provides a message containing information regarding why your custom step failed. - -You can reference your custom step's inputs using the `inputs` listener argument. - -```js -// This sample custom step formats an input and outputs it -app.function('sample_custom_step', async ({ inputs, complete, fail, logger }) => { - try { - const { message } = inputs; - - await complete({ - outputs: { - message: `:wave: You submitted the following message: \n\n>${message}` - } - }); - } catch (error) { - logger.error(error); - await fail({ error: `Failed to handle a function request: ${error}` }); - } -}); -``` - -
- -Example app manifest definition - - -```json -... -"functions": { - "sample_custom_step": { - "title": "Sample custom step", - "description": "Run a sample custom step", - "input_parameters": { - "message": { - "type": "string", - "title": "Message", - "description": "A message to be formatted by a custom step", - "is_required": true, - } - }, - "output_parameters": { - "message": { - "type": "string", - "title": "Messge", - "description": "A formatted message", - "is_required": true, - } - } - } -} -``` - -
- ---- - -### Listening to custom step interactivity events - -Your app's custom steps may create interactivity points for users, for example: Post a message with a button - -If such interaction points originate from a custom step execution, the events sent to your app representing the end-user interaction with these points are considered to be _function-scoped interactivity events_. These interactivity events can be handled by your app using the same concepts we covered earlier, such as [Listening to actions](/concepts/action-listening). - -_function-scoped interactivity events_ will contain data related to the custom step (`function_executed` event) they were spawned from, such as custom step `inputs` and access to `complete()` and `fail()` listener arguments. - -Your app can skip calling `complete()` or `fail()` in the `function()` handler method if the custom step creates an interaction point that requires user interaction before the step can end. However, in the relevant interactivity handler method, your app must invoke `complete()` or `fail()` to notify Slack that the custom step has been processed. - -You’ll notice in all interactivity handler examples, `ack()` is used. It is required to call the `ack()` function within an interactivity listener to acknowledge that the request was received from Slack. This is discussed in the [acknowledging requests section](/concepts/acknowledge). - -```js -/** This sample custom step posts a message with a button */ -app.function('custom_step_button', async ({ client, inputs, fail, logger }) => { - try { - const { user_id } = inputs; - - await client.chat.postMessage({ - channel: user_id, - text: 'Click the button to signal the function has completed', - blocks: [ - { - type: 'section', - text: { - type: 'mrkdwn', - text: 'Click the button to signal the function has completed', - }, - accessory: { - type: 'button', - text: { - type: 'plain_text', - text: 'Complete function', - }, - action_id: 'sample_button', - }, - }, - ], - }); - } catch (error) { - logger.error(error); - await fail({ error: `Failed to handle a function request: ${error}` }); - } -}); - -/** Your listener will be called every time a block element with the action_id "sample_button" is triggered */ -app.action('sample_button', async ({ ack, body, client, complete, fail, logger }) => { - try { - await ack(); - - const { channel, message, user } = body; - // Functions should be marked as successfully completed using `complete` or - // as having failed using `fail`, else they'll remain in an 'In progress' state. - await complete({ outputs: { user_id: user.id } }); - - await client.chat.update({ - channel: channel.id, - ts: message.ts, - text: 'Function completed successfully!', - }); - } catch (error) { - logger.error(error); - await fail({ error: `Failed to handle a function request: ${error}` }); - } -}); -``` - -
- -Example app manifest definition - - -```json -... -"functions": { - "custom_step_button": { - "title": "Custom step with a button", - "description": "Custom step that waits for a button click", - "input_parameters": { - "user_id": { - "type": "slack#/types/user_id", - "title": "User", - "description": "The recipient of a message with a button", - "is_required": true, - } - }, - "output_parameters": { - "user_id": { - "type": "slack#/types/user_id", - "title": "User", - "description": "The user that completed the function", - "is_required": true - } - } - } -} -``` - -
- -Learn more about responding to interactivity, see the [Slack API documentation](https://api.slack.com/automation/functions/custom-bolt#interactivity). diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/acknowledge.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/acknowledge.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/acknowledge.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/acknowledge.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/action-listening.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/actions.md similarity index 60% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/action-listening.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/actions.md index bfe5edbe1..510ac555f 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/action-listening.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/actions.md @@ -1,11 +1,13 @@ --- -title: アクションのリスニング +title: アクション lang: ja-jp -slug: /concepts/action-listening +slug: /concepts/actions --- Bolt アプリは `action` メソッドを用いて、ボタンのクリック、メニューの選択、メッセージショートカットなどのユーザーのアクションをリッスンすることができます。 +## アクションのリスニング + アクションは文字列型の `action_id` または RegExp オブジェクトでフィルタリングできます。 `action_id` は、Slack プラットフォーム上のインタラクティブコンポーネントの一意の識別子として機能します。 すべての `action()` の例で `ack()` が使用されていることに注目してください。Slack からリクエストを受信したことを確認するために、アクションリスナー内で `ack()` 関数を呼び出す必要があります。これについては、「[リクエストの確認](/concepts/acknowledge)」 セクションで説明しています。 @@ -22,10 +24,7 @@ app.action('approve_button', async ({ ack }) => { }); ``` -
- -制約付きオブジェクトを使用したアクションのリスニング - +### 制約付きオブジェクトを使用したアクションのリスニング 制約付きのオブジェクトを使って、 `callback_id` 、 `block_id` 、および `action_id` (またはそれらの組み合わせ) をリッスンすることができます。オブジェクト内の制約には、文字列型または RegExp オブジェクトを使用できます。 @@ -52,4 +51,31 @@ app.action({ action_id: 'select_user', block_id: 'assign_ticket' }, }); ``` -
\ No newline at end of file +## アクションへの応答 + +アクションへの応答には、主に 2 つのやり方があります。1 つ目の (最も一般的な) やり方は `say` 関数の利用です。 `say` 関数は、Slack 内のリクエストが発生した会話(チャンネルや DM)へメッセージを返します。 + +アクションに応答する 2 つ目の方法は `respond()` です。これはアクションに紐付けられている `response_url` を用いたメッセージの送信をシンプルに行うためのユーティリティです。 + +```javascript +// action_id が "approve_button" のインタラクティブコンポーネントがトリガーされる毎にミドルウェアが呼び出される +app.action('approve_button', async ({ ack, say }) => { + // アクションリクエストの確認 + await ack(); + await say('Request approved 👍'); +}); +``` + +### `respond()` の使用 + +`respond()` は `response_url` を呼び出すためのユーティリティであるため、それを直接使うときと同様に動作します。新しいメッセージのペイロードと、オプショナルな引数である `response_type` (値は `in_channel` または `ephemeral` )、 `replace_original` 、 `delete_original` を含む JSON オブジェクトを渡すことができます。 + +```javascript +// "user_select" の action_id がトリガーされたアクションをリッスン +app.action('user_select', async ({ action, ack, respond }) => { + await ack(); + if (action.type === 'users_select') { + await respond(`You selected <@${action.selected_user}>`); + } +}); +``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/authenticating-oauth.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/authenticating-oauth.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/authenticating-oauth.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/authenticating-oauth.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/authorization.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/authorization.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/authorization.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/authorization.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/commands.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/commands.md similarity index 94% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/commands.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/commands.md index 5616bf65e..c71b1d153 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/commands.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/commands.md @@ -10,7 +10,7 @@ slug: /concepts/commands アプリがスラッシュコマンドのリクエストを受け取ったことを `ack()` の実行によって Slack に通知する必要があります。 -スラッシュコマンドへの応答には 2 つのやり方があります。1 つ目の方法は、文字列または JSON ペイロードを受け取る `say()` で、2 つ目は `response_url` を簡単に利用するためのユーティリティである `respond()` です。これらについては、「[アクションへの応答](/concepts/action-respond)」セクションで詳しく説明しています。 +スラッシュコマンドへの応答には 2 つのやり方があります。1 つ目の方法は、文字列または JSON ペイロードを受け取る `say()` で、2 つ目は `response_url` を簡単に利用するためのユーティリティである `respond()` です。これらについては、「[アクションへの応答](/concepts/actions)」セクションで詳しく説明しています。 Slack アプリの管理画面でスラッシュコマンドを設定するとき、そのスラッシュコマンドの Request URL に(`https://{ドメイン}` に続いて) `/slack/events` を指定するようにしてください。 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/context.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/context.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/context.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/context.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/creating-modals.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/creating-modals.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/creating-modals.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/creating-modals.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/custom-routes.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/custom-routes.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/custom-routes.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/custom-routes.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/deferring-initialization.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/deferring-initialization.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/deferring-initialization.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/deferring-initialization.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/error-handling.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/error-handling.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/error-handling.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/error-handling.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/event-listening.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/event-listening.md similarity index 51% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/event-listening.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/event-listening.md index 7dbadd081..8f3c3a0bd 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/event-listening.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/event-listening.md @@ -25,29 +25,4 @@ app.event('team_join', async ({ event, client, logger }) => { logger.error(error); } }); -``` - -
- -メッセージのサブタイプのフィルタリング - - -`message()` リスナーは `event('message')` と等価の機能を提供します。 - -イベントのサブタイプをフィルタリングしたい場合、組み込みの `subtype()` ミドルウェアを使用できます。 `message_changed` や `message_replied` のような一般的なメッセージサブタイプの情報は、[メッセージイベントのドキュメント](https://api.slack.com/events/message#message_subtypes)を参照してください。 - -```javascript -// パッケージから subtype をインポート -const { App, subtype } = require('@slack/bolt'); - -// user からのメッセージの編集と一致 -app.message(subtype('message_changed'), ({ event, logger }) => { - // この if 文は TypeScript でコードを書く際に必要 - if (event.subtype === 'message_changed' - && !event.message.subtype - && !event.previous_message.subtype) { - logger.info(`The user ${event.message.user} changed their message from ${event.previous_message.text} to ${event.message.text}`); - } -}); -``` -
\ No newline at end of file +``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/global-middleware.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/global-middleware.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/global-middleware.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/global-middleware.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/listener-middleware.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/listener-middleware.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/listener-middleware.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/listener-middleware.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/logging.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/logging.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/logging.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/logging.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/message-listening.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-listening.md similarity index 54% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/message-listening.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-listening.md index 254d3aea1..b03033f37 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/message-listening.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-listening.md @@ -4,7 +4,8 @@ lang: ja-jp slug: /concepts/message-listening --- -[アプリが受信可能な](https://api.slack.com/messaging/retrieving#permissions)メッセージをリッスンするには、`message` 型でないイベントを除外する `message()` メソッドを使用します。 +[アプリが受信可能な](https://api.slack.com/messaging/retrieving#permissions)メッセージをリッスンするには、`message` 型でないイベントを除外する `message()` メソッドを使用します。`message()` リスナーは `event('message')` と等価の機能を提供します。 + `message()` は、`string` 型か `RegExp` 型の、指定パターンに一致しないメッセージを除外する `pattern` パラメーター(指定は必須ではありません)を受け付けます。 @@ -21,10 +22,7 @@ app.message(':wave:', async ({ message, say }) => { }); ``` -
- -正規表現(RegExp) パターンの使用 - +## 正規表現(RegExp) パターンの使用 文字列の代わりに 正規表現(RegExp) パターンを使用すると、より細やかなマッチングが可能です。 @@ -39,4 +37,21 @@ app.message(/^(hi|hello|hey).*/, async ({ context, say }) => { }); ``` -
\ No newline at end of file +## メッセージのサブタイプのフィルタリング + + +イベントのサブタイプをフィルタリングしたい場合、組み込みの `subtype()` ミドルウェアを使用できます。 `message_changed` や `message_replied` のような一般的なメッセージサブタイプの情報は、[メッセージイベントのドキュメント](https://api.slack.com/events/message#message_subtypes)を参照してください。 + +```javascript +// パッケージから subtype をインポート +const { App, subtype } = require('@slack/bolt'); + +// user からのメッセージの編集と一致 +app.message(subtype('message_changed'), ({ event, logger }) => { + // この if 文は TypeScript でコードを書く際に必要 + if (event.subtype === 'message_changed' + && !event.message.subtype + && !event.previous_message.subtype) { + logger.info(`The user ${event.message.user} changed their message from ${event.previous_message.text} to ${event.message.text}`); + } +}); \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/message-sending.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-sending.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/message-sending.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-sending.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/publishing-views.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/publishing-views.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/publishing-views.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/publishing-views.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/receiver.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/receiver.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/receiver.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/receiver.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/options.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/select-menu-options.md similarity index 92% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/options.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/select-menu-options.md index 430e9b4f5..2a81d89ec 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/options.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/select-menu-options.md @@ -4,7 +4,7 @@ lang: ja-jp slug: /concepts/options --- -`options()` メソッドは、Slack からのオプション(セレクトメニュー内の動的な選択肢)をリクエストするペイロードをリッスンします。 [`action()` と同様](/concepts/action-listening)に、文字列型の `action_id` または制約付きオブジェクトが必要です。 +`options()` メソッドは、Slack からのオプション(セレクトメニュー内の動的な選択肢)をリクエストするペイロードをリッスンします。 [`action()` と同様](/concepts/actions)に、文字列型の `action_id` または制約付きオブジェクトが必要です。 `external_select` メニューには `action_id` を使用することをおすすめしますが、ダイアログはまだ Block Kit をサポートしていないため、制約オブジェクトを用いて `callback_id` でフィルタリングする必要があります。 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/shortcuts.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/shortcuts.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/shortcuts.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/shortcuts.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/socket-mode.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/socket-mode.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/socket-mode.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/socket-mode.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/token-rotation.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/token-rotation.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/token-rotation.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/token-rotation.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/updating-pushing-views.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/updating-pushing-views.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/updating-pushing-views.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/updating-pushing-views.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/view-submissions.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/view-submissions.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/view-submissions.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/view-submissions.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/web-api.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/web-api.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/basic/web-api.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/web-api.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/getting-started.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/getting-started.mdx similarity index 70% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/getting-started.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/getting-started.mdx index 2bfc095af..ccee79ded 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/getting-started.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/getting-started.mdx @@ -9,11 +9,7 @@ lang: ja-jp このガイドでは、Bolt を使用して Slack アプリを起動し実行する方法について説明します。その過程で、新しい Slack アプリを作成し、ローカル環境を設定し、Slack ワークスペースからのメッセージをリッスンして応答するアプリを開発します。 -:::tip - -このガイドでは[ソケットモード](https://api.slack.com/apis/connections/socket) を利用します。ソケットモードは、Slack アプリ開発をとりあえず始めてみるときやあなたのチームだけのためのアプリをつくるときにおすすめのやり方です。もしすでに HTTP をアプリのコミュニケーションプロトコルとしてするとわかっているなら、HTTP の方式に対応した同様のドキュメントである [Bolt 入門ガイド(HTTP)](/tutorial/getting-started-http) を参照してください。 - -::: +このガイドが終わったら、あなたはこの⚡️[Getting Started app](https://github.com/slackapi/bolt-js-getting-started-app)を実行したり、修正したり、自分で作ったりすることができます。 --- @@ -79,17 +75,23 @@ npm init Bolt パッケージを新しいプロジェクトにインストールする前に、アプリの設定時に生成されたボットトークンと signing secret (サイン認証) を保存しましょう。これらは環境変数として保存する必要があります。**バージョン管理では保存しない**でください。 -1. **Basic Information ページから Signing Secret をコピー**して、新しい環境変数に保存します。次の例は Linux と macOS で動作します。ただし、[Windows でも同様のコマンドが利用可能](https://superuser.com/questions/212150/how-to-set-env-variable-in-windows-cmd-line/212153#212153)です。 +1. **Basic Information ページから Signing Secret をコピー**して、新しい環境変数に保存します。次の例は Linux と macOS で動作します。ただし、[Windows でも同様のコマンドが利用可能](https://superuser.com/questions/212150/how-to-set-env-variable-in-windows-cmd-line/212153#212153)です。 + ```shell export SLACK_SIGNING_SECRET= ``` -2. **OAuth & Permissions ページからボット (xoxb) トークンをコピー**し、それを別の環境変数に格納します。 +2. **OAuth & Permissions ページからボット (xoxb) トークンをコピー**し、それを別の環境変数に格納します。 + ```shell export SLACK_BOT_TOKEN=xoxb- ``` -> 🔒 全てのトークンは安全に保管してください。少なくともパブリックなバージョン管理にチェックインするようなことは避けるべきでしょう。また、上にあった例のように環境変数を介してアクセスするようにしてください。詳細な情報は [アプリのセキュリティのベストプラクティス](https://api.slack.com/authentication/best-practices)のドキュメントを参照してください。 +:::info + +🔒 全てのトークンは安全に保管してください。少なくともパブリックなバージョン管理にチェックインするようなことは避けるべきでしょう。また、上にあった例のように環境変数を介してアクセスするようにしてください。詳細な情報は [アプリのセキュリティのベストプラクティス](https://api.slack.com/authentication/best-practices)のドキュメントを参照してください。 + +::: それでは、アプリを作成しましょう。次のコマンドを使用して、`@slack/bolt` パッケージをインストールし、 `package.json` 中で依存ファイルとして保存します。 @@ -130,11 +132,19 @@ node app.js アプリはワークスペース内の他のメンバーと同じように振る舞い、メッセージを投稿したり、絵文字リアクションを追加したり、イベントをリッスンして返答したりできます。 -Slack ワークスペースで発生するイベント(メッセージが投稿されたときや、メッセージに対するリアクションがつけられたときなど)をリッスンするには、[Events API を使って特定の種類のイベントをサブスクライブします](https://api.slack.com/events-api)。このチュートリアルでは、[ソケットモード](https://api.slack.com/apis/connections/socket)を使用します。 Socket モードは、チームのために何かを作り始めたばかりの人にお勧めのオプションです。 +Slack ワークスペースで発生するイベント(メッセージが投稿されたときや、メッセージに対するリアクションがつけられたときなど)をリッスンするには、[Events API を使って特定の種類のイベントをサブスクライブします](https://api.slack.com/events-api)。 + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + +このチュートリアルでは、[ソケットモード](https://api.slack.com/apis/connections/socket)を使用します。 Socket モードは、チームのために何かを作り始めたばかりの人にお勧めのオプションです。 :::tip -ソケットモードを使うことで、アプリが公開された HTTP エンドポイントを公開せずに Events API やインタラクティブコンポーネントを利用できるようになります。このことは、開発時やファイヤーウォールの裏からのリクエストを受ける際に便利です。HTTP での方式はホスティング環境([AWS](/deployments/aws-lambda) or [Heroku](/deployments/heroku)など)にデプロイするアプリや Slack App Directory で配布されるアプリに適しています。 HTTP での情報については[こちらのドキュメント](/tutorial/getting-started-http#setting-up-events-with-http)を参照してください。 +ソケットモードを使うことで、アプリが公開された HTTP エンドポイントを公開せずに Events API やインタラクティブコンポーネントを利用できるようになります。このことは、開発時やファイヤーウォールの裏からのリクエストを受ける際に便利です。HTTP での方式はホスティング環境([AWS](/deployments/aws-lambda) or [Heroku](/deployments/heroku)など)にデプロイするアプリや Slack App Directory で配布されるアプリに適しています。 HTTP での情報については[こちらのドキュメント](#setting-up-events)を参照してください。 ::: @@ -144,6 +154,30 @@ Slack ワークスペースで発生するイベント(メッセージが投 2. **Basic Information** にアクセスし、「App Token」セクションの下にスクロールし、**Generate Token and Scopes** をクリックしてアプリトークンを生成します。このトークンに `connections:write` スコープを追加し、生成された `xapp` トークンを保存します。 + + + +アプリのイベントを有効にしましょう。 + +1. アプリのイベントを有効にするには、まずアプリ設定ページに戻ります ([アプリ管理ページ](https://api.slack.com/apps)でアプリをクリックします)。左側のサイドバーにある **Event Subscription** をクリックします。**Enable Events** のスイッチをオンにします。 + +2. Request URLを追加します。Slackはイベントに対応するHTTP POSTリクエストをこの[Request URL](https://api.slack.com/apis/connections/events-api#the-events-api__subscribing-to-event-types__events-api-request-urls)エンドポイントに送信します。Boltは`/slack/events`のパスを使用して、すべての受信リクエスト(ショートカット、イベント、インタラクティビティのペイロードなど)をリッスンします。アプリの設定でRequest URLを設定する際には、`https:///slack/events`のように`/slack/events`を追加します。💡 + +:::tip + +ローカル開発では、[ngrok](https://ngrok.com/)のようなプロキシサービスを使って公開 URL を作成し、リクエストを開発環境にトンネリングすることができます。このトンネリングの方法については、[ngrok のガイド](https://ngrok.com/docs#getting-started-expose)を参照してください。 + +::: + +最後に、聞きたいイベントをSlackに伝えましょう。**Event Subscriptions**の下にある、**Enable Events**というラベルの付いたスイッチを切り替えます。 + +イベントが発生すると、Slack は、そのイベントをトリガーしたユーザーやイベントが発生したチャンネルなど、イベントに関する情報をアプリに送信します。アプリが詳細を処理し、それに応じて応答することができます。 + +**Request URL** ボックスの **Enable Events** スイッチの下のフィールドにこの URL を貼り付けます。Bolt アプリが引き続き実行されている場合は、URL が検証されチェックマークが表示されます。 + + + + そして最後に、私たちがどのイベントをリッスンしたいかを Slack に伝えましょう。 イベントが発生すると、そのイベントをトリガーしたユーザーやイベントが発生したチャンネルなど、イベントに関する情報が Slack からアプリに送信されます。アプリではこれらの情報を処理して、適切な応答を返します。 @@ -163,6 +197,9 @@ Slack ワークスペースで発生するイベント(メッセージが投 次の例では、あなたのアプリが追加されているチャンネルや DM で `hello` という単語を含むすべてのメッセージをリッスンし、 `Hey there @user!` と応答します。 + + + ```javascript const { App } = require('@slack/bolt'); @@ -190,6 +227,34 @@ app.message('hello', async ({ message, say }) => { })(); ``` + + + +```javascript +const { App } = require('@slack/bolt'); + +const app = new App({ + token: process.env.SLACK_BOT_TOKEN, + signingSecret: process.env.SLACK_SIGNING_SECRET +}); + +// "hello" を含むメッセージをリッスンします +app.message('hello', async ({ message, say }) => { + // イベントがトリガーされたチャンネルに say() でメッセージを送信します + await say(`Hey there <@${message.user}>!`); +}); + +(async () => { + // アプリを起動します + await app.start(process.env.PORT || 3000); + + console.log('⚡️ Bolt app is running!'); +})(); +``` + + + + アプリを再起動したら、ボットユーザーをチャンネル、 DM に追加し、 `hello` を含むメッセージを送信してみてください。アプリが応答したら成功です。 これは基本的な例ですが、ここから自分の好きなようにアプリをカスタマイズしていくことができます。さらにインタラクティブな動作を試すために、プレーンテキストではなくボタンを送信してみましょう。 @@ -200,12 +265,27 @@ app.message('hello', async ({ message, say }) => { ボタン、選択メニュー、日付ピッカー、モーダルなどの機能を使用するには、インタラクティブ機能を有効にする必要があります。イベントと同様に、Slack の URL を指定してアクション ( 「ボタン・クリック」など) を送信する必要があります。 + + + +ソケットモードを有効にしているとき、デフォルトで基本的なインタラクティブ機能が有効になっていため、ここでは特に何もする必要はいありません。 + + + + +アプリ設定ページに戻り、左側の **Interactivity & Shortcuts** をクリックします。**Request URL** ボックスがもう 1 つあることがわかります。 + :::tip -ソケットモードを有効にしているとき、デフォルトで基本的なインタラクティブ機能が有効になっていため、ここでは特に何もする必要はいありません。もし HTTP を使っている場合、Slack からのイベント送信先である Request URL を設定する必要があります。 +デフォルトでは、Bolt はイベントに使用しているのと同じエンドポイントをインタラクティブコンポーネントに使用するように設定されているため、上記と同じリクエスト URL (この例では `https://8e8ec2d7.ngrok.io/slack/events`) を使用します。右下隅にある **Save Changes** ボタンを押してください。これでアプリのインタラクティブなコンポーネントを利用する設定が有効になりました! ::: +![Configuring a Request URL](/img/request-url-config.png "Configuring a Request URL") + + + + インタラクティブ機能が有効化されていると、ショートカット、モーダル、インタラクティブコンポーネント (例:ボタン、選択メニュー、日付ピッカーなど) とのインタラクションがイベントとしてあなたのアプリに送信されます。 それでは、アプリのコードに戻り、インタラクティブな処理を追加しましょう。この実装は以下の二つのステップで構成されます。 @@ -214,6 +294,9 @@ app.message('hello', async ({ message, say }) => { 以下は、前のセクションで記述したアプリコードを、文字列だけでなく、ボタン付きのメッセージを送信するように変更したものです。 + + + ```javascript const { App } = require('@slack/bolt'); @@ -260,6 +343,53 @@ app.message('hello', async ({ message, say }) => { })(); ``` + + + +```javascript +const { App } = require('@slack/bolt'); + +const app = new App({ + token: process.env.SLACK_BOT_TOKEN, + signingSecret: process.env.SLACK_SIGNING_SECRET +}); + +// "hello" を含むメッセージをリッスンします +app.message('hello', async ({ message, say }) => { + // イベントがトリガーされたチャンネルに say() でメッセージを送信します + 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}>!` + }); +}); + +(async () => { + // アプリを起動します + await app.start(process.env.PORT || 3000); + + console.log('⚡️ Bolt app is running!'); +})(); +``` + + + + `say()` に格納されている値が、 `blocks` の配列を含むオブジェクトになりました。このブロックは Slack メッセージを構成するコンポーネントであり、テキストや画像、日付ピッカーなど、さまざまなタイプがあります。この例では、アプリは、ボタンを `accessory` として含むセクションブロックを使用して応答します。`blocks` を使っている場合、 `text` は通知やアクセシビリティのためのフォールバックとして使用されます。 このボタン `accessory` オブジェクトには、`action_id` が割り当てられています。これはボタンの一意の識別子として機能するため、アプリはどのアクションに応答するかを指定できます。 @@ -274,6 +404,9 @@ app.message('hello', async ({ message, say }) => { ボタンがクリックされるとフォローアップメッセージを送信するハンドラーを追加してみましょう。 + + + ```javascript const { App } = require('@slack/bolt'); @@ -326,12 +459,66 @@ app.action('button_click', async ({ body, ack, say }) => { })(); ``` + + + + +```javascript +const { App } = require('@slack/bolt'); + +const app = new App({ + token: process.env.SLACK_BOT_TOKEN, + signingSecret: process.env.SLACK_SIGNING_SECRET +}); + +// "hello" を含むメッセージをリッスンします +app.message('hello', async ({ message, say }) => { + // イベントがトリガーされたチャンネルに say() でメッセージを送信します + 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 }) => { + // アクションのリクエストを確認 + await ack(); + await say(`<@${body.user.id}> clicked the button`); +}); + +(async () => { + // アプリを起動します + await app.start(process.env.PORT || 3000); + + console.log('⚡️ Bolt app is running!'); +})(); +``` + + + + このように、`app.action()` を使うことで `button_click` という `action_id` のボタンアクションのリスナーを追加できるのです。アプリを再起動してボタンをクリックしてみましょう。すると、you clicked the button という新しいメッセージがアプリに表示されるはずです。 --- ### 次のステップ {#next-steps} -これで最初の Bolt アプリをソケットモードを使って構築できました! 🎉 +これで最初の Bolt アプリが構築できました! 🎉 基本的なアプリの作成ができましたので、次回は是非もっといろいろな、 Bolt の機能を使ってアプリを作ってみましょう。下記のリンクを辿っていろいろアイデアを模索してみてください! @@ -340,5 +527,3 @@ app.action('button_click', async ({ body, ack, say }) => { * ボットが[`events()` メソッド](/concepts/event-listening)でリッスンできるさまざまなイベントを確認しましょう。イベントはすべて[API サイト](https://api.slack.com/events)にリストされています。 * Bolt を使用すると、アプリにアタッチされているクライアントで [Web API メソッドを呼び出す](/concepts/web-api)ことができます。API サイトに [200 を超えるメソッド](https://api.slack.com/methods)を用意してあります。 - -* [API サイト](https://api.slack.com/docs/token-types)では、様々なトークンタイプの詳細を確認することができます。アプリには、実行するアクションに応じて異なるトークンが必要になる場合があります。ソケットモードを使わないアプリでは、通常はボットトークン (`xoxb`) と署名シークレットが必要です。ソケットモードを使わない場合の例については、 HTTP 方式のやり方としてこのチュートリアルと対になっている [Bolt 入門ガイド(HTTP)](/tutorial/getting-started-http)を参照してください。 \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/conversation-store.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/conversation-store.md similarity index 100% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/advanced/conversation-store.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/conversation-store.md diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/hubot-migration.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/hubot-migration.md similarity index 97% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/hubot-migration.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/hubot-migration.md index 30d5173db..358171433 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/hubot-migration.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/hubot-migration.md @@ -24,7 +24,7 @@ Bolt アプリを作成する前に考慮に入れた方がよい違いがほか --- ### ボットの設定 {#configuring-your-bot} -ボットユーザーを持つ既存の Slack アプリをお持ちの方は、[次のセクションに進むことができます](#ボットの設定-1)。わからない場合は、[App Management ページ](https://api.slack.com/apps) に移動し、自分の Hubot アプリがあるかどうかを確認してください。ある場合は、そのアプリの認証情報をそのまま使用できます ([次のセクションに進んでください](#ボットの設定-1))。ない場合は、下記の手順通りに進めていきましょう。 +ボットユーザーを持つ既存の Slack アプリをお持ちの方は, 次のセクションに進むことができます。わからない場合は、[App Management ページ](https://api.slack.com/apps) に移動し、自分の Hubot アプリがあるかどうかを確認してください。ある場合は、そのアプリの認証情報をそのまま使用できます (次のセクションに進んでください)。ない場合は、下記の手順通りに進めていきましょう。 #### Slack アプリを作成する まず最初に、Slack アプリを作成します。 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/steps-from-apps.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/steps-from-apps.md new file mode 100644 index 000000000..a131e4320 --- /dev/null +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/steps-from-apps.md @@ -0,0 +1,194 @@ +--- +title: ワークフローステップの概要 +lang: ja-jp +slug: /concepts/steps-from-apps +--- + +(アプリによる)ワークフローステップ(Workflow Steps from Apps) は、[ワークフロービルダー](https://api.slack.com/workflows)におけるワークフローに組み込み可能なカスタムのワークフローステップを任意の Slack アプリが提供することを可能とします。 + +ワークフローステップは、三つの異なるユーザーイベントから構成されます: + +- ワークフロー作成者がワークフローにカスタムステップを追加・または編集する +- ワークフロー作成者がステップの設定を保存・更新する +- ワークフローの利用者がそのワークフローステップを実行する + +ワークフローステップを機能させるためには、これら三つのイベント全てを適切にハンドリングする必要があります。 + +ワークフローステップのさらなる詳細については [API ドキュメント](https://api.slack.com/workflows/steps)を参考にしてください。 + +--- + +## ステップの定義 + +ワークフローステップを作るための手段として Bolt は `WorkflowStep` というクラスを提供しています。 + +新しい `WorkflowStep` インスタンスの生成には、そのステップの `callback_id` と設定オブジェクトを渡します。 + +設定オブジェクトには `edit`、`save`、`execute` という三つのプロパティがあります。これらのそれぞれは単一のコールバック関数、またはコールバック関数の配列である必要があります。すべてのコールバック関数は、ワークフローステップのイベントに関する情報を保持しする `step` オブジェクトにアクセスすることができます。 + +`WorkflowStep` インスタンスを生成したら、それを `app.step()` メソッドに渡します。これによって、Bolt アプリは対象のワークフローステップのイベントをリッスンしたり、設定オブジェクトが提供するコールバック関数を使ってイベントに応答したりすることができるようになります。 + + +```javascript +const { App, WorkflowStep } = require('@slack/bolt'); + +// いつも通り Bolt アプリを初期化 +const app = new App({ + signingSecret: process.env.SLACK_SIGNING_SECRET, + token: process.env.SLACK_BOT_TOKEN, +}); + +// WorkflowStep インスタンスを生成 +const ws = new WorkflowStep('add_task', { + edit: async ({ ack, step, configure }) => {}, + save: async ({ ack, step, update }) => {}, + execute: async ({ step, complete, fail }) => {}, +}); + +app.step(ws); +``` + +--- + +## ステップの追加・編集 + +ワークフローの作成者が、アプリが提供するステップをワークフローに追加(またはその設定を変更)するタイミングで、アプリは [`workflow_step_edit`](https://api.slack.com/reference/workflows/workflow_step_edit) というイベントを受信します。このイベントの受信時に `WorkflowStep` 設定オブジェクト内の `edit` コールバック関数が実行されます。 + +このとき、ワークフロー作成・変更のどちらの場合でも、アプリは[ワークフローステップ設定のためのモーダル](https://api.slack.com/reference/workflows/configuration-view)を応答する必要があります。このモーダルは、ワークフローステップに固有の設定である必要があり、通常のモーダルにはない制約があります。最もわかりやすいものとしては、`title​`、`submit​`、`close` プロパティを設定することができません。また、デフォルトの設定では、この設定モーダルの `callback_id` はワークフローステップのものと同じものが使用されます。 + +`edit` コールバック関数の中では モーダルの view のうち `blocks` だけを渡すだけで簡単にステップ設定モーダルをオープンすることができる `configure()` というユーティリティ関数が利用できます。これは、必要な入力内容が揃うまで設定の保存を無効にする `submit_disabled` というオプションを `true` に設定します。 + +設定モーダルを開く処理に関するさらなる詳細は、[ドキュメント](https://api.slack.com/workflows/steps#handle_config_view)を参考にしてください。 + +```javascript +const ws = new WorkflowStep('add_task', { + edit: async ({ ack, step, configure }) => { + await ack(); + + const blocks = [ + { + type: 'input', + block_id: 'task_name_input', + element: { + type: 'plain_text_input', + action_id: 'name', + placeholder: { + type: 'plain_text', + text: 'Add a task name', + }, + }, + label: { + type: 'plain_text', + text: 'Task name', + }, + }, + { + type: 'input', + block_id: 'task_description_input', + element: { + type: 'plain_text_input', + action_id: 'description', + placeholder: { + type: 'plain_text', + text: 'Add a task description', + }, + }, + label: { + type: 'plain_text', + text: 'Task description', + }, + }, + ]; + + await configure({ blocks }); + }, + save: async ({ ack, step, update }) => {}, + execute: async ({ step, complete, fail }) => {}, +}); +``` + +--- + +## ステップの設定の保存 + +ワークフローステップの設定モーダルが開いたら、アプリはワークフロー作成者がモーダルを送信するイベントである `view_submission` イベントを待ち受けます。このイベントを受信すると `WorkflowStep` 設定オブジェクト内の `save` コールバック関数が実行されます。 + +`save` コールバック関数の中では、以下の引数を渡してステップの設定を保存するための `update()` 関数を利用できます。 + +- `inputs` は、ワークフローステップ実行時にアプリが受け取ることを期待するデータの内容を表現するオブジェクトです +- `outputs` は、ステップの実行が正常に完了したとき、同一ワークフロー内の後続のステップに提供するデータの内容を表現するオブジェクトの配列です。 +- `step_name` は、デフォルトのステップ名を上書きするために使用します +- `step_image_url` は、デフォルトのステップのイメージ画像を上書きするために使用します + +これら引数をどのように構成するかの詳細は、[ドキュメント](https://api.slack.com/reference/workflows/workflow_step)を参考にしてください。 + +```javascript +const ws = new WorkflowStep('add_task', { + edit: async ({ ack, step, configure }) => {}, + save: async ({ ack, step, view, update }) => { + await ack(); + + const { values } = view.state; + const taskName = values.task_name_input.name; + const taskDescription = values.task_description_input.description; + + const inputs = { + taskName: { value: taskName.value }, + taskDescription: { value: taskDescription.value } + }; + + const outputs = [ + { + type: 'text', + name: 'taskName', + label: 'Task name', + }, + { + type: 'text', + name: 'taskDescription', + label: 'Task description', + } + ]; + + await update({ inputs, outputs }); + }, + execute: async ({ step, complete, fail }) => {}, +}); +``` + + +--- + +## ステップの実行 + +ワークフローの利用者によって、アプリが提供するカスタムのワークフローステップが実行されるとき、アプリは[`workflow_step_execute`](https://api.slack.com/events/workflow_step_execute) というイベントを受信します。このイベントの受信時に `WorkflowStep` 設定オブジェクト内の `execute` コールバック関数が実行されます。 + +`save` コールバック関数で予め規定された `inputs` の情報を使って、ここでの処理は、サードパーティの API を呼び出したり、データベースに情報を保存したり、そのユーザーのホームタブを更新したり、`outputs` オブジェクトを構築することで後続のワークフローステップが利用できる情報を設定したりします。 + +`execute` コールバック関数内では、ステップの実行が成功であることを Slack 側に伝える `complete()` 関数、失敗であることを伝える `fail()` 関数のいずれかを呼び出す必要があります。 + +```javascript +const ws = new WorkflowStep('add_task', { + edit: async ({ ack, step, configure }) => {}, + save: async ({ ack, step, update }) => {}, + execute: async ({ step, complete, fail }) => { + const { inputs } = step; + + const outputs = { + taskName: inputs.taskName.value, + taskDescription: inputs.taskDescription.value, + }; + + // もし全て OK なら + await complete({ outputs }); + // 注意: processBeforeResponse: true を指定している場合 + // ここでは await complete() はおすすめしません。呼び出す API の応答が遅いためです。 + // これにより、3 秒以内に Slack のイベント API に応答することができなくなる場合があります。 + // 代わりに以下のようにすることができます: + // complete({ outputs }).then(() => { console.log('workflow step execution complete registered'); }); + + // もし何か問題が起きたら + // fail({ error: { message: "Just testing step failure!" } }).then(() => { console.log('workflow step execution failure registered'); }); + }, +}); +``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/migration-v2.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v2.md similarity index 96% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/migration-v2.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v2.md index ec65f0020..1361e1f5a 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/migration-v2.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v2.md @@ -1,6 +1,6 @@ --- title: 2.x マイグレーションガイド -slug: migration-v2 +slug: /tutorial/migration-v2 lang: ja-jp --- @@ -8,7 +8,7 @@ lang: ja-jp このガイドは Bolt 1.x を利用しているアプリを 2.x にアップグレードするための手順について説明します。いくつかの変更が必要とはなりますが、ほとんどのアプリの場合で、おそらく対応に必要な時間は 5 〜 15 分程度です。 -*注: もしすぐにアップグレードをしない場合は、[Bolt 1.x に関するサポートスケジュール](#bolt-1x-%E3%81%AE%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)をご確認ください* +*注: もしすぐにアップグレードをしない場合は、[Bolt 1.x に関するサポートスケジュール](#slackbolt1x-support-schedule)をご確認ください* --- diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/migration-v3.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v3.md similarity index 99% rename from docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/migration-v3.md rename to docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v3.md index 2cea018cc..cc795ed16 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/migration-v3.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v3.md @@ -1,6 +1,6 @@ --- title: 3.x マイグレーションガイド -slug: migration-v3 +slug: /tutorial/migration-v3 lang: ja-jp --- # 3.x マイグレーションガイド diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/reference.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/reference.md index 175c11311..ddf47a638 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/reference.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/reference.md @@ -8,18 +8,6 @@ permalink: /reference このガイドでは、Bolt インターフェイスのリスナー関数、リスナー関数の引数、初期化オプション、エラーについて詳しく説明します。⚡[入門ガイド](/getting-started)をまだ完了していない場合は、先にそちらで Bolt for JavaScript アプリ開発の基本を確認しておきましょう。 -- [リスナー関数](#listener-functions) - - [メソッド](#methods) - - [リスナー関数の引数](#listener-function-arguments) - - [リスナーミドルウェアとの違い](#difference-from-listener-middleware) -- [初期化オプション](#initialization-options) - - [レシーバーオプション](#receiver-options) - - [Appオプション](#app-options) -- [フレームワークのエラー](#framework-error-types) - - [クライアント側のエラー](#client-errors) - ---- - ## リスナー関数 {#listener-functions} Slack アプリは通常、Slack からのイベント情報を受け取ったり、それに応答を返したりします。受信するイベントは 1 つの場合もあれば、多数の場合もあります。例えば、Events API のイベント(アプリに関連するリンクが共有されたときなど)や、ユーザーがアプリのショートカットを実行するイベントを受け取ったりします。Slack からのリクエストの種類に応じて、それぞれ異なるメソッドが用意されています。これらのメソッドに、それらのイベントを処理したり応答を返したりするための**リスナー関数**を渡します。 @@ -33,7 +21,7 @@ Slack アプリは通常、Slack からのイベント情報を受け取った | `app.action(actionId, fn);` | Block Kit エレメントから送信される `action` イベントをリッスンします。このイベントにはユーザーのボタン操作、メニュー選択、日付ピッカーの操作などがあります。`actionId` は文字列型で、アプリがビュー内に含めたブロックエレメントに指定した一意の `action_id` の値と一致する必要があります。ここでいう「ビュー」とは、メッセージ、モーダル、アプリのホームタブのことを指します。アクションエレメントを `input` ブロックに配置した場合はイベントがトリガーされないことに注意してください。 | `app.shortcut(callbackId, fn);` | グローバルショートカットまたはメッセージショートカットの呼び出しをリッスンします。`callbackId` は文字列または正規表現で、アプリの設定で指定したショートカットの `callback_id` にマッチする必要があります。 | `app.view(callbackId, fn);` | `view_submission` イベントと `view_closed` イベントをリッスンします。`view_submission` イベントは、アプリが開いたモーダルでユーザーがデータ送信の操作をしたときに発生します。`view_closed` イベントは、ユーザーがデータ送信を実行せずにモーダルを閉じたときに発生します。 -| `app.step(workflowStep)` | `WorkflowStep` のインスタンスに渡されたコールバックを使用して、ワークフローステップイベントのリッスンと応答を行います。コールバックには `edit`、`save`、`execute` の 3 種類があります。ワークフローステップについて詳しくは、[ドキュメント](/concepts/adding-editing-steps)を参照してください。 +| `app.step(workflowStep)` | `WorkflowStep` のインスタンスに渡されたコールバックを使用して、ワークフローステップイベントのリッスンと応答を行います。コールバックには `edit`、`save`、`execute` の 3 種類があります。ワークフローステップについて詳しくは、[ドキュメント](/concepts/steps-from-apps)を参照してください。 | `app.command(commandName, fn);` | Slash コマンドの呼び出しをリッスンします。`commandName` は文字列型で、アプリの設定で指定したスラッシュコマンドと一致する必要があります。スラッシュコマンドの名前では `/` を最初に配置します(例 : `/helpdesk`)。 | `app.options(actionId, fn);` | 外部データソースを使用するセレクトメニューなどから送られる選択肢読み込みのリクエストをリッスンします。使う機会は多くありませんが、`app.action` と混同しないようにしましょう。`actionId` は文字列型で、アプリがビュー内に[外部データソースを使用するセレクトメニュー](https://api.slack.com/reference/block-kit/block-elements#external_select)を含めるときに指定した`action_id` と一致する必要があります。 @@ -134,7 +122,7 @@ Bolt では、さまざまなエラーが定義されています。これらに | `ReceiverMultipleAckError` | Receiver 内で、すでに確認が済んでいるリクエストに対してアプリがさらに `ack()` を呼んだ場合にスローされるエラーです。現在、デフォルトの `HTTPReceiver` でのみ使用されます。 | | `ReceiverAuthenticityError` | アプリのリクエストの署名が検証できないときにスローされるエラーです。このエラーには、失敗した理由を示す情報が含まれます(例 : タイムスタンプが有効でない、ヘッダーに抜けがある、署名シークレットが有効でない)。 | `MultipleListenerError` | 単一のイベントに対して複数のリスナーでの処理中に複数のエラーが発生した場合にスローされるエラーです。個々のエラーを配列に収めた `originals` プロパティを持ちます。 | -| `WorkflowStepInitializationError` | 新しい `WorkflowStep` をインスタンス化する際に、設定オプションが無効な場合、または不足している場合にスローされるエラーです。原因として、`callback_id` が指定されていない、または設定オブジェクトが指定されていないことが考えられます。ワークフローステップについて詳しくは、[ドキュメント](/concepts/creating-steps)を参照してください。 | +| `WorkflowStepInitializationError` | 新しい `WorkflowStep` をインスタンス化する際に、設定オプションが無効な場合、または不足している場合にスローされるエラーです。原因として、`callback_id` が指定されていない、または設定オブジェクトが指定されていないことが考えられます。ワークフローステップについて詳しくは、[ドキュメント](/concepts/steps-from-apps)を参照してください。 | | `UnknownError` | フレームワーク内でスローされる、特定のエラーコードを持たないエラーです。`original` プロパティで詳細を確認できます。 | > [errors.ts](https://github.com/slackapi/bolt-js/blob/main/src/errors.ts) のコードで、エラー定義の部分とコンストラクターの部分を読み、参考にしてみてください。 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/adding-editing-steps.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/adding-editing-steps.md deleted file mode 100644 index 376aedaee..000000000 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/adding-editing-steps.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: ステップの追加・編集 -lang: ja-jp -slug: /concepts/adding-editing-steps ---- - -ワークフローの作成者が、アプリが提供するステップをワークフローに追加(またはその設定を変更)するタイミングで、アプリは [`workflow_step_edit`](https://api.slack.com/reference/workflows/workflow_step_edit) というイベントを受信します。このイベントの受信時に `WorkflowStep` 設定オブジェクト内の `edit` コールバック関数が実行されます。 - -このとき、ワークフロー作成・変更のどちらの場合でも、アプリは[ワークフローステップ設定のためのモーダル](https://api.slack.com/reference/workflows/configuration-view)を応答する必要があります。このモーダルは、ワークフローステップに固有の設定である必要があり、通常のモーダルにはない制約があります。最もわかりやすいものとしては、`title​`、`submit​`、`close` プロパティを設定することができません。また、デフォルトの設定では、この設定モーダルの `callback_id` はワークフローステップのものと同じものが使用されます。 - -`edit` コールバック関数の中では モーダルの view のうち `blocks` だけを渡すだけで簡単にステップ設定モーダルをオープンすることができる `configure()` というユーティリティ関数が利用できます。これは、必要な入力内容が揃うまで設定の保存を無効にする `submit_disabled` というオプションを `true` に設定します。 - -設定モーダルを開く処理に関するさらなる詳細は、[ドキュメント](https://api.slack.com/workflows/steps#handle_config_view)を参考にしてください。 - -```javascript -const ws = new WorkflowStep('add_task', { - edit: async ({ ack, step, configure }) => { - await ack(); - - const blocks = [ - { - type: 'input', - block_id: 'task_name_input', - element: { - type: 'plain_text_input', - action_id: 'name', - placeholder: { - type: 'plain_text', - text: 'Add a task name', - }, - }, - label: { - type: 'plain_text', - text: 'Task name', - }, - }, - { - type: 'input', - block_id: 'task_description_input', - element: { - type: 'plain_text_input', - action_id: 'description', - placeholder: { - type: 'plain_text', - text: 'Add a task description', - }, - }, - label: { - type: 'plain_text', - text: 'Task description', - }, - }, - ]; - - await configure({ blocks }); - }, - save: async ({ ack, step, update }) => {}, - execute: async ({ step, complete, fail }) => {}, -}); -``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/creating-steps.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/creating-steps.md deleted file mode 100644 index 600504501..000000000 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/creating-steps.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: ステップの定義 -lang: ja-jp -slug: /concepts/creating-steps ---- - -ワークフローステップを作るための手段として Bolt は `WorkflowStep` というクラスを提供しています。 - -新しい `WorkflowStep` インスタンスの生成には、そのステップの `callback_id` と設定オブジェクトを渡します。 - -設定オブジェクトには `edit`、`save`、`execute` という三つのプロパティがあります。これらのそれぞれは単一のコールバック関数、またはコールバック関数の配列である必要があります。すべてのコールバック関数は、ワークフローステップのイベントに関する情報を保持しする `step` オブジェクトにアクセスすることができます。 - -`WorkflowStep` インスタンスを生成したら、それを `app.step()` メソッドに渡します。これによって、Bolt アプリは対象のワークフローステップのイベントをリッスンしたり、設定オブジェクトが提供するコールバック関数を使ってイベントに応答したりすることができるようになります。 - - -```javascript -const { App, WorkflowStep } = require('@slack/bolt'); - -// いつも通り Bolt アプリを初期化 -const app = new App({ - signingSecret: process.env.SLACK_SIGNING_SECRET, - token: process.env.SLACK_BOT_TOKEN, -}); - -// WorkflowStep インスタンスを生成 -const ws = new WorkflowStep('add_task', { - edit: async ({ ack, step, configure }) => {}, - save: async ({ ack, step, update }) => {}, - execute: async ({ step, complete, fail }) => {}, -}); - -app.step(ws); -``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/executing-steps.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/executing-steps.md deleted file mode 100644 index 2bd6660bd..000000000 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/executing-steps.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: ステップの実行 -lang: ja-jp -slug: /concepts/executing-steps ---- - -ワークフローの利用者によって、アプリが提供するカスタムのワークフローステップが実行されるとき、アプリは[`workflow_step_execute`](https://api.slack.com/events/workflow_step_execute) というイベントを受信します。このイベントの受信時に `WorkflowStep` 設定オブジェクト内の `execute` コールバック関数が実行されます。 - -`save` コールバック関数で予め規定された `inputs` の情報を使って、ここでの処理は、サードパーティの API を呼び出したり、データベースに情報を保存したり、そのユーザーのホームタブを更新したり、`outputs` オブジェクトを構築することで後続のワークフローステップが利用できる情報を設定したりします。 - -`execute` コールバック関数内では、ステップの実行が成功であることを Slack 側に伝える `complete()` 関数、失敗であることを伝える `fail()` 関数のいずれかを呼び出す必要があります。 - -```javascript -const ws = new WorkflowStep('add_task', { - edit: async ({ ack, step, configure }) => {}, - save: async ({ ack, step, update }) => {}, - execute: async ({ step, complete, fail }) => { - const { inputs } = step; - - const outputs = { - taskName: inputs.taskName.value, - taskDescription: inputs.taskDescription.value, - }; - - // もし全て OK なら - await complete({ outputs }); - // 注意: processBeforeResponse: true を指定している場合 - // ここでは await complete() はおすすめしません。呼び出す API の応答が遅いためです。 - // これにより、3 秒以内に Slack のイベント API に応答することができなくなる場合があります。 - // 代わりに以下のようにすることができます: - // complete({ outputs }).then(() => { console.log('workflow step execution complete registered'); }); - - // もし何か問題が起きたら - // fail({ error: { message: "Just testing step failure!" } }).then(() => { console.log('workflow step execution failure registered'); }); - }, -}); -``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/saving-steps.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/saving-steps.md deleted file mode 100644 index 7eda9c243..000000000 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/saving-steps.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: ステップの設定の保存 -lang: ja-jp -slug: /concepts/saving-steps ---- - -ワークフローステップの設定モーダルが開いたら、アプリはワークフロー作成者がモーダルを送信するイベントである `view_submission` イベントを待ち受けます。このイベントを受信すると `WorkflowStep` 設定オブジェクト内の `save` コールバック関数が実行されます。 - -`save` コールバック関数の中では、以下の引数を渡してステップの設定を保存するための `update()` 関数を利用できます。 - -- `inputs` は、ワークフローステップ実行時にアプリが受け取ることを期待するデータの内容を表現するオブジェクトです -- `outputs` は、ステップの実行が正常に完了したとき、同一ワークフロー内の後続のステップに提供するデータの内容を表現するオブジェクトの配列です。 -- `step_name` は、デフォルトのステップ名を上書きするために使用します -- `step_image_url` は、デフォルトのステップのイメージ画像を上書きするために使用します - -これら引数をどのように構成するかの詳細は、[ドキュメント](https://api.slack.com/reference/workflows/workflow_step)を参考にしてください。 - -```javascript -const ws = new WorkflowStep('add_task', { - edit: async ({ ack, step, configure }) => {}, - save: async ({ ack, step, view, update }) => { - await ack(); - - const { values } = view.state; - const taskName = values.task_name_input.name; - const taskDescription = values.task_description_input.description; - - const inputs = { - taskName: { value: taskName.value }, - taskDescription: { value: taskDescription.value } - }; - - const outputs = [ - { - type: 'text', - name: 'taskName', - label: 'Task name', - }, - { - type: 'text', - name: 'taskDescription', - label: 'Task description', - } - ]; - - await update({ inputs, outputs }); - }, - execute: async ({ step, complete, fail }) => {}, -}); -``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/steps.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/steps.md deleted file mode 100644 index 405219353..000000000 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/steps/steps.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: ワークフローステップの概要 -lang: ja-jp -slug: /concepts/steps ---- - -(アプリによる)ワークフローステップ(Workflow Steps from Apps) は、[ワークフロービルダー](https://api.slack.com/workflows)におけるワークフローに組み込み可能なカスタムのワークフローステップを任意の Slack アプリが提供することを可能とします。 - -ワークフローステップは、三つの異なるユーザーイベントから構成されます: - -- ワークフロー作成者がワークフローにカスタムステップを追加・または編集する -- ワークフロー作成者がステップの設定を保存・更新する -- ワークフローの利用者がそのワークフローステップを実行する - -ワークフローステップを機能させるためには、これら三つのイベント全てを適切にハンドリングする必要があります。 - -ワークフローステップのさらなる詳細については [API ドキュメント](https://api.slack.com/workflows/steps)を参考にしてください。 \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/getting-started-http.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/getting-started-http.md deleted file mode 100644 index 6b4dfa8d3..000000000 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/tutorials/getting-started-http.md +++ /dev/null @@ -1,324 +0,0 @@ ---- -title: Bolt 入門ガイド (HTTP) -slug: getting-started-http -lang: ja-jp ---- - -# Bolt 入門ガイド (HTTP) - -このガイドでは、Bolt を使用して Slack アプリを起動し実行する方法について説明します。その過程で、新しい Slack アプリを作成し、ローカル環境を設定し、Slack ワークスペースからのメッセージをリッスンして応答するアプリを開発します。 - -このガイドが終わったら、あなたはこの⚡️[Getting Started app](https://github.com/slackapi/bolt-js-getting-started-app)を実行したり、修正したり、自分で作ったりすることができます。 - ---- - -### アプリを作成する {#create-an-app} -最初にやるべきこと: Bolt で開発を始める前に、 [Slack アプリを作成](https://api.slack.com/apps/new)します。 - -:::tip - -いつもの仕事のさまたげにならないように、別に開発用のワークスペースを使用することをおすすめします — [新しいワークスペースを無料で作成](https://slack.com/get-started#create)できます。 - -::: - -アプリ名を入力し (後で変更可能)、インストール先のワークスペースを選択したら、`Create App` ボタンをクリックすると、アプリの **Basic Information** ページが表示されます。 - -このページには、後で必要になる重要な認証情報 (**App Credentials** ヘッダーの下の `Signing Secret` など) に加えて、アプリケーションの概要が表示されます。 - -![Basic Information page](/img/basic-information-page.png "Basic Information page") - -ひと通り確認し、アプリのアイコンと説明を追加してから、アプリの設定 🔩 を始めましょう。 - ---- - -### トークンとアプリのインストール {#tokens-and-installing-apps} -Slack アプリは、[OAuth を使用して、Slack の API へのアクセスを管理](https://api.slack.com/docs/oauth)します。アプリがインストールされると、トークンを受け取ります。そのトークンを使って、アプリは API メソッドを呼び出すことができます。 - -Slack アプリで使用できるトークンには、ユーザートークン(`xoxp`)とボットトークン(`xoxb`)、アプリレベルトークン(`xapp`)の 3 種類があります。 -- [ユーザートークン](https://api.slack.com/authentication/token-types#user) を使用すると、アプリをインストールまたは認証したユーザーに成り代わって API メソッドを呼び出すことができます。1 つのワークスペースに複数のユーザートークンが存在する可能性があります。 -- [ボットトークン](https://api.slack.com/authentication/token-types#bot) はボットユーザーに関連づけられ、1 つのワークスペースでは最初に誰かがそのアプリをインストールした際に一度だけ発行されます。どのユーザーがインストールを実行しても、アプリが使用するボットトークンは同じになります。 _ほとんど_ のアプリで使用されるのは、ボットトークンです。 -- [アプリレベルトークン](https://api.slack.com/authentication/token-types#app) は、全ての組織(とその配下のワークスペースでの個々のユーザーによるインストール)を横断して、あなたのアプリを代理するものです。アプリレベルトークンは、アプリの WebSocket コネクションを確立するためによく使われます。 - -説明を簡潔にするために、このガイドではボットトークンを使用します。 - -1. 左側のサイドバーの **OAuth & Permissions** にアクセスして、**Bot Token Scopes** までスクロールします。そして、**Add an OAuth Scope** をクリックします。 - -2. とりあえずは、[`chat:write`](https://api.slack.com/scopes/chat:write) というスコープだけを追加してみましょう。これは、アプリにボットユーザがメンバーとして参加しているチャンネルへのメッセージの投稿を許可するスコープです。 - -3. ページ上部までスクロールして戻り、**Install App to Workspace** をクリックします。すると、開発用のワークスペースにこのアプリをインストールするための Slack の OAuth 確認画面へと誘導されます。 - -4. インストールを承認すると、**OAuth & Permissions** ページが表示され、**Bot User OAuth Access Token** を確認することができるはずです。 - -![OAuth Tokens](/img/bot-token.png "OAuth Tokens") - -:::tip - -トークンは、パスワードのように大切に扱い、[安全に保管](https://api.slack.com/docs/oauth-safety)してください。アプリではそのトークンを使用して、Slack ワークスペースからの情報を投稿および取得します。 - -::: - ---- - -### ローカルプロジェクトの設定 {#setting-up-your-project} -初期設定が完了したので、次は新しい Bolt プロジェクトを設定します。ここで、アプリのロジックを処理するコードを記述します。 - -プロジェクトをまだ作成していない場合は、新しいプロジェクトを作成しましょう。次のように、空のディレクトリを作成して、新しいプロジェクトを初期化します。 - -```shell -mkdir first-bolt-app -cd first-bolt-app -npm init -``` - -新しいプロジェクトを説明するための一連の質問が表示されます (特に問題がなければ、各プロンプトで Enter を押すと、デフォルトを受け入れることができます)。完了すると、ディレクトリ内に新しい `package.json` ファイルが作成されます。 - -Bolt パッケージを新しいプロジェクトにインストールする前に、アプリの設定時に生成されたボットトークンと signing secret (サイン認証) を保存しましょう。これらは環境変数として保存する必要があります。**バージョン管理では保存しない**でください。 - -1. **Basic Information ページから Signing Secret をコピー**して、新しい環境変数に保存します。次の例は Linux と macOS で動作します。ただし、[Windows でも同様のコマンドが利用可能](https://superuser.com/questions/212150/how-to-set-env-variable-in-windows-cmd-line/212153#212153)です。 -```shell -export SLACK_SIGNING_SECRET= -``` - -2. **OAuth & Permissions ページからボット (xoxb) トークンをコピー**し、それを別の環境変数に格納します。 -```shell -export SLACK_BOT_TOKEN=xoxb- -``` - -それでは、アプリを作成しましょう。次のコマンドを使用して、`@slack/bolt` パッケージをインストールし、 `package.json` 中で依存ファイルとして保存します。 - -```shell -npm install @slack/bolt -``` - -このディレクトリ内に `app.js` という名前の新しいファイルを作成し、以下のコードを追加します。 - -```javascript -const { App } = require('@slack/bolt'); - -// ボットトークンとソケットモードハンドラーを使ってアプリを初期化します -const app = new App({ - token: process.env.SLACK_BOT_TOKEN, - signingSecret: process.env.SLACK_SIGNING_SECRET -}); - -(async () => { - // アプリを起動します - await app.start(process.env.PORT || 3000); - - console.log('⚡️ Bolt app is running!'); -})(); -``` - -まず実行してみましょう。 `app.js` ファイルを保存してから、以下のコマンドラインで動かします。 - -```script -node app.js -``` - -アプリから、起動し実行中であることが通知されます🎉 - ---- - -### イベントの設定 (HTTP) {#setting-up-events-with-http} -アプリはボットとしてチームメンバーのように動作し、メッセージを投稿したり、絵文字リアクションを追加したりすることができます。 - -Slack ワークスペースで発生するイベント (メッセージが投稿されたときや、メッセージに対するリアクションが投稿されたときなど) をリッスンするには、[Events API を使用してイベントタイプに登録](https://api.slack.com/events-api)します。 - -アプリのイベントを有効にしましょう。 - -1. アプリのイベントを有効にするには、まずアプリ設定ページに戻ります ([アプリ管理ページ](https://api.slack.com/apps)でアプリをクリックします)。左側のサイドバーにある **Event Subscription** をクリックします。**Enable Events** のスイッチをオンにします。 - - -2. Request URLを追加します。Slackはイベントに対応するHTTP POSTリクエストをこの[Request URL](https://api.slack.com/apis/connections/events-api#the-events-api__subscribing-to-event-types__events-api-request-urls)エンドポイントに送信します。Boltは`/slack/events`のパスを使用して、すべての受信リクエスト(ショートカット、イベント、インタラクティビティのペイロードなど)をリッスンします。アプリの設定でRequest URLを設定する際には、`https:///slack/events`のように`/slack/events`を追加します。💡 - -> ローカル開発では、[ngrok](https://ngrok.com/)のようなプロキシサービスを使って公開 URL を作成し、リクエストを開発環境にトンネリングすることができます。このトンネリングの方法については、[ngrok のガイド](https://ngrok.com/docs#getting-started-expose)を参照してください。 - -最後に、聞きたいイベントをSlackに伝えましょう。**Event Subscriptions**の下にある、**Enable Events**というラベルの付いたスイッチを切り替えます。 - -イベントが発生すると、Slack は、そのイベントをトリガーしたユーザーやイベントが発生したチャンネルなど、イベントに関する情報をアプリに送信します。アプリが詳細を処理し、それに応じて応答することができます。 - -**Request URL** ボックスの **Enable Events** スイッチの下のフィールドにこの URL を貼り付けます。Bolt アプリが引き続き実行されている場合は、URL が検証されチェックマークが表示されます。 - -Request URL が検証されたら、**Subscribe to Bot Events** までスクロールします。メッセージに関するイベントが4つあります: -- `message.channels` あなたのアプリが追加されているパブリックチャンネルのメッセージをリッスン -- `message.groups` あなたのアプリが追加されている🔒プライベートチャンネルのメッセージをリッスン -- `message.im` あなたのアプリとユーザーのダイレクトメッセージをリッスン -- `message.mpim` あなたのアプリが追加されているグループ DM をリッスン - -もしボットに参加しているすべての場所で全てのメッセージイベントをリッスンさせたいなら、これら4つ全てのイベントを選んでください。選択したら、緑の **Save Changes** ボタンをクリックします。 - ---- - -### メッセージのリスニングと応答 {#listening-and-responding-to-a-message} -これで、アプリでいくつかのロジックを設定する準備が整いました。まずは `message()` メソッドを使用して、メッセージのリスナーをアタッチしましょう。 - -次の例では、あなたのアプリが追加されているチャンネルや DM で `hello` という単語を含むすべてのメッセージをリッスンし、 `Hey there @user!` と応答します。 - -```javascript -const { App } = require('@slack/bolt'); - -const app = new App({ - token: process.env.SLACK_BOT_TOKEN, - signingSecret: process.env.SLACK_SIGNING_SECRET -}); - -// "hello" を含むメッセージをリッスンします -app.message('hello', async ({ message, say }) => { - // イベントがトリガーされたチャンネルに say() でメッセージを送信します - await say(`Hey there <@${message.user}>!`); -}); - -(async () => { - // アプリを起動します - await app.start(process.env.PORT || 3000); - - console.log('⚡️ Bolt app is running!'); -})(); -``` - -アプリを再起動したら、ボットユーザーをチャンネル、 DM に追加し、 `hello` を含むメッセージを送信してみてください。アプリが応答したら成功です。 - -これは基本的な例ですが、ここから自分の好きなようにアプリをカスタマイズしていくことができます。さらにインタラクティブな動作を試すために、プレーンテキストではなくボタンを送信してみましょう。 - ---- - -### アクションの送信と応答 {#sending-and-responding-to-actions} - -ボタン、選択メニュー、日付ピッカー、モーダルなどの機能を使用するには、インタラクティブ性を有効にする必要があります。イベントと同様に、Slack の URL を指定してアクション ( 「ボタン・クリック」など) を送信する必要があります。 - -アプリ設定ページに戻り、左側の **Interactivity & Shortcuts** をクリックします。**Request URL** ボックスがもう 1 つあることがわかります。 - -:::tip - -デフォルトでは、Bolt はイベントに使用しているのと同じエンドポイントをインタラクティブコンポーネントに使用するように設定されているため、上記と同じリクエスト URL (この例では `https://8e8ec2d7.ngrok.io/slack/events`) を使用します。右下隅にある **Save Changes** ボタンを押してください。これでアプリのインタラクティブなコンポーネントを利用する設定が有効になりました! - -::: - -![Configuring a Request URL](/img/request-url-config.png "Configuring a Request URL") - -インタラクティブ機能を有効にすると、ショートカット、モーダル、インタラクティブコンポーネント(ボタン、セレクトメニュー、データピッカーなど)とのやり取りがイベントとしてアプリに送信されます。 - -それでは、アプリのコードに戻り、インタラクティブな処理を追加しましょう。この実装は以下の二つのステップで構成されます。 -- 最初に、アプリからボタンを含むメッセージを送信します。 -- 次に、ユーザーがボタンをクリックしたときの動作をアプリでリッスンし、応答します。 - -以下は、前のセクションで記述したアプリコードを、文字列だけでなく、ボタン付きのメッセージを送信するように変更したものです。 - -```javascript -const { App } = require('@slack/bolt'); - -const app = new App({ - token: process.env.SLACK_BOT_TOKEN, - signingSecret: process.env.SLACK_SIGNING_SECRET -}); - -// "hello" を含むメッセージをリッスンします -app.message('hello', async ({ message, say }) => { - // イベントがトリガーされたチャンネルに say() でメッセージを送信します - 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}>!` - }); -}); - -(async () => { - // アプリを起動します - await app.start(process.env.PORT || 3000); - - console.log('⚡️ Bolt app is running!'); -})(); -``` - -`say()` に格納されている値が、 `blocks` の配列を含むオブジェクトになりました。このブロックは Slack メッセージを構成するコンポーネントであり、テキストや画像、日付ピッカーなど、さまざまなタイプがあります。この例では、アプリは、ボタンを `accessory` として含むセクションブロックを使用して応答します。`blocks` を使っている場合、 `text` は通知やアクセシビリティのためのフォールバックとして使用されます。 - -このボタン `accessory` オブジェクトには、`action_id` が割り当てられています。これはボタンの一意の識別子として機能するため、アプリはどのアクションに応答するかを指定できます。 - -:::tip - -[Block Kit ビルダー](https://app.slack.com/block-kit-builder)を使うとインタラクティブメッセージを簡単にプロトタイプすることができます。ビルダーを使用すると、ユーザー (またはそのチームメンバー) はメッセージをモックアップして、対応する JSON を生成し、それをアプリに直接貼り付けることができます。 - -::: - -これで、アプリを再起動し、アプリが登録されているチャンネルで `hello` と入力すると、ボタン付きのメッセージが表示されます。ただしこのボタンをクリックしても、まだ何も起こりません。 - -ボタンがクリックされるとフォローアップメッセージを送信するハンドラーを追加してみましょう。 - -```javascript -const { App } = require('@slack/bolt'); - -const app = new App({ - token: process.env.SLACK_BOT_TOKEN, - signingSecret: process.env.SLACK_SIGNING_SECRET -}); - -// "hello" を含むメッセージをリッスンします -app.message('hello', async ({ message, say }) => { - // イベントがトリガーされたチャンネルに say() でメッセージを送信します - 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 }) => { - // アクションのリクエストを確認 - await ack(); - await say(`<@${body.user.id}> clicked the button`); -}); - -(async () => { - // アプリを起動します - await app.start(process.env.PORT || 3000); - - console.log('⚡️ Bolt app is running!'); -})(); -``` - -このように、`app.action()` を使うことで `button_click` という `action_id` のボタンアクションのリスナーを追加できるのです。アプリを再起動してボタンをクリックしてみましょう。すると、you clicked the button という新しいメッセージがアプリに表示されるはずです。 - ---- - -### 次のステップ {#next-steps} -これで最初の Bolt アプリが構築できました! 🎉 - -基本的なアプリの作成ができましたので、次回は是非もっといろいろな、 Bolt の機能を使ってアプリを作ってみましょう。下記のリンクを辿っていろいろアイデアを模索してみてください! - -* 基本的な概念 をお読みください。Bolt アプリからアクセスできるさまざまなメソッドと機能について学ぶことができます。 - -* ボットが[`events()` メソッド](/concepts/event-listening)でリッスンできるさまざまなイベントを確認しましょう。イベントはすべて[API サイト](https://api.slack.com/events)にリストされています。 - -* Bolt を使用すると、アプリにアタッチされているクライアントで [Web API メソッドを呼び出す](/concepts/web-api)ことができます。API サイトに [200 を超えるメソッド](https://api.slack.com/methods)を用意してあります。 - -* 異なるトークンの種類については、[APIサイト](https://api.slack.com/docs/token-types)を参照してください。アプリケーションが実行したいアクションに応じて、異なるトークンが必要になる場合があります。HTTPではなく[Socket Mode](/getting-started)を使用している場合は、`connections:write`スコープを持つ追加の(`xapp`)トークンが必要です。 \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-theme-classic/navbar.json b/docs/i18n/ja-jp/docusaurus-theme-classic/navbar.json index d9ffa7ec8..6d84ae7e9 100644 --- a/docs/i18n/ja-jp/docusaurus-theme-classic/navbar.json +++ b/docs/i18n/ja-jp/docusaurus-theme-classic/navbar.json @@ -54,5 +54,9 @@ "item.label.Slack Community": { "message": "Slack Community", "description": "Navbar item with label Slack Community" + }, + "logo.alt": { + "message": "Slack logo", + "description": "The alt text of navbar logo" } } diff --git a/docs/sidebars.js b/docs/sidebars.js index 15ae96e45..7ea9d6924 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -1,109 +1,109 @@ -/** - The sidebars can be generated from the filesystem, or explicitly defined here. - Create as many sidebars as you want. - */ - -// @ts-check - /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ const sidebars = { - // By default, Docusaurus generates a sidebar from the docs folder structure - // tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], - - // But you can create a sidebar manually sidebarJSBolt: [ { - type: 'doc', - id: 'index', // document ID - label: 'Bolt for JavaScript', // sidebar label - className: 'sidebar-title', + type: "doc", + id: "index", + label: "Bolt for JavaScript", + className: "sidebar-title", + }, + "getting-started", + { + type: "category", + label: "Slack API calls", + items: ["concepts/message-sending", "concepts/web-api"], + }, + { + type: "category", + label: "Events", + items: ["concepts/message-listening", "concepts/event-listening"], + }, + { + type: "category", + label: "App UI & Interactivity", + items: [ + "concepts/acknowledge", + "concepts/shortcuts", + "concepts/commands", + "concepts/actions", + "concepts/creating-modals", + "concepts/updating-pushing-views", + "concepts/view-submissions", + "concepts/select-menu-options", + "concepts/publishing-views", + ], + }, + "concepts/custom-steps", + { + type: "category", + label: "App Configuration", + items: [ + "concepts/socket-mode", + "concepts/error-handling", + "concepts/logging", + "concepts/custom-routes", + "concepts/deferring-initialization", + "concepts/receiver", + ], }, - 'getting-started', { - type: 'category', - label: 'Basic concepts', + type: "category", + label: "Middleware & Context", items: [ - 'basic/message-listening', - 'basic/message-sending', - 'basic/event-listening', - 'basic/web-api', - 'basic/action-listening', - 'basic/action-respond', - 'basic/acknowledge', - 'basic/shortcuts', - 'basic/commands', - 'basic/creating-modals', - 'basic/updating-pushing-views', - 'basic/view-submissions', - 'basic/publishing-views', - 'basic/custom-steps', - 'basic/options', - 'basic/authenticating-oauth', - 'basic/socket-mode', + "concepts/global-middleware", + "concepts/listener-middleware", + "concepts/context", ], }, { - type: 'category', - label: 'Advanced concepts', + type: "category", + label: "Authorization & Security", items: [ - 'advanced/error-handling', - 'advanced/authorization', - 'advanced/token-rotation', - 'advanced/conversation-store', - 'advanced/global-middleware', - 'advanced/listener-middleware', - 'advanced/context', - 'advanced/deferring-initialization', - 'advanced/logging', - 'advanced/custom-routes', - 'advanced/receiver', + "concepts/authenticating-oauth", + "concepts/authorization", + "concepts/token-rotation", ], }, { - type: 'category', - label: 'Deployments', - items: ['deployments/aws-lambda', 'deployments/heroku'], + type: "category", + label: "Deployments", + items: ["deployments/aws-lambda", "deployments/heroku"], }, { - type: 'category', - label: 'Steps from apps (Deprecated)', + type: "category", + label: "Migration Guides", items: [ - 'steps/steps', - 'steps/creating-steps', - 'steps/adding-editing-steps', - 'steps/saving-steps', - 'steps/executing-steps', + "migration/migration-v2", + "migration/migration-v3", + "migration/migration-v4", ], }, - { type: 'html', value: '
' }, { - type: 'category', - label: 'Tutorials', + type: "category", + label: "Legacy", items: [ - 'tutorial/getting-started-http', - 'tutorial/hubot-migration', - 'tutorial/migration-v2', - 'tutorial/migration-v3', - 'tutorial/migration-v4', + "legacy/hubot-migration", + "legacy/steps-from-apps", + "legacy/conversation-store", ], }, - { type: 'html', value: '
' }, - 'reference', - { type: 'html', value: '
' }, + { type: "html", value: "
" }, + "reference", + { type: "html", value: "
" }, { - type: 'link', - label: 'Release notes', - href: 'https://github.com/slackapi/bolt-js/releases', + type: "link", + label: "Release notes", + href: "https://github.com/slackapi/bolt-js/releases", }, { - type: 'link', - label: 'Code on GitHub', - href: 'https://github.com/SlackAPI/bolt-js', + type: "link", + label: "Code on GitHub", + href: "https://github.com/SlackAPI/bolt-js", }, { - type: 'link', - label: 'Contributors Guide', - href: 'https://github.com/SlackAPI/bolt-js/blob/main/.github/contributing.md', + type: "link", + label: "Contributors Guide", + href: "https://github.com/SlackAPI/bolt-js/blob/main/.github/contributing.md", }, ], }; diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index 45378d07b..c6cc91b1a 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -113,3 +113,9 @@ html[data-theme="dark"] .navbar-github-link::before { font-weight: bold; color: #000; } + +.tabs-container { + border: 2px solid var(--ifm-hr-background-color); /* Adjust the color and thickness as needed */ + border-radius: 5px; /* To give rounded corners */ + padding: 0.5em; /* To add spacing inside the tab */ +} From 4b6b25f44200781481c84aa8e42768c2b9cbe656 Mon Sep 17 00:00:00 2001 From: Alissa Renz Date: Tue, 29 Oct 2024 12:56:50 -0700 Subject: [PATCH 08/17] Add `title` to setSuggestedPrompts utility (#2308) --- docs/docusaurus.config.js | 9 +-- docs/sidebars.js | 132 ++++++++++++++++-------------------- src/Assistant.ts | 8 ++- test/unit/Assistant.spec.ts | 2 +- 4 files changed, 69 insertions(+), 82 deletions(-) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 14963051a..04a174bec 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -57,7 +57,7 @@ const config = { redirects: [ { to: '/getting-started', - from: ['/tutorial/getting-started','/tutorial/getting-started-http'], + from: ['/tutorial/getting-started', '/tutorial/getting-started-http'], }, { to: '/concepts/steps-from-apps', @@ -65,15 +65,12 @@ const config = { '/concepts/creating-steps', '/concepts/adding-editing-steps', '/concepts/saving-steps', - '/concepts/executing-steps' + '/concepts/executing-steps', ], }, { to: '/concepts/actions', - from: [ - '/concepts/action-listening', - '/concepts/action-responding' - ], + from: ['/concepts/action-listening', '/concepts/action-responding'], }, { to: '/', diff --git a/docs/sidebars.js b/docs/sidebars.js index 7ea9d6924..e5442a016 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -2,108 +2,92 @@ const sidebars = { sidebarJSBolt: [ { - type: "doc", - id: "index", - label: "Bolt for JavaScript", - className: "sidebar-title", + type: 'doc', + id: 'index', + label: 'Bolt for JavaScript', + className: 'sidebar-title', }, - "getting-started", + 'getting-started', { - type: "category", - label: "Slack API calls", - items: ["concepts/message-sending", "concepts/web-api"], + type: 'category', + label: 'Slack API calls', + items: ['concepts/message-sending', 'concepts/web-api'], }, { - type: "category", - label: "Events", - items: ["concepts/message-listening", "concepts/event-listening"], + type: 'category', + label: 'Events', + items: ['concepts/message-listening', 'concepts/event-listening'], }, { - type: "category", - label: "App UI & Interactivity", + type: 'category', + label: 'App UI & Interactivity', items: [ - "concepts/acknowledge", - "concepts/shortcuts", - "concepts/commands", - "concepts/actions", - "concepts/creating-modals", - "concepts/updating-pushing-views", - "concepts/view-submissions", - "concepts/select-menu-options", - "concepts/publishing-views", + 'concepts/acknowledge', + 'concepts/shortcuts', + 'concepts/commands', + 'concepts/actions', + 'concepts/creating-modals', + 'concepts/updating-pushing-views', + 'concepts/view-submissions', + 'concepts/select-menu-options', + 'concepts/publishing-views', ], }, - "concepts/custom-steps", + 'concepts/custom-steps', { - type: "category", - label: "App Configuration", + type: 'category', + label: 'App Configuration', items: [ - "concepts/socket-mode", - "concepts/error-handling", - "concepts/logging", - "concepts/custom-routes", - "concepts/deferring-initialization", - "concepts/receiver", + 'concepts/socket-mode', + 'concepts/error-handling', + 'concepts/logging', + 'concepts/custom-routes', + 'concepts/deferring-initialization', + 'concepts/receiver', ], }, { - type: "category", - label: "Middleware & Context", - items: [ - "concepts/global-middleware", - "concepts/listener-middleware", - "concepts/context", - ], + type: 'category', + label: 'Middleware & Context', + items: ['concepts/global-middleware', 'concepts/listener-middleware', 'concepts/context'], }, { - type: "category", - label: "Authorization & Security", - items: [ - "concepts/authenticating-oauth", - "concepts/authorization", - "concepts/token-rotation", - ], + type: 'category', + label: 'Authorization & Security', + items: ['concepts/authenticating-oauth', 'concepts/authorization', 'concepts/token-rotation'], }, { - type: "category", - label: "Deployments", - items: ["deployments/aws-lambda", "deployments/heroku"], + type: 'category', + label: 'Deployments', + items: ['deployments/aws-lambda', 'deployments/heroku'], }, { - type: "category", - label: "Migration Guides", - items: [ - "migration/migration-v2", - "migration/migration-v3", - "migration/migration-v4", - ], + type: 'category', + label: 'Migration Guides', + items: ['migration/migration-v2', 'migration/migration-v3', 'migration/migration-v4'], }, { - type: "category", - label: "Legacy", - items: [ - "legacy/hubot-migration", - "legacy/steps-from-apps", - "legacy/conversation-store", - ], + type: 'category', + label: 'Legacy', + items: ['legacy/hubot-migration', 'legacy/steps-from-apps', 'legacy/conversation-store'], }, - { type: "html", value: "
" }, - "reference", - { type: "html", value: "
" }, + { type: 'html', value: '
' }, + 'reference', + { type: 'html', value: '
' }, { - type: "link", - label: "Release notes", - href: "https://github.com/slackapi/bolt-js/releases", + type: 'link', + label: 'Release notes', + href: 'https://github.com/slackapi/bolt-js/releases', }, { - type: "link", - label: "Code on GitHub", - href: "https://github.com/SlackAPI/bolt-js", + type: 'link', + label: 'Code on GitHub', + href: 'https://github.com/SlackAPI/bolt-js', }, { - type: "link", - label: "Contributors Guide", - href: "https://github.com/SlackAPI/bolt-js/blob/main/.github/contributing.md", + type: 'link', + label: 'Contributors Guide', + href: 'https://github.com/SlackAPI/bolt-js/blob/main/.github/contributing.md', }, ], }; diff --git a/src/Assistant.ts b/src/Assistant.ts index ddcc44c27..14d817d19 100644 --- a/src/Assistant.ts +++ b/src/Assistant.ts @@ -45,11 +45,16 @@ type SetSuggestedPromptsFn = ( ) => Promise; interface SetSuggestedPromptsArguments { + /** @description Prompt suggestions that appear when opening assistant thread. */ prompts: [AssistantPrompt, ...AssistantPrompt[]]; + /** @description Title for the prompts. */ + title?: string; } interface AssistantPrompt { + /** @description Title of the prompt. */ title: string; + /** @description Message of the prompt. */ message: string; } @@ -345,11 +350,12 @@ function createSetSuggestedPrompts(args: AllAssistantMiddlewareArgs): SetSuggest const { channelId: channel_id, threadTs: thread_ts } = extractThreadInfo(payload); return (params: Parameters[0]) => { - const { prompts } = params; + const { prompts, title } = params; return client.assistant.threads.setSuggestedPrompts({ channel_id, thread_ts, prompts, + title, }); }; } diff --git a/test/unit/Assistant.spec.ts b/test/unit/Assistant.spec.ts index 61071f832..40dc4b24f 100644 --- a/test/unit/Assistant.spec.ts +++ b/test/unit/Assistant.spec.ts @@ -387,7 +387,7 @@ describe('Assistant class', () => { const { enrichAssistantArgs } = await importAssistant(); const threadStartedArgs = enrichAssistantArgs(mockThreadContextStore, mockThreadStartedArgs); - await threadStartedArgs.setSuggestedPrompts({ prompts: [{ title: '', message: '' }] }); + await threadStartedArgs.setSuggestedPrompts({ prompts: [{ title: '', message: '' }], title: '' }); sinon.assert.called(fakeClient.assistant.threads.setSuggestedPrompts); }); From 78e062839026369de72ca51c47fe6dc7fad7f51d Mon Sep 17 00:00:00 2001 From: Luke Russell <31357343+lukegalbraithrussell@users.noreply.github.com> Date: Wed, 30 Oct 2024 10:36:15 -0700 Subject: [PATCH 09/17] docs: general page cleanup (#2310) Co-authored-by: Michael Brooks --- docs/content/concepts/actions.md | 1 - docs/content/concepts/authorization.md | 6 +- docs/content/concepts/custom-routes.md | 9 +- docs/content/concepts/custom-steps.md | 14 +-- .../concepts/deferring-initialization.md | 2 +- docs/content/concepts/error-handling.md | 8 +- docs/content/concepts/listener-middleware.md | 2 +- docs/content/concepts/logging.md | 6 +- docs/content/concepts/message-sending.md | 8 +- docs/content/concepts/receiver.md | 2 +- docs/content/concepts/select-menu-options.md | 2 +- docs/content/concepts/shortcuts.md | 98 ++++++++--------- docs/content/concepts/socket-mode.md | 9 +- .../concepts/updating-pushing-views.md | 10 +- docs/content/concepts/view-submissions.md | 6 +- docs/content/concepts/web-api.md | 4 +- docs/content/deployments/aws-lambda.md | 56 +++++----- docs/content/deployments/heroku.md | 35 +++--- docs/content/getting-started.mdx | 7 +- docs/content/legacy/conversation-store.md | 4 +- docs/content/legacy/hubot-migration.md | 35 +++--- docs/content/legacy/steps-from-apps.md | 2 +- docs/content/migration/migration-v2.md | 26 ++--- docs/content/migration/migration-v3.md | 20 ++-- docs/content/migration/migration-v4.md | 26 ++--- docs/docusaurus.config.js | 5 +- .../current/concepts/actions.md | 6 +- .../current/concepts/authenticating-oauth.md | 8 +- .../current/concepts/custom-routes.md | 8 +- .../current/concepts/error-handling.md | 9 +- .../current/concepts/global-middleware.md | 6 +- .../current/concepts/listener-middleware.md | 6 +- .../current/concepts/logging.md | 9 +- .../current/concepts/message-listening.md | 2 - .../current/concepts/message-sending.md | 8 +- .../current/concepts/shortcuts.md | 101 ++++++++---------- .../current/concepts/socket-mode.md | 9 +- .../concepts/updating-pushing-views.md | 6 +- .../current/concepts/view-submissions.md | 4 +- .../current/concepts/web-api.md | 2 +- .../current/deployments/aws-lambda.md | 53 +++++---- .../current/deployments/heroku.md | 39 ++++--- .../current/getting-started.mdx | 18 ++-- .../current/legacy/hubot-migration.md | 69 ++++++++---- .../current/legacy/steps-from-apps.md | 2 +- .../current/migration/migration-v2.md | 22 ++-- .../current/migration/migration-v3.md | 17 ++- .../current/reference.md | 11 +- 48 files changed, 380 insertions(+), 438 deletions(-) diff --git a/docs/content/concepts/actions.md b/docs/content/concepts/actions.md index d64cfc780..65b98be2b 100644 --- a/docs/content/concepts/actions.md +++ b/docs/content/concepts/actions.md @@ -64,7 +64,6 @@ app.action('approve_button', async ({ ack, say }) => { }); ``` - ### Using the `respond()` utility Since `respond()` is a utility for calling the `response_url`, it behaves in the same way. You can pass a JSON object with a new message payload that will be published back to the source of the original interaction with optional properties like `response_type` (which has a value of `in_channel` or `ephemeral`), `replace_original`, and `delete_original`. diff --git a/docs/content/concepts/authorization.md b/docs/content/concepts/authorization.md index 56faea126..ce6c69b80 100644 --- a/docs/content/concepts/authorization.md +++ b/docs/content/concepts/authorization.md @@ -6,7 +6,11 @@ slug: /concepts/authorization Authorization is the process of deciding which Slack credentials (such as a bot token) should be available while processing a specific incoming request. -Custom apps installed on a single workspace can simply use the `token` option at the time of `App` initialization. However, when your app needs to handle several tokens, such as cases where it will be installed on multiple workspaces or needs access to more than one user token, the `authorize` option should be used instead. If you're using the [built-in OAuth support](/concepts/authenticating-oauth) authorization is handled by default, so you do not need to pass in an `authorize` option. +Custom apps installed on a single workspace can simply use the `token` option at the time of `App` initialization. However, when your app needs to handle several tokens, such as cases where it will be installed on multiple workspaces or needs access to more than one user token, the `authorize` option should be used instead. + +:::tip +If you're using the [built-in OAuth support](/concepts/authenticating-oauth) authorization is handled by default, so you do not need to pass in an `authorize` option. +::: The `authorize` option can be set to a function that takes an event source as its input, and should return a Promise for an object containing the authorized credentials. The source contains information about who and where the request is coming from by using properties like `teamId` (always available), `userId`, `conversationId`, and `enterpriseId`. diff --git a/docs/content/concepts/custom-routes.md b/docs/content/concepts/custom-routes.md index d4bc7595f..e776088e1 100644 --- a/docs/content/concepts/custom-routes.md +++ b/docs/content/concepts/custom-routes.md @@ -48,11 +48,7 @@ const app = new App({ })(); ``` -
- -Custom ExpressReceiver routes - - +## Custom ExpressReceiver routes Adding custom HTTP routes is quite straightforward when using Bolt’s built-in ExpressReceiver. Since `v2.1.0`, `ExpressReceiver` added a `router` property, which exposes the Express [Router](http://expressjs.com/en/4x/api.html#router) on which additional routes and middleware can be added. @@ -91,5 +87,4 @@ receiver.router.post('/secret-page', (req, res) => { await app.start(); console.log('⚡️ Bolt app started'); })(); -``` -
+``` \ No newline at end of file diff --git a/docs/content/concepts/custom-steps.md b/docs/content/concepts/custom-steps.md index f54c01cd1..084a958f7 100644 --- a/docs/content/concepts/custom-steps.md +++ b/docs/content/concepts/custom-steps.md @@ -29,10 +29,7 @@ app.function('sample_custom_step', async ({ inputs, complete, fail, logger }) => }); ``` -
- -Example app manifest definition - +### Example app manifest definition ```json ... @@ -60,8 +57,6 @@ Example app manifest definition } ``` -
- --- ## Listening to custom step interactivity events @@ -131,10 +126,7 @@ app.action('sample_button', async ({ ack, body, client, complete, fail, logger } }); ``` -
- -Example app manifest definition - +### Example app manifest definition ```json ... @@ -162,6 +154,4 @@ Example app manifest definition } ``` -
- Learn more about responding to interactivity, see the [Slack API documentation](https://api.slack.com/automation/functions/custom-bolt#interactivity). diff --git a/docs/content/concepts/deferring-initialization.md b/docs/content/concepts/deferring-initialization.md index 303eae4b9..fcc06a0c1 100644 --- a/docs/content/concepts/deferring-initialization.md +++ b/docs/content/concepts/deferring-initialization.md @@ -8,7 +8,7 @@ Bolt offers a way to defer full initialization via the `deferInitialization` opt :::info -If you call `start()` before `init()`, Bolt will raise an exception._ +If you call `start()` before `init()`, Bolt will raise an exception. ::: diff --git a/docs/content/concepts/error-handling.md b/docs/content/concepts/error-handling.md index 4cd94eaa7..653ebfbda 100644 --- a/docs/content/concepts/error-handling.md +++ b/docs/content/concepts/error-handling.md @@ -62,10 +62,7 @@ app.error(async (error) => { }); ``` -
- -Accessing more data in the error handler - +## Accessing more data in the error handler There may be cases where you need to log additional data from a request in the global error handler. Or you may simply wish to have access to the `logger` you've passed into Bolt. @@ -90,5 +87,4 @@ app.error(async ({ error, logger, context, body }) => { // Do something with the team's ID for debugging purposes } }); -``` -
+``` \ No newline at end of file diff --git a/docs/content/concepts/listener-middleware.md b/docs/content/concepts/listener-middleware.md index e7945449e..3040977e5 100644 --- a/docs/content/concepts/listener-middleware.md +++ b/docs/content/concepts/listener-middleware.md @@ -10,7 +10,7 @@ There’s a collection of [built-in listener middleware](/reference#built-in-lis But of course, you can write your own middleware for more custom functionality. While writing your own middleware, your function must call `await next()` to pass control to the next middleware, or `throw` to pass an error back up the previously-executed middleware chain. -As an example, let’s say your listener should only deal with messages from humans. You can write a listener middleware th +As an example, let’s say your listener should only deal with messages from humans. You can write a listener middleware that excludes any bot messages. ```javascript // Listener middleware that filters out messages with 'bot_message' subtype diff --git a/docs/content/concepts/logging.md b/docs/content/concepts/logging.md index 99291332c..515eafd26 100644 --- a/docs/content/concepts/logging.md +++ b/docs/content/concepts/logging.md @@ -18,10 +18,7 @@ const app = new App({ }); ``` -
- -Sending log output somewhere besides the console - +## Sending log output somewhere besides the console If you want to send logs to somewhere besides the console or want more control over the logger, you can implement a custom logger. A custom logger must implement specific methods (known as the `Logger` interface): @@ -57,4 +54,3 @@ const app = new App({ }, }); ``` -
diff --git a/docs/content/concepts/message-sending.md b/docs/content/concepts/message-sending.md index cbe4bc912..873ce1f11 100644 --- a/docs/content/concepts/message-sending.md +++ b/docs/content/concepts/message-sending.md @@ -15,10 +15,7 @@ app.message('knock knock', async ({ message, say }) => { }); ``` -
- -Sending a message with blocks - +## Sending a message with blocks `say()` accepts more complex message payloads to make it easy to add functionality and structure to your messages. @@ -48,5 +45,4 @@ app.event('reaction_added', async ({ event, say }) => { }); } }); -``` -
\ No newline at end of file +``` \ No newline at end of file diff --git a/docs/content/concepts/receiver.md b/docs/content/concepts/receiver.md index 3c1dcca47..ba99d8ad2 100644 --- a/docs/content/concepts/receiver.md +++ b/docs/content/concepts/receiver.md @@ -107,7 +107,7 @@ class SimpleReceiver { }) } - // This is a very simple implementation. Look at the ExpressReceiver source for more detail + // This is a simple implementation. Look at the ExpressReceiver source for more detail async requestHandler(req, res) { let ackCalled = false; // Assume parseBody function exists to parse incoming requests diff --git a/docs/content/concepts/select-menu-options.md b/docs/content/concepts/select-menu-options.md index 6589cd3d4..7acc2a27b 100644 --- a/docs/content/concepts/select-menu-options.md +++ b/docs/content/concepts/select-menu-options.md @@ -4,7 +4,7 @@ lang: en slug: /concepts/options --- -The `options()` method listens for incoming option request payloads from Slack. [Similar to `action()`](/concepts/actions), +The `options()` method listens for incoming option request payloads from Slack. Similar to the [`action()`](/concepts/actions) method, an `action_id` or constraints object is required. While it's recommended to use `action_id` for `external_select` menus, dialogs do not yet support Block Kit so you'll have to diff --git a/docs/content/concepts/shortcuts.md b/docs/content/concepts/shortcuts.md index 0c57d792e..3785065a3 100644 --- a/docs/content/concepts/shortcuts.md +++ b/docs/content/concepts/shortcuts.md @@ -76,59 +76,55 @@ app.shortcut('open_modal', async ({ shortcut, ack, client, logger }) => { }); ``` -
- - Listening to shortcuts using a constraint object - +## Listening to shortcuts using a constraint object - You can use a constraints object to listen to `callback_id` and `type` values. Constraints in the object can be of type string or RegExp object. +You can use a constraints object to listen to `callback_id` and `type` values. Constraints in the object can be of type string or RegExp object. - ```javascript - // Your middleware will only be called when the callback_id matches 'open_modal' AND the type matches 'message_action' - app.shortcut({ callback_id: 'open_modal', type: 'message_action' }, async ({ shortcut, ack, client, logger }) => { - try { - // Acknowledge shortcut request - await ack(); - - // Call the views.open method using one of the built-in WebClients - const result = await client.views.open({ - trigger_id: shortcut.trigger_id, - view: { - type: "modal", - title: { - type: "plain_text", - text: "My App" - }, - close: { - type: "plain_text", - text: "Close" +```javascript +// Your middleware will only be called when the callback_id matches 'open_modal' AND the type matches 'message_action' +app.shortcut({ callback_id: 'open_modal', type: 'message_action' }, async ({ shortcut, ack, client, logger }) => { + try { + // Acknowledge shortcut request + await ack(); + + // Call the views.open method using one of the built-in WebClients + const result = await client.views.open({ + trigger_id: shortcut.trigger_id, + view: { + type: "modal", + title: { + type: "plain_text", + text: "My App" + }, + close: { + type: "plain_text", + text: "Close" + }, + blocks: [ + { + type: "section", + text: { + type: "mrkdwn", + text: "About the simplest modal you could conceive of :smile:\n\nMaybe or ." + } }, - blocks: [ - { - type: "section", - text: { + { + type: "context", + elements: [ + { type: "mrkdwn", - text: "About the simplest modal you could conceive of :smile:\n\nMaybe or ." + text: "Psssst this modal was designed using " } - }, - { - type: "context", - elements: [ - { - type: "mrkdwn", - text: "Psssst this modal was designed using " - } - ] - } - ] - } - }); - - logger.info(result); - } - catch (error) { - logger.error(error); - } - }); - ``` -
\ No newline at end of file + ] + } + ] + } + }); + + logger.info(result); + } + catch (error) { + logger.error(error); + } +}); +``` diff --git a/docs/content/concepts/socket-mode.md b/docs/content/concepts/socket-mode.md index 2dc9e153c..a020723a9 100644 --- a/docs/content/concepts/socket-mode.md +++ b/docs/content/concepts/socket-mode.md @@ -23,10 +23,7 @@ const app = new App({ })(); ``` -
- -Custom SocketMode Receiver - +## Custom SocketMode Receiver You can define a custom `SocketModeReceiver` by importing it from `@slack/bolt`. @@ -53,6 +50,4 @@ const app = new App({ await app.start(); console.log('⚡️ Bolt app started'); })(); -``` - -
+``` \ No newline at end of file diff --git a/docs/content/concepts/updating-pushing-views.md b/docs/content/concepts/updating-pushing-views.md index 3ccf4f14a..3ba2a164b 100644 --- a/docs/content/concepts/updating-pushing-views.md +++ b/docs/content/concepts/updating-pushing-views.md @@ -4,15 +4,15 @@ lang: en slug: /concepts/updating-pushing-views --- -Modals contain a stack of views. When you call [`views.open`](https://api.slack.com/methods/views.open), you add the root view to the modal. After the initial call, you can dynamically update a view by calling [`views.update`](https://api.slack.com/methods/views.update), or stack a new view on top of the root view by calling [`views.push`](https://api.slack.com/methods/views.push). +Modals contain a stack of views. When you call the [`views.open`](https://api.slack.com/methods/views.open) method, you add the root view to the modal. After the initial call, you can dynamically update a view by calling the [`views.update`](https://api.slack.com/methods/views.update) method, or stack a new view on top of the root view by calling the [`views.push`](https://api.slack.com/methods/views.push) method. -**`views.update`** +## The `views.update` method -To update a view, you can use the built-in client to call `views.update` with the `view_id` that was generated when you opened the view, and a new `view` including the updated `blocks` array. If you're updating the view when a user interacts with an element inside of an existing view, the `view_id` will be available in the `body` of the request. +To update a view, you can use the built-in client to call the `views.update` method with the `view_id` parameter that was generated when you opened the view, and a new `view` object including the updated `blocks` array. If you're updating the view when a user interacts with an element inside of an existing view, the `view_id` parameter will be available in the `body` of the request. -**`views.push`** +## The `views.push` method -To push a new view onto the view stack, you can use the built-in client to call `views.push` with a valid `trigger_id` a new [view payload](https://api.slack.com/reference/block-kit/views). The arguments for `views.push` is the same as [opening modals](/concepts/creating-modals). After you open a modal, you may only push two additional views onto the view stack. +To push a new view onto the view stack, you can use the built-in client to call the `views.push` method by passing a valid `trigger_id` parameter and a new [view payload](https://api.slack.com/reference/block-kit/views). The arguments for the `views.push` method is the same as [`views.open`](/concepts/creating-modals). After you open a modal, you may only push two additional views onto the view stack. Learn more about updating and pushing views in our [API documentation](https://api.slack.com/surfaces/modals/using#modifying) diff --git a/docs/content/concepts/view-submissions.md b/docs/content/concepts/view-submissions.md index 1a51d34c3..6ca0a9ed9 100644 --- a/docs/content/concepts/view-submissions.md +++ b/docs/content/concepts/view-submissions.md @@ -10,7 +10,7 @@ Slack will send a `view_submission` request when a user submits a view. To recei If the `notify_on_close` field of a view has been set to `true`, Slack will also send a `view_closed` request if a user clicks the close button. See the section on **Handling views on close** for more detail. To listen to either a `view_submission` request or `view_closed` request, you can use the built-in `view()` method. -`view()` requires a `callback_id` of type `string` or `RegExp` or a constraint object with properties `type` and `callback_id`. +The `view()` method requires a `callback_id` of type `string` or `RegExp` or a constraint object with properties `type` and `callback_id`. --- @@ -35,9 +35,11 @@ Read more about view submissions in our [API documentation](https://api.slack.co ## Handling views on close -💡 When listening for `view_closed` requests, you must pass an object containing `type: 'view_closed'` and the view `callback_id`. See below for an example of this: +When listening for `view_closed` requests, you must pass an object containing `type: 'view_closed'` and the view `callback_id`. See below for an example of this. +:::tip See the [API documentation](https://api.slack.com/surfaces/modals/using#modal_cancellations) for more information about `view_closed`. +::: #### Handle a `view_closed` request diff --git a/docs/content/concepts/web-api.md b/docs/content/concepts/web-api.md index 0e1b3cdbe..667378aef 100644 --- a/docs/content/concepts/web-api.md +++ b/docs/content/concepts/web-api.md @@ -8,9 +8,9 @@ You can call any [Web API method](https://api.slack.com/methods) using the [`Web Your Bolt app also has a top-level `app.client` which you can manually pass the `token` parameter. If the incoming request is not authorized or you're calling a method from outside of a listener, use the top-level `app.client`. -Calling one of the [`WebClient`](https://tools.slack.dev/node-slack-sdk/web-api)'s methods will return a Promise containing the response from Slack, regardless of whether you use the top-level or listener's client. +Calling one of the [`WebClient`](https://tools.slack.dev/node-slack-sdk/web-api) methods will return a Promise containing the response from Slack, regardless of whether you use the top-level or listener's client. -Since the introduction of [org wide app installations](https://api.slack.com/enterprise/apps), [some web-api methods](https://api.slack.com/enterprise/apps/changes-apis#methods) now require `team_id` to indicate which workspace to act on. Bolt for JavaScript will attempt to infer the `team_id` based on incoming payloads and pass it along to `client`. This is handy for existing applications looking to add support for org wide installations and not spend time updating all of these web-api calls. +Since the introduction of [org wide app installations](https://api.slack.com/enterprise/apps), [some web-api methods](https://api.slack.com/enterprise/apps/changes-apis#methods) now require a `team_id` parameter to indicate which workspace to act on. Bolt for JavaScript will attempt to infer the `team_id` value based on incoming payloads and pass it along to `client`. This is handy for existing applications looking to add support for org wide installations and not spend time updating all of these web-api calls. ```javascript // Unix Epoch time for September 30, 2019 11:59:59 PM diff --git a/docs/content/deployments/aws-lambda.md b/docs/content/deployments/aws-lambda.md index 0a5e0012b..ec56b6a70 100644 --- a/docs/content/deployments/aws-lambda.md +++ b/docs/content/deployments/aws-lambda.md @@ -19,7 +19,7 @@ Skip this section if you have already [configured a profile](https://docs.aws.am ::: -**1. Sign up for an AWS account** +### 1. Sign up for an AWS account If you don't already have an account, you should [sign up for AWS](https://aws.amazon.com/) and follow the on-screen instructions. @@ -29,25 +29,25 @@ You may be asked for payment information during the sign up. Don't worry, this g ::: -**2. Create an AWS access key** +### 2. Create an AWS access key Next, you'll need programmatic access to your AWS account to deploy onto Lambda. In the world of AWS, this requires an **Access Key ID** and **Secret Access Key**. We recommend watching this short, step-by-step video to 🍿 [create an IAM user and download the access keys](https://www.youtube.com/watch?v=KngM5bfpttA). -:::tip - - **Do you already have an IAM user?** Follow the official AWS guide to [create access keys for existing IAM users](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds). +:::tip[Do you already have an IAM user?] + +Follow the official AWS guide to [create access keys for existing IAM users](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds). ::: -**3. Install the AWS CLI** +### 3. Install the AWS CLI The AWS tools are available as a Command Line Interface (CLI) and can be [installed on macOS, Windows, or Linux](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html). On macOS, you can install the AWS CLI by [downloading the latest package installer](https://awscli.amazonaws.com/AWSCLIV2.pkg). -**4. Configure an AWS profile** +### 4. Configure an AWS profile You can use the AWS CLI to configure a profile that stores your access key pair on your local machine. This profile is used by the CLI and other tools to access AWS. @@ -75,8 +75,6 @@ That wraps up configuring your local machine to access AWS. 👏 Next, let's do The [Serverless Framework](https://serverless.com/) includes tools that let you easily configure, debug, and deploy your app to AWS Lambda. -**1. Install the Serverless Framework CLI** - The Serverless tools are available as a Command Line Interface (CLI) and can be installed on macOS, Windows, or Linux. Check out the [Serverless Getting Started documentation](https://www.serverless.com/framework/docs/getting-started/) for instructions on how to install. Once the installation is complete, test the Serverless CLI by displaying the commands available to you: @@ -109,7 +107,7 @@ Now that you have an app, let's prepare it for AWS Lambda and the Serverless Fra ## Prepare the app {#prepare-the-app} -**1. Prepare the app for AWS Lambda** +### 1. Prepare the app for AWS Lambda By default, our Bolt Getting Started app sample is configured to use SocketMode. Let's update the setup in `app.js` to have our app listen for HTTP requests instead. @@ -172,7 +170,7 @@ module.exports.handler = async (event, context, callback) => { When you're done, your app should look similar to the ⚡️[Deploying to AWS Lambda app](https://github.com/slackapi/bolt-js/tree/main/examples/deploy-aws-lambda/app.js). -**2. Add a serverless.yml** +### 2. Add a serverless.yml Serverless Framework projects use a `serverless.yml` file to configure and deploy apps. @@ -206,7 +204,7 @@ You can [learn how to export Slack environment variables](/getting-started#setti ::: -**3. Install Serverless Offline** +### 3. Install Serverless Offline To make local development a breeze, we'll use the `serverless-offline` module to emulate a deployed function. @@ -224,7 +222,7 @@ Congratulations, you've just prepared your Bolt app for AWS Lambda and Serverles Now that your app is configured to respond to an AWS Lambda function, we'll set up your environment to run the app locally. -**1. Start your local servers** +### 1. Start your local servers First, use the `serverless offline` command to start your app and listen to AWS Lambda function events: @@ -250,7 +248,7 @@ ngrok http 3000 ::: -**2. Update your Request URL** +### 2. Update your Request URL Next, visit your [Slack app's settings](https://api.slack.com/apps) to update your **Request URL** to use the ngrok web address. @@ -264,18 +262,21 @@ Second, select **Event Subscriptions** from the side and update the **Request UR ![Event Subscriptions page](/img/event-subscriptions-page.png "Event Subscriptions page") -**3. Test your Slack app** +### 3. Test your Slack app -Now you can test your Slack app by inviting your app to a channel then saying “hello” (lower-case). Just like in the [Getting Started guide](/getting-started, your app should respond back: +Now you can test your Slack app by inviting your app to a channel then saying “hello” (lower-case). Just like in the [Getting Started guide](/getting-started), your app should respond back: -> 👩‍💻 hello
+``` +> 👩‍💻 hello +``` + +``` > 🤖 Hey there @Jane! +``` If you don’t receive a response, check your **Request URL** and try again. -:::info - -**How does this work?** +:::info[How does this work?] The ngrok and Serverless commands are configured on the same port (default: 3000). When a Slack event is sent to your **Request URL**, it's received on your local machine by ngrok. The request is then forwarded to Serverless Offline, which emulates an AWS Lambda function event and triggers your Bolt app's receiver. 🛫🛬 Phew, what a trip! @@ -289,7 +290,7 @@ In the previous section of this tutorial, you ran your app locally and tested it You can use the Serverless Framework tools to provision, package, and deploy your app onto AWS Lambda. After your app is deployed, you'll need to update your app's request URL to say "hello" to your app. ✨ -**1. Deploy the app to AWS Lambda** +### 1. Deploy the app to AWS Lambda Now, deploy your app to AWS Lambda with the following command: @@ -304,7 +305,7 @@ serverless deploy After your app is deployed, you'll be given an **endpoint** which you'll use as your app's **Request URL**. The **endpoint** should end in `/slack/events`. Go ahead and copy this **endpoint** to use in the next section. -**2. Update your Slack app's settings** +### 2. Update your Slack app's settings Now we need to use your AWS Lambda **endpoint** as your **Request URL**, which is where Slack will send events and actions. With your endpoint copied, navigate to your [Slack app's configuration](https://api.slack.com/apps) to update your app's **Request URLs**. @@ -317,16 +318,21 @@ Second, select **Event Subscriptions** from the side and update the **Request UR ![Event Subscriptions page](/img/event-subscriptions-page.png "Event Subscriptions page") -**3. Test your Slack app** +### 3. Test your Slack app Your app is now deployed and Slack is updated, so let's try it out! Just like the [running the app locally](#run-the-app-locally) section, open a Slack channel that your app is in and say "hello". You app should once again respond with a greeting: -> 👩‍💻 hello
+``` +> 👩‍💻 hello +``` + +``` > 🤖 Hey there @Jane! +``` -**4. Deploy an update** +### 4. Deploy an update As you continue to build your Slack app, you'll need to deploy the updates. Let's get a feel for this by updating your app to respond to a "goodbye" message. diff --git a/docs/content/deployments/heroku.md b/docs/content/deployments/heroku.md index 7593fd2cc..b399f9f67 100644 --- a/docs/content/deployments/heroku.md +++ b/docs/content/deployments/heroku.md @@ -1,20 +1,17 @@ --- -title: Heroku Platform +title: Deploying to Heroku lang: en --- -# Deploying to Heroku +This guide will walk you through preparing and deploying a Slack app using Bolt for JavaScript and the [Heroku platform](https://heroku.com/). Along the way, we’ll download a Bolt Slack app, prepare it for Heroku, and deploy it. + +When you’re finished, you’ll have this ⚡️[Deploying to Heroku app](https://github.com/slackapi/bolt-js/tree/main/examples/deploy-heroku) to run, modify, and make your own. :::warning Using Heroku dynos to complete this tutorial counts towards your usage. [Delete your app](https://devcenter.heroku.com/articles/heroku-cli-commands#heroku-apps-destroy) as soon as you are done to control costs. - ::: - -This guide will walk you through preparing and deploying a Slack app using Bolt for JavaScript and the [Heroku platform](https://heroku.com/). Along the way, we’ll download a Bolt Slack app, prepare it for Heroku, and deploy it. - - -When you’re finished, you’ll have this ⚡️[Deploying to Heroku app](https://github.com/slackapi/bolt-js/tree/main/examples/deploy-heroku) to run, modify, and make your own. +::: --- @@ -40,7 +37,7 @@ Now that you have an app, let's prepare it for Heroku. Heroku is a flexible platform that requires some configuration to host your app. In this section, we'll update your Bolt app to support Heroku. -**1. Use a Git repository** +### 1. Use a Git repository :::info @@ -50,7 +47,7 @@ Skip this step if you used `git clone` in the previous section because you alrea Before you can deploy your app to Heroku, you'll need a Git repository. If you aren't already using Git, you'll need to [install Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) and [create a Git repository](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository). -**2. Add a `Procfile`** +### Add a `Procfile` Every Heroku app uses a special file called `Procfile` that tells Heroku how to start your app. The contents of the file will depend on whether or not you are using Socket Mode. @@ -87,7 +84,7 @@ Are you following this guide with an existing Bolt app? If so, please review the Now we can set up the Heroku tools on your local machine. These tools will help you manage, deploy, and debug your app on Heroku's platform. -**1. Install the Heroku CLI** +### 1. Install the Heroku CLI The Heroku tools are available as a Command Line Interface (CLI). Go ahead and [install the Heroku CLI for macOS, Windows, or Linux](https://devcenter.heroku.com/articles/getting-started-with-nodejs#set-up). On macOS, you can run the command: @@ -107,7 +104,7 @@ If the `heroku` command is not found, refresh your path by opening a new termina ::: -**2. Log into the Heroku CLI** +### 2. Log into the Heroku CLI The Heroku CLI connects your local machine with your Heroku account. [Sign up for a free Heroku account](https://heroku.com) and then log into the Heroku CLI with the following command: @@ -120,7 +117,7 @@ If you're behind a firewall, you may need to [set the proxy environment variable ::: -**3. Confirm you're logged into the Heroku CLI** +### 3. Confirm you're logged into the Heroku CLI Check that you're logged in by displaying the account currently connected to your Heroku CLI: @@ -144,7 +141,7 @@ Eligible students can apply for platform credits through the [Heroku for GitHub ::: -**1. Create an app on Heroku** +### 1. Create an app on Heroku Create an app on Heroku with a unique name: @@ -172,7 +169,7 @@ After your app is created, you'll be given some information that we'll use in th - Web address is `https://sharp-rain-871.herokuapp.com/` - Empty Git remote is `https://git.heroku.com/sharp-rain-871.git` -**2. Confirm Heroku Git remote** +### 2. Confirm Heroku Git remote The Heroku CLI automatically adds a Git remote called `heroku` to your local repository. You can list your Git remotes to confirm `heroku` exists: @@ -182,7 +179,7 @@ git remote -v # heroku https://git.heroku.com/sharp-rain-871.git (push) ``` -**3. Set environment variables on Heroku** +### 3. Set environment variables on Heroku Now you'll need to add your Slack app credentials to your Heroku app: @@ -205,7 +202,7 @@ Now that we have prepared your local app and created a Heroku app, the next step To deploy the app, we're going to push your local code to Heroku, update your Slack app's settings, and say "hello" to your Heroku app. ✨ -**1. Deploy the app to Heroku** +### 1. Deploy the app to Heroku When deploying an app to Heroku, you'll typically use the `git push` command. This will push your code from your local repository to your `heroku` remote repository. @@ -227,7 +224,7 @@ Finally, we need to start a web server instance using the Heroku CLI: heroku ps:scale web=1 ``` -**2. Update your Slack app's settings** +### 2. Update your Slack app's settings Now we need to use your Heroku web address as your **Request URL**, which is where Slack will send events and actions. @@ -263,7 +260,7 @@ Heroku Eco Dyno apps sleep when inactive. 💤 If your verification fails, pleas ::: -**3. Test your Slack app** +### 3. Test your Slack app Your app is now deployed and Slack is updated, so let's try it out! diff --git a/docs/content/getting-started.mdx b/docs/content/getting-started.mdx index af9bfa0a7..e07b47c33 100644 --- a/docs/content/getting-started.mdx +++ b/docs/content/getting-started.mdx @@ -141,18 +141,18 @@ import TabItem from '@theme/TabItem'; -1. Head to your app's configuration page (click on the app [from your app management page](https://api.slack.com/apps)). Navigate to **Socket Mode** on the left side menu and toggle to enable. +1. Head to your app's configuration page (click on the app [from your app settings page](https://api.slack.com/apps)). Navigate to **Socket Mode** on the left side menu and toggle to enable. 2. Go to **Basic Information** and scroll down under the App Token section and click **Generate Token and Scopes** to generate an app token. Add the `connections:write` scope to this token and save the generated `xapp` token, we'll use that in just a moment. -Finally, it's time to tell Slack what events we'd like to listen for. Under **Event Subscriptions**, toggle the switch labeled **Enable Events**. +3. Finally, it's time to tell Slack what events we'd like to listen for. Under **Event Subscriptions**, toggle the switch labeled **Enable Events**. When an event occurs, Slack will send your app information about the event, like the user that triggered it and the channel it occurred in. Your app will process the details and can respond accordingly. -1. Go back to your app configuration page (click on the app from your [app management page](https://api.slack.com/apps)). Click **Event Subscriptions** on the left sidebar. Toggle the switch labeled **Enable Events**. +1. Go back to your app configuration page (click on the app from your [app settings page](https://api.slack.com/apps)). Click **Event Subscriptions** on the left sidebar. Toggle the switch labeled **Enable Events**. 2. Add your Request URL. Slack will send HTTP POST requests corresponding to events to this [Request URL](https://api.slack.com/apis/connections/events-api#the-events-api__subscribing-to-event-types__events-api-request-urls) endpoint. Bolt uses the `/slack/events` path to listen to all incoming requests (whether shortcuts, events, or interactivity payloads). When configuring your Request URL within your app configuration, you'll append `/slack/events`, e.g. `https:///slack/events`. 💡 @@ -162,7 +162,6 @@ For local development, you can use a proxy service like [ngrok](https://ngrok.co ::: - diff --git a/docs/content/legacy/conversation-store.md b/docs/content/legacy/conversation-store.md index 6c67bdb25..3a260fd53 100644 --- a/docs/content/legacy/conversation-store.md +++ b/docs/content/legacy/conversation-store.md @@ -4,7 +4,9 @@ lang: en slug: /concepts/conversation-store --- -Bolt for JavaScript includes support for a store, which sets and retrieves state related to a conversation. Conversation stores have two methods: +Bolt for JavaScript includes support for a store, which sets and retrieves state related to a conversation. + +Conversation stores have two methods: * `set()` modifies conversation state. `set()` requires a `conversationId` of type string, `value` of any type, and an optional `expiresAt` of type number. `set()` returns a `Promise`. * `get()` fetches conversation state from the store. `get()` requires a `conversationId` of type string and returns a Promise with the conversation’s state. diff --git a/docs/content/legacy/hubot-migration.md b/docs/content/legacy/hubot-migration.md index 2aa2a1c33..d29c40ad6 100644 --- a/docs/content/legacy/hubot-migration.md +++ b/docs/content/legacy/hubot-migration.md @@ -1,5 +1,6 @@ --- title: Migrating apps from Hubot to Bolt for JavaScript +sidebar_label: Hubot app migration slug: /tutorial/hubot-migration lang: en --- @@ -10,7 +11,7 @@ If you already have an [app with a bot user](https://api.slack.com/bot-users#get --- -### Setting the stage {#setting-the-stage} +## Setting the stage {#setting-the-stage} When translating a Hubot app to Bolt for JavaScript, it’s good to know how each are working behind the scenes. Slack’s Hubot adapter is built to interface with the [RTM API](https://api.slack.com/rtm), which uses a WebSocket-based connection that sends a stream of workspace events to your Hubot app. The RTM API is not recommended for most use cases since it doesn’t include support for newer platform features and it can become very resource-intensive, particularly if the app is installed on multiple or large Slack teams. The default Bolt for JavaScript receiver is built to support the [Events API](https://api.slack.com/events-api), which uses HTTP-based event subscriptions to send JSON payloads to your Bolt app. The Events API includes newer events that aren’t on RTM and is more granular and scalable. It’s recommended for most use cases, though one reason your app may be stuck using the RTM API could be that the server you’re hosting your app from has a firewall that only allows outgoing requests and not incoming ones. @@ -20,12 +21,10 @@ There are a few other differences you may want to consider before creating a Bol - Bolt for JavaScript doesn’t have support for external scripts. If your Hubot app uses external scripts that are necessary to your app’s functionality or deployment, you probably want to stay with Hubot for now. If you aren’t sure whether your app has any external scripts, you can check the `external-scripts.json` file. As we continue to invest in Bolt for JavaScript, we are thinking about the future and how to make development and deployment of Slack apps easier. If there’s a valuable external script that your app uses, we’d love to hear what it is [in the dedicated GitHub issue](https://github.com/slackapi/bolt-js/issues/119). - Hubot apps are written in Coffeescript, which transpiles into JavaScript. We decided to write Bolt in Typescript to give access to rich type information. Bolt apps can be developed using Typescript or JavaScript. The [example script](https://github.com/slackapi/bolt-js/blob/master/examples/hubot-example/script.js) shows you how your Coffeescript may translate to JavaScript. If your app is more than a few simple scripts, it may be worth looking into projects like [Decaffeinate](https://github.com/decaffeinate/decaffeinate) to convert your CoffeeScript to JavaScript. ---- - -### Configuring your bot {#configuring-your-bot} -If you have access to an existing Slack app with a bot user, you can [jump ahead to the next section](#configure-what-your-bot-will-hear). If you aren’t sure, go to your [App Management page](https://api.slack.com/apps) and check whether your Hubot app is there. If it is, you can use the credentials from that app ([go ahead and skip to the next section](#configure-what-your-bot-will-hear)). Otherwise, we’ll walk you through creating a Slack app. +## Configuring your bot {#configuring-your-bot} +If you have access to an existing Slack app with a bot user, you can [jump ahead to the next section](#configure-what-your-bot-will-hear). If you aren’t sure, go to your [app settings page](https://api.slack.com/apps) and check whether your Hubot app is there. If it is, you can use the credentials from that app ([go ahead and skip to the next section](#configure-what-your-bot-will-hear)). Otherwise, we’ll walk you through creating a Slack app. -#### Create a Slack app +### Create a Slack app The first thing you’ll want to do is [create a Slack app](https://api.slack.com/apps/new). @@ -41,12 +40,12 @@ This page contains an overview of your app in addition to important credentials Look around, add an app icon and description, and then let’s start configuring your app 🔩 -#### Add a bot user +### Add a bot user On Slack, Hubot apps employ bot users which are designed to interact with users in conversation. To add a bot user to your new app, click **Bot Users** on the left sidebar and then **Add A Bot User**. Give it a display name and username, then click **Add Bot User**. There’s more information about what the different fields are [on our API site](https://api.slack.com/bot-users#creating-bot-user). -### Configure what your bot will hear {#configure-what-your-bot-will-hear} +## Configure what your bot will hear {#configure-what-your-bot-will-hear} The [Events API](https://api.slack.com/bot-users#app-mentions-response) is a bot's equivalent of eyes and ears. It gives a bot a way to react to posted messages, changes to channels, and other activities that happen in Slack. :::info @@ -55,7 +54,7 @@ Before you configure your bot’s events, you’ll need a public URL. If you’v ::: -#### Listening for messages +### Listening for messages All Hubot apps can listen to messages by default, so we need to configure your bot user to do the same. After walking through [setting up events](/getting-started#setting-up-events), your Request URL should be verified. Scroll down to **Subscribe to Bot Events**. There are four events related to messages: `message.channels` (listens for messages in public channels), `message.groups` (listens for messages in private channels), `message.im` (listens for messages in the App Home/DM space), and `message.mpim` (listens for messages in multi-person DMs). @@ -64,7 +63,7 @@ If you only want your bot to listen to messages in channels, you can listen to ` After you’ve added the kinds of message events you want your bot to listen to, click **Save Changes**. -#### Listening for other events +### Listening for other events Your Hubot app may have responded to other events depending on what functionality you used. Look through your script and identify any places where your script uses `react`, `respond`, or `presenceChange`: - If your app uses `respond`, subscribe to the `app_mention` event. This listens for any time your bot user is mentioned. - If your app uses `react`, subscribe to the `reaction_added` event. This listens for any time a reaction is added to a message in channels your bot user is in. @@ -78,7 +77,7 @@ An added benefit to Bolt is you can listen to any [Events API event](https://api After you added events that correspond to your app’s functionality, click **Save Changes**. -### Changes to script interfaces {#changes-to-script-interfaces} +## Changes to script interfaces {#changes-to-script-interfaces} Bolt’s interface was designed to conform to the Slack API language as much as possible, while Hubot was designed with more generalized language to abstract multiple services. While the interfaces are similar, converting a Hubot script to a Bolt for JavaScript one still requires some code changes. Bolt for JavaScript doesn’t use `res` or expose the raw request from Slack. Instead, you can use the payload body from `payload`, or common functionality like sending a message using `say()`. @@ -89,14 +88,14 @@ To make it easier, we’ve created a sample script on GitHub that [showcases Hub ::: -#### Listening to patterns using `message()` +### Listening to patterns using `message()` Hubot scripts use `hear()` listen to messages with a matching pattern. Bolt for JavaScript instead uses `message()` and accepts a `string` or `RegExp` for the pattern. 👨‍💻👩‍💻 Anywhere where you use `hear()` in your code, change it to use `message()` [Read more about listening to messages](/concepts/message-listening). -#### Responding with a message using `say()` and `respond()` +### Responding with a message using `say()` and `respond()` Hubot scripts use `send()` to send a message to the same conversation and `reply()` to send a message to the same conversation with an @-mention to the user that sent the original message. Bolt for JavaScript uses `await say()` in place of `send()`, or `await respond()` to use the `response_url` to send a reply. To add an @-mention to the beginning of your reply, you can use the user ID found in the `context` object. For example, for a message event you could use `await say('<@${message.user}> Hello :wave:')` @@ -107,7 +106,7 @@ The arguments for Hubot’s `send()` and Bolt for JavaScript's `say()` are mostl [Read more about responding to messages](/concepts/message-sending). -#### `respond` and `react` +### `respond` and `react` In the previous section, you should have subscribed your app to the `app_mention` event if your Hubot script uses `respond()`, and `reaction_added` if you uses `react()`. @@ -117,7 +116,7 @@ Bolt for JavaScript uses a method called `event()` that allows you to listen to [Read more about listening to events](/concepts/event-listening). -### Using Web API methods with Bolt for JavaScript {#using-web-api-methods-with-bolt-for-javascript} +## Using Web API methods with Bolt for JavaScript {#using-web-api-methods-with-bolt-for-javascript} In Hubot, you needed to import the `WebClient` package from `@slack/client`. Bolt for JavaScript imports a `WebClient` instance for you by default, and exposes it as the `client` argument available on all listeners. To use the built-in `WebClient`, you’ll need to pass the token used to instantiate your app or the token associated with the team your request is coming from. This is found on the `context` object passed in to your listener functions. For example, to add a reaction to a message, you’d use: @@ -142,7 +141,7 @@ app.message('react', async ({ message, context, client, logger }) => { [Read more about using the Web API with Bolt](/concepts/web-api). -### Using middleware with Bolt for JavaScript {#using-middleware-with-bolt-for-javascript} +## Using middleware with Bolt for JavaScript {#using-middleware-with-bolt-for-javascript} Hubot has three kinds of middleware: receive (runs before any listeners are called), listener (runs for every matching listener), and response (runs for every response sent). Bolt for JavaScript only has two kinds of middleware — global and listener: @@ -155,7 +154,7 @@ To migrate your existing middleware functions, it’s evident that Hubot’s rec If your middleware needs to perform post-processing of an event, you can call `await next()` and any code after will be processed after the downstream middleware has been called. -### Migrating the brain to the conversation store {#migrating-the-brain-to-the-conversation-store} +## Migrating the brain to the conversation store {#migrating-the-brain-to-the-conversation-store} Hubot has an in-memory store called the brain. This enables a Hubot script to `get` and `set` basic pieces of data. Bolt for JavaScript uses a conversation store, which is a global middleware with a `get()`/`set()` interface. The default, built-in conversation store uses an in-memory store similar to Hubot, with the ability to set an expiration time in milliseconds. There are two ways to get and set conversation state: @@ -166,7 +165,7 @@ If there is more than one instance of your app running, the built-in conversatio [Read more about conversation stores](/concepts/conversation-store). -### Next steps {#next-steps} +## Next steps {#next-steps} If you’ve made it this far, it means you’ve likely converted your Hubot app into a Bolt for JavaScript app! ✨⚡ Now that you have your flashy new Bolt for JavaScript app, you can explore how to power it up: diff --git a/docs/content/legacy/steps-from-apps.md b/docs/content/legacy/steps-from-apps.md index 659786c2d..3d3803220 100644 --- a/docs/content/legacy/steps-from-apps.md +++ b/docs/content/legacy/steps-from-apps.md @@ -1,7 +1,7 @@ --- title: Steps from Apps lang: en -slug: /concepts/steps-from-apps +slug: /legacy/steps-from-apps --- :::danger diff --git a/docs/content/migration/migration-v2.md b/docs/content/migration/migration-v2.md index f7b5b2dff..f2737ce28 100644 --- a/docs/content/migration/migration-v2.md +++ b/docs/content/migration/migration-v2.md @@ -4,17 +4,15 @@ slug: /tutorial/migration-v2 lang: en --- -This guide will walk you through the process of updating your app from using `@slack/bolt@1.x` to `@slack/bolt@2.x`. There are a few changes you'll need to make but for most apps, these changes can be applied in 5 - 15 minutes. - -:::info +End of life for `@slack/bolt@1.x` was **April 30th, 2021**. Development has been fully stopped for `@slack/bolt@1.x` and all remaining open issues and pull requests have been closed. -Make sure to checkout our [support schedule](#slackbolt1x-support-schedule) for `@slack/bolt@1.x` if you don't plan on upgrading right away* +This guide will walk you through the process of updating your app from using `@slack/bolt@1.x` to `@slack/bolt@2.x`. There are a few changes you'll need to make but for most apps, these changes can be applied in 5 - 15 minutes. -::: +That being said, End of life for `@slack/bolt@2.x` was **May 31st, 2021**. After following this guide, you'll then want to follow the guide for [Migrating to V3](/tutorial/migration-v3). --- -### Upgrading your listeners to `async` {#upgrading-your-listeners-to-async} +## Upgrading your listeners to `async` {#upgrading-your-listeners-to-async} Listeners in your app should updated to `async` functions and `say()`, `respond()`, and `ack()` should be prefaced with `await`. @@ -36,8 +34,7 @@ app.action('some-action-id', async ({action, ack, say}) => { }) ``` - -### Error handling {#error-handling} +## Error handling {#error-handling} The recent changes in Bolt for JavaScript V2 have improved our ability to catch errors and filter them to the global error handler. It is still recommended to manage errors in the listeners themselves instead of letting them propagate to the global handler when possible. @@ -55,7 +52,7 @@ app.action('some-action-id', async ({action, ack, say, logger}) => { }) ``` -#### Handling errors with the global error handler +### Handling errors with the global error handler ```javascript app.error(async (error) => { @@ -69,8 +66,7 @@ Other error related changes include: - When your listener doesn’t call `ack` within the 3 second time limit, we log the failure instead of throwing an error. - If multiple errors occur when processing multiple listeners for a single event, Bolt for JavaScript will return a wrapper error with a `code` property of `ErrorCode.MultipleListenerError` and an `originals` property that contains an array of the individual errors. - -### Message shortcuts {#message-shortcuts} +## Message shortcuts {#message-shortcuts} [Message shortcuts](https://api.slack.com/interactivity/shortcuts/using#message_shortcuts) (previously referred to as message actions) now use the `shortcut()` method instead of the `action()` method. @@ -92,7 +88,7 @@ app.shortcut('message-action-callback', async ({shortcut, ack, context}) => { }) ``` -### Upgrading middleware {#upgrading-middleware} +## Upgrading middleware {#upgrading-middleware} If you wrote a custom middleware, adjust your function to `async` and update `next()` to `await next()`. If your middleware does some post processing, instead of passing a function to `next()`, you can now run it after `await next()`. @@ -121,10 +117,6 @@ async function noBotMessages({ message, next }) { } ``` -### @slack/bolt@1.x support schedule {#slackbolt1x-support-schedule} - -`@slack/bolt@1.x` will be deprecated on **June 30th, 2020**. We plan on continuing to implement bug fixes and will also consider back-porting new features on a case by case basis up until then. Once `@slack/bolt@1.x` has been deprecated, we will only implement **critical bug fixes** until the official end of life date and close non critical issues and pull requests. End of life is slated for **April 30th, 2021**. At this time, development will fully stop for `@slack/bolt@1.x` and all remaining open issues and pull requests will be closed. - -### Minimum TypeScript version {#minimum-typescript-version} +## Minimum TypeScript version {#minimum-typescript-version} `@slack/bolt@2.x` requires a minimum TypeScript version of 3.7. diff --git a/docs/content/migration/migration-v3.md b/docs/content/migration/migration-v3.md index b453984a2..df46040db 100644 --- a/docs/content/migration/migration-v3.md +++ b/docs/content/migration/migration-v3.md @@ -4,17 +4,13 @@ slug: /tutorial/migration-v3 lang: en --- -This guide will walk you through the process of updating your app from using `@slack/bolt@2.x` to `@slack/bolt@3.x`. There are a few changes you'll need to make but for most apps, these changes can be applied in 5 - 15 minutes. - -:::info - -Make sure to checkout our [support schedule](#slackbolt2x-support-schedule) for `@slack/bolt@2.x` if you don't plan on upgrading right away* +End of life for `@slack/bolt@2.x` was **May 31st, 2021**. Development has been fully stopped for `@slack/bolt@2.x` and all remaining open issues and pull requests have been closed. -::: +This guide will walk you through the process of updating your app from using `@slack/bolt@2.x` to `@slack/bolt@3.x`. There are a few changes you'll need to make but for most apps, these changes can be applied in 5 - 15 minutes. --- -### Org wide app installation changes to Installation Store & orgAuthorize {#org-wide-app-installation-changes-to-installationstore--orgauthorize} +## Org wide app installation changes to Installation Store & orgAuthorize {#org-wide-app-installation-changes-to-installationstore--orgauthorize} In [Bolt for JavaScript 2.5.0](https://github.com/slackapi/bolt-js/releases/tag/%40slack%2Fbolt%402.5.0), we introduced support for [org wide app installations](https://api.slack.com/enterprise/apps). To add support to your applications, two new methods were introduced to the Installation Store used during OAuth, `fetchOrgInstallation` & `storeOrgInstallation`. With `@slack/bolt@3.x`, we have dropped support for these two new methods for a simpler interface and to be better aligned with Bolt for Python and Bolt for Java. See the code samples below for the recommended changes to migrate. @@ -99,18 +95,14 @@ const authorizeFn = async ({ teamId, enterpriseId, isEnterpriseInstall}) => { } ``` -### HTTP Receiver as default {#http-receiver-as-default} +## HTTP Receiver as default {#http-receiver-as-default} In `@slack/bolt@3.x`, we have introduced a new default [`HTTPReceiver`](https://github.com/slackapi/bolt-js/issues/670) which replaces the previous default `ExpressReceiver`. This will allow Bolt for JavaScript apps to easily work with other popular web frameworks (Hapi.js, Koa, etc). `ExpressReceiver` is still being shipped with Bolt for JavaScript and `HTTPReceiver` will not provide all the same functionality. One use case that isn't supported by `HTTPReceiver` is creating custom routes (ex: create a route to do a health check). For these use cases, we recommend continuing to use `ExpressReceiver` by importing the class, and creating your own instance of it, and passing this instance into the constructor of `App`. See [our documentation on adding custom http routes](/concepts/custom-routes) for an example. -### @slack/bolt@2.x support schedule {#slackbolt2x-support-schedule} - -`@slack/bolt@2.x` will be deprecated on **January 12th, 2021**. We will only implement **critical bug fixes** until the official end of life date and close non critical issues and pull requests, which is slated for **May 31st, 2021**. At this time, development will fully stop for `@slack/bolt@2.x` and all remaining open issues and pull requests will be closed. - -### Minimum Node version {#minimum-node-version} +## Minimum Node version {#minimum-node-version} `@slack/bolt@3.x` requires a minimum Node version of `12.13.0` and minimum npm version of `6.12.0` . -### Minimum TypeScript version {#minimum-typescript-version} +## Minimum TypeScript version {#minimum-typescript-version} `@slack/bolt@3.x` requires a minimum TypeScript version of `4.1`. diff --git a/docs/content/migration/migration-v4.md b/docs/content/migration/migration-v4.md index cadc5233d..94b799705 100644 --- a/docs/content/migration/migration-v4.md +++ b/docs/content/migration/migration-v4.md @@ -26,13 +26,13 @@ This guide will walk you through the process of updating your app from using `@s - 🚳 [Steps From Apps related types, methods and constants were marked as deprecated](#sfa-deprecation). - 📦 [The `@slack/web-api` package leveraged within bolt-js is now exported under the `webApi` namespace](#web-api-export). -## Details +--- -### ⬆️ Minimum Node version {#minimum-node-version} +## ⬆️ Minimum Node version {#minimum-node-version} `@slack/bolt@4.x` requires a minimum Node version of `18` and minimum npm version of `8.6.0` . -### 🚥 Changes to middleware argument types {#middleware-arg-types} +## 🚥 Changes to middleware argument types {#middleware-arg-types} This change primarily applies to TypeScript users. @@ -52,21 +52,21 @@ type SomeMiddlewareArgs = { With the above, now when a message payload is wrapped in middleware arguments, it will contain an appropriate `message` property, whereas a non-message payload will be intersected with `unknown` - effectively a type "noop." No more e.g. `say: undefined` or `message: undefined` to deal with! -### 🌐 `@slack/web-api` v7 upgrade {#web-api-v7} +## 🌐 `@slack/web-api` v7 upgrade {#web-api-v7} All bolt handlers are [provided a convenience `client` argument](../concepts/web-api) that developers can use to make API requests to [Slack's public HTTP APIs][methods]. This `client` is powered by [the `@slack/web-api` package][web-api]. In bolt v4, `web-api` has been upgraded from v6 to v7. More APIs! Better argument type safety! And a whole slew of other changes, too. Many of these changes won't affect JavaScript application builders, but if you are building a bolt app using TypeScript, you may see some compilation issues. Head over to [the `@slack/web-api` v6 -> v7 migration guide](https://github.com/slackapi/node-slack-sdk/wiki/Migration-Guide-for-web%E2%80%90api-v7) to get the details on what changed and how to migrate to v7. -### 🔌 `@slack/socket-mode` v2 upgrade {#socket-mode-v2} +## 🔌 `@slack/socket-mode` v2 upgrade {#socket-mode-v2} While the breaking changes from this upgrade should be shielded from most bolt-js users, if you are using [the `SocketModeReceiver` or setting `socketMode: true`](../concepts/socket-mode) _and_ attach custom code to how the `SocketModeReceiver` operates, we suggest you read through [the `@slack/socket-mode` v1 -> v2 migration guide](https://github.com/slackapi/node-slack-sdk/wiki/Migration-Guide-for-socket%E2%80%90mode-2.0), just in case. -### 🚅 `express` v5 upgrade {#express-v5} +## 🚅 `express` v5 upgrade {#express-v5} For those building bolt-js apps using the `ExpressReceiver`, the packaged `express` version has been upgraded to v5. Best to check [the list of breaking changes in `express` v5](https://github.com/expressjs/express/blob/5.x/History.md#500--2024-09-10) and keep tabs on [express#5944](https://github.com/expressjs/express/issues/5944), which tracks the creation of an `express` v4 -> v5 migration guide. -### 🍽️ `@slack/types` exported as a named `types` export {#types-named-export} +## 🍽️ `@slack/types` exported as a named `types` export {#types-named-export} We are slowly moving more core Slack domain object types and interfaces into [the utility package `@slack/types`][types]. For example, recently we shuffled [Slack Events API payloads](https://api.slack.com/events) from bolt-js over to `@slack/types`. Similar moves will continue as we improve bolt-js. Ideally, we'd like for everyone - ourselves as Slack employees but of course you as well, dear developer - to leverage these types when modeling Slack domain objects. @@ -78,7 +78,7 @@ import { App, type types } from '@slack/bolt'; // Now you can get references to e.g. `types.BotMessageEvent` ``` -### 🧘 `SocketModeFunctions` class disassembled {#socketmodefunctions} +## 🧘 `SocketModeFunctions` class disassembled {#socketmodefunctions} If you previously imported the `SocketModeFunctions` class, you likely only did so to get a reference to the single static method available on this class: [`defaultProcessEventErrorHandler`](https://github.com/slackapi/bolt-js/blob/cd662ed540aa40b5cf20b4d5c21b0008db8ed427/src/receivers/SocketModeFunctions.ts#L13). Instead, you can now directly import the named `defaultProcessEventErrorHandler` export instead: @@ -92,7 +92,7 @@ SocketModeFunctions.defaultProcessEventErrorHandler import { defaultProcessEventHandler } from '@slack/bolt'; ``` -### 🏭 Built-in middleware changes {#built-in-middleware-changes} +## 🏭 Built-in middleware changes {#built-in-middleware-changes} Two [built-in middlewares](../reference#built-in-middleware-functions), `ignoreSelf` and `directMention`, previously needed to be invoked as a function in order to _return_ a middleware. These two built-in middlewares were not parameterized in the sense that they should just be used directly; as a result, you no longer should invoke them and instead pass them directly. @@ -112,7 +112,7 @@ app.message(directMention, async (args) => { }); ``` -### 🌩️ `AwsEvent` interface changes {#awsevent-changes} +## 🌩️ `AwsEvent` interface changes {#awsevent-changes} For users of the `AwsLambdaReceiver` and TypeScript, [we previously modeled, rather simplistically, the AWS event payloads](https://github.com/slackapi/bolt-js/blob/cd662ed540aa40b5cf20b4d5c21b0008db8ed427/src/receivers/AwsLambdaReceiver.ts#L11-L24): liberal use of `any` and in certain cases, incorrect property types altogether. We've now improved these to be more accurate and to take into account the two versions of API Gateway payloads that AWS supports (v1 and v2). Details for these changes are available in [#2277](https://github.com/slackapi/bolt-js/pull/2277). @@ -131,17 +131,17 @@ if ('path' in awsEvent) { this.logger.info(`No request handler matched the request: ${path}`); ``` -### 🧹 Removed deprecations {#removed-deprecations} +## 🧹 Removed deprecations {#removed-deprecations} - The deprecated type `KnownKeys` was removed. Admittedly, it wasn't very useful: `export type KnownKeys<_T> = never;` - The deprecated types `VerifyOptions` and `OptionsRequest` were removed. - The deprecated methods `extractRetryNum`, `extractRetryReason`, `defaultRenderHtmlForInstallPath`, `renderHtmlForInstallPath` and `verify` were removed. -### 🚳 Steps From Apps related deprecations {#sfa-deprecation} +## 🚳 Steps From Apps related deprecations {#sfa-deprecation} A variety of methods, constants and types related to Steps From Apps were deprecated and will be removed in bolt-js v5. -### 📦 `@slack/web-api` exported as `webApi` {#web-api-export} +## 📦 `@slack/web-api` exported as `webApi` {#web-api-export} To help application developers keep versions of various `@slack/*` dependencies in sync with those used by bolt-js, `@slack/web-api` is now exported from bolt-js under the `webApi` export. Unless applications have specific version needs from the `@slack/web-api` package, apps should be able to import `web-api` from bolt instead: diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 04a174bec..7be0d2e44 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -8,7 +8,7 @@ import { themes as prismThemes } from 'prism-react-renderer'; /** @type {import('@docusaurus/types').Config} */ const config = { - title: 'Slack Developer Tools', + title: 'Bolt for JavaScript', tagline: 'Official frameworks, libraries, and SDKs for Slack developers', favicon: 'img/favicon.ico', @@ -60,8 +60,9 @@ const config = { from: ['/tutorial/getting-started', '/tutorial/getting-started-http'], }, { - to: '/concepts/steps-from-apps', + to: '/legacy/steps-from-apps', from: [ + '/concepts/steps', '/concepts/creating-steps', '/concepts/adding-editing-steps', '/concepts/saving-steps', diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/actions.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/actions.md index 510ac555f..756f88b42 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/actions.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/actions.md @@ -12,7 +12,11 @@ Bolt アプリは `action` メソッドを用いて、ボタンのクリック すべての `action()` の例で `ack()` が使用されていることに注目してください。Slack からリクエストを受信したことを確認するために、アクションリスナー内で `ack()` 関数を呼び出す必要があります。これについては、「[リクエストの確認](/concepts/acknowledge)」 セクションで説明しています。 -*注: Bolt 2.x からメッセージショートカット(以前はメッセージアクションと呼ばれていました)は `action()` ではなく `shortcut()` メソッドを使用するようになりました。この変更については [2.x マイグレーションガイド](/tutorial/migration-v2)を参照してください。* +:::info + +Bolt 2.x からメッセージショートカット(以前はメッセージアクションと呼ばれていました)は `action()` ではなく `shortcut()` メソッドを使用するようになりました。この変更については [2.x マイグレーションガイド](/tutorial/migration-v2)を参照してください。 + +::: `block_actions` ペイロードの詳細については、[こちら](https://api.slack.com/reference/interaction-payloads) をご覧ください。リスナー内からビューの完全なペイロードにアクセスするには、コールバック関数内で `body` 引数を参照します。 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/authenticating-oauth.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/authenticating-oauth.md index f17fa03e7..25f06b8cb 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/authenticating-oauth.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/authenticating-oauth.md @@ -170,10 +170,7 @@ const app = new App({ }); ``` -
- -OAuth デフォルト設定をカスタマイズ - +## OAuth デフォルト設定をカスタマイズ `installerOptions` を使って OAuth モジュールのデフォルト設定を上書きすることができます。このカスタマイズされた設定は `App` の初期化時に渡します。以下の情報を変更可能です: @@ -237,5 +234,4 @@ const app = new App({ }, } }); -``` -
+``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/custom-routes.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/custom-routes.md index fbb559711..d42fb0420 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/custom-routes.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/custom-routes.md @@ -48,10 +48,7 @@ const app = new App({ })(); ``` -
- -カスタム ExpressReceiver ルート - +## カスタム ExpressReceiver ルート Bolt の組み込みの `ExpressReceiver` を使っているなら、カスタムの HTTP ルートを追加するのはとても簡単です。`v2.1.0` から `ExpressReceiver` には `router` というプロパティが追加されています。これは、さらにルートを追加できるように `App` 内部で保持している Express の [Router](http://expressjs.com/en/4x/api.html#router) を public にしたものです。 @@ -88,5 +85,4 @@ receiver.router.post('/secret-page', (req, res) => { await app.start(); console.log('⚡️ Bolt app started'); })(); -``` -
\ No newline at end of file +``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/error-handling.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/error-handling.md index 090c6795d..5d5159c4e 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/error-handling.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/error-handling.md @@ -54,10 +54,7 @@ app.error(async (error) => { }); ``` -
- -エラーハンドラーでのさらなるデータの参照 - +## エラーハンドラーでのさらなるデータの参照 グローバルエラーハンドラーの中で、リクエストからのデータをログ出力したい場合もあるでしょう。あるいは単に Bolt に設定した `logger` を利用したい場合もあるでしょう。 @@ -83,6 +80,4 @@ app.error(async ({ error, logger, context, body }) => { // デバッグのために teamId を使ってなんらかの処理 } }); -``` - -
+``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/global-middleware.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/global-middleware.md index 1e3189e7b..465964423 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/global-middleware.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/global-middleware.md @@ -10,7 +10,11 @@ slug: /concepts/global-middleware たとえば、アプリが、対応する内部認証サービス (SSO プロバイダ、LDAP など) で識別されたユーザーにのみ応答する必要があるとします。この場合、グローバルミドルウェアを使用して認証サービス内のユーザーレコードを検索し、ユーザーが見つからない場合はエラーとなるように定義するのがよいでしょう。 -*注: Bolt 2.x からグローバルミドルウェアが `async` 関数をサポートしました!この変更については [2.x マイグレーションガイド](/tutorial/migration-v2)を参照してください。* +:::info + +Bolt 2.x からグローバルミドルウェアが `async` 関数をサポートしました!この変更については [2.x マイグレーションガイド](/tutorial/migration-v2)を参照してください。 + +::: ```javascript // Acme ID情報管理プロバイダ上のユーザからの着信リクエストと紐つけた認証ミドルウェア diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/listener-middleware.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/listener-middleware.md index 96d556b6b..74b90a494 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/listener-middleware.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/listener-middleware.md @@ -12,7 +12,11 @@ slug: /concepts/listener-middleware 例として、リスナーが人(ボットではないユーザー)からのメッセージのみを扱うケースを考えてみましょう。このためには、全てのボットメッセージを除外するリスナーミドルウェアを実装します。 -*注: Bolt 2.x からミドルウェアが `async` 関数をサポートしました!この変更については [2.x マイグレーションガイド](/tutorial/migration-v2)を参照してください。* +:::info + +Bolt 2.x からミドルウェアが `async` 関数をサポートしました!この変更については [2.x マイグレーションガイド](/tutorial/migration-v2)を参照してください。 + +::: ```javascript // 'bot_message' サブタイプを持つメッセージをフィルタリングするリスナーミドルウェア diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/logging.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/logging.md index c1307d5da..137c53cdd 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/logging.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/logging.md @@ -18,10 +18,7 @@ const app = new App({ }); ``` -
- -コンソール以外へのログ出力の送信 - +## コンソール以外へのログ出力の送信 ログの送信先をコンソール以外に設定したり、よりロガーを細かくコントロールしたい場合は、カスタムロガーを実装します。カスタムロガーは、以下のメソッド (`Logger` インターフェイスに定義されているもの) を実装する必要があります。 @@ -56,6 +53,4 @@ const app = new App({ setName: (name) => { }, }, }); -``` - -
\ No newline at end of file +``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-listening.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-listening.md index b03033f37..907b5b52c 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-listening.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-listening.md @@ -6,7 +6,6 @@ slug: /concepts/message-listening [アプリが受信可能な](https://api.slack.com/messaging/retrieving#permissions)メッセージをリッスンするには、`message` 型でないイベントを除外する `message()` メソッドを使用します。`message()` リスナーは `event('message')` と等価の機能を提供します。 - `message()` は、`string` 型か `RegExp` 型の、指定パターンに一致しないメッセージを除外する `pattern` パラメーター(指定は必須ではありません)を受け付けます。 ```javascript @@ -39,7 +38,6 @@ app.message(/^(hi|hello|hey).*/, async ({ context, say }) => { ## メッセージのサブタイプのフィルタリング - イベントのサブタイプをフィルタリングしたい場合、組み込みの `subtype()` ミドルウェアを使用できます。 `message_changed` や `message_replied` のような一般的なメッセージサブタイプの情報は、[メッセージイベントのドキュメント](https://api.slack.com/events/message#message_subtypes)を参照してください。 ```javascript diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-sending.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-sending.md index 5ccef4f28..a4b17b889 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-sending.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/message-sending.md @@ -15,10 +15,7 @@ app.message('knock knock', async ({ message, say }) => { }); ``` -
- -ブロックを用いたメッセージの送信 - +## ブロックを用いたメッセージの送信 `say()` は、より複雑なメッセージペイロードを受け付けるので、メッセージに機能やリッチな構造を与えることが容易です。 @@ -48,5 +45,4 @@ app.event('reaction_added', async ({ event, say }) => { }); } }); -``` -
\ No newline at end of file +``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/shortcuts.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/shortcuts.md index c440feb28..61a1bb6b7 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/shortcuts.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/shortcuts.md @@ -68,64 +68,57 @@ app.shortcut('open_modal', async ({ shortcut, ack, context, logger }) => { }); ``` -
- - 制約付きオブジェクトを使用したショートカットのリスニング - +## 制約付きオブジェクトを使用したショートカットのリスニング - 制約付きオブジェクトを使って `callback_id` や `type` によるリスニングができます。オブジェクト内の制約は文字列型または RegExp オブジェクトを使用できます。 +制約付きオブジェクトを使って `callback_id` や `type` によるリスニングができます。オブジェクト内の制約は文字列型または RegExp オブジェクトを使用できます。 - - - ```javascript - // callback_id が 'open_modal' と一致し type が 'message_action' と一致する場合のみミドルウェアが呼び出される - app.shortcut({ callback_id: 'open_modal', type: 'message_action' }, async ({ shortcut, ack, context, client, logger }) => { - try { - // ショートカットリクエストの確認 - await ack(); +```javascript +// callback_id が 'open_modal' と一致し type が 'message_action' と一致する場合のみミドルウェアが呼び出される +app.shortcut({ callback_id: 'open_modal', type: 'message_action' }, async ({ shortcut, ack, context, client, logger }) => { + try { + // ショートカットリクエストの確認 + await ack(); - // 組み込みの WebClient を使って views.open API メソッドを呼び出す - const result = await app.client.views.open({ - // `context` オブジェクトに保持されたトークンを使用 - token: context.botToken, - trigger_id: shortcut.trigger_id, - view: { - type: "modal", - title: { - type: "plain_text", - text: "My App" - }, - close: { - type: "plain_text", - text: "Close" + // 組み込みの WebClient を使って views.open API メソッドを呼び出す + const result = await app.client.views.open({ + // `context` オブジェクトに保持されたトークンを使用 + token: context.botToken, + trigger_id: shortcut.trigger_id, + view: { + type: "modal", + title: { + type: "plain_text", + text: "My App" + }, + close: { + type: "plain_text", + text: "Close" + }, + blocks: [ + { + type: "section", + text: { + type: "mrkdwn", + text: "About the simplest modal you could conceive of :smile:\n\nMaybe or ." + } }, - blocks: [ - { - type: "section", - text: { + { + type: "context", + elements: [ + { type: "mrkdwn", - text: "About the simplest modal you could conceive of :smile:\n\nMaybe or ." + text: "Psssst this modal was designed using " } - }, - { - type: "context", - elements: [ - { - type: "mrkdwn", - text: "Psssst this modal was designed using " - } - ] - } - ] - } - }); - - logger.info(result); - } - catch (error) { - logger.error(error); - } - }); - ``` + ] + } + ] + } + }); -
\ No newline at end of file + logger.info(result); + } + catch (error) { + logger.error(error); + } +}); +``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/socket-mode.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/socket-mode.md index 275cdea5c..b765a8e5b 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/socket-mode.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/socket-mode.md @@ -23,10 +23,7 @@ const app = new App({ })(); ``` -
- -ソケットモードレシーバーのカスタム初期化 - +## ソケットモードレシーバーのカスタム初期化 以下のように `@slack/bolt` から `SocketModeReceiver` を import して、カスタムされたインスタンスとして定義することができます。 @@ -53,6 +50,4 @@ const app = new App({ await app.start(); console.log('⚡️ Bolt app started'); })(); -``` - -
+``` \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/updating-pushing-views.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/updating-pushing-views.md index 17c5a8c63..0f7d99804 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/updating-pushing-views.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/updating-pushing-views.md @@ -6,13 +6,13 @@ slug: /concepts/updating-pushing-views モーダルでは、複数のモーダルをスタックのように積み重ねて表示できます。[`views.open`](https://api.slack.com/methods/views.open) という API を呼び出すと、まず親の(最初の)モーダルが表示されます。この最初の呼び出しの後、[`views.update`](https://api.slack.com/methods/views.update) を実行することでそのビューを書き換えることもできますし、最初に述べたように [`views.push`](https://api.slack.com/methods/views.push) で新しいモーダルを積み重ねて表示することもできます。 -**`views.update`** +## `views.update` モーダルの更新には、組み込みの API クライアントを使って `views.update` を呼び出します。この API 呼び出しには、そのモーダルを開いたときに生成された `view_id` と、更新後の内容を表現する `blocks` の配列を含む新しい `view` を渡します。ユーザーが既存のモーダル内の要素とインタラクションを行なった(例:ボタンを押す、メニューから選択する)ことをトリガーにビューを更新する場合、そのリクエストの `body` に `view_id` が含まれます。 -**`views.push`** +## `views.push` -モーダルのスタックに新しいモーダルを積み重ねるためには、組み込みの API クライアントを用いて `views.push` を呼び出します。この API 呼び出しには、有効な `trigger_id` と、新しく生成する [ビュー部分のペイロード](https://api.slack.com/reference/block-kit/views)を渡します。`views.push` の引数は モーダルを開始するときと同様です。最初のモーダルを開いた後、その上にさらに二つまで追加のモーダルをスタックに積み重ねることができます。 +モーダルのスタックに新しいモーダルを積み重ねるためには、組み込みの API クライアントを用いて `views.push` を呼び出します。この API 呼び出しには、有効な `trigger_id` と、新しく生成する [ビュー部分のペイロード](https://api.slack.com/reference/block-kit/views)を渡します。`views.push` の引数は [モーダルを開始するとき](/concepts/creating-modals)と同様です。最初のモーダルを開いた後、その上にさらに二つまで追加のモーダルをスタックに積み重ねることができます。 より詳細な情報は [API ドキュメント](/concepts/view-submissions)を参照してください。 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/view-submissions.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/view-submissions.md index f22c6cf89..641de55d5 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/view-submissions.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/view-submissions.md @@ -14,7 +14,7 @@ slug: /concepts/view-submissions --- -##### モーダル送信でのビューの更新 +## モーダル送信でのビューの更新 `view_submission` リクエストに対してモーダルを更新するには、リクエストの確認の中で `update` という `response_action` と新しく作成した `view` を指定します。 @@ -33,7 +33,7 @@ app.view('modal-callback-id', async ({ ack, body }) => { --- -##### モーダルを閉じるときのハンドリング +## モーダルを閉じるときのハンドリング 💡 `view_closed` リクエストをリッスンするとき、`callback_id` と `type: 'view_closed'` を含むオブジェクトの指定が必要です。以下の例を参照してください。 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/web-api.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/web-api.md index a5578871f..6eccc9c0b 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/web-api.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/concepts/web-api.md @@ -4,7 +4,7 @@ lang: ja-jp slug: /concepts/web-api --- -[Web API メソッド](https://api.slack.com/methods)を呼び出すには、リスナー関数の引数に `client` として提供されている [`WebClient`](https://tools.slack.dev/node-slack-sdk/web-api) を使用します。このインスタンスが使用するトークンは、Bolt アプリの初期化時に指定されたもの もしくは Slack からのリクエストに対して [`authorize` 関数](/concepts/authorization)から返されたものが設定されます。組み込みの [OAuth サポート](/concepts/authenticating-oauth)は、この後者のケースをデフォルトでハンドリングします。 +[Web API メソッド](https://api.slack.com/methods)を呼び出すには、リスナー関数の引数に `client` として提供されている [`WebClient`](https://tools.slack.dev/node-slack-sdk/web-api) を使用します。このインスタンスが使用するトークンは、Bolt アプリの初期化時に指定されたもの **もしくは** Slack からのリクエストに対して [`authorize` 関数](/concepts/authorization)から返されたものが設定されます。組み込みの [OAuth サポート](/concepts/authenticating-oauth)は、この後者のケースをデフォルトでハンドリングします。 Bolt アプリケーションは、トップレベルに `app.client` も持っています。このインスタンスには、トークンをメソッド呼び出しのパラメーターとして都度指定します。Slack からのリクエストが authorize されないユースケースや、リスナー関数の外で Web API を呼び出したい場合は、このトップレベルの `app.client` を使用します。 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/deployments/aws-lambda.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/deployments/aws-lambda.md index 743589da5..5a266eb60 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/deployments/aws-lambda.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/deployments/aws-lambda.md @@ -3,16 +3,13 @@ title: AWS Lambda へのデプロイ lang: ja-jp --- -# AWS Lambda へのデプロイ - このガイドでは、Bolt for JavaScript、[Serverless Framework](https://serverless.com/)、[AWS Lambda](https://aws.amazon.com/lambda/) を使った Slack アプリの準備とデプロイの方法について説明します。 - この手順を全て終わらせたら、あなたはきっと⚡️ [Deploying to AWS Lambda](https://github.com/slackapi/bolt-js/tree/main/examples/deploy-aws-lambda) のサンプルアプリを動作させたり、それに変更を加えたり、自分のアプリを作ったりすることができるようになるでしょう。 --- -### AWS Lambda のセットアップ {#set-up-aws-lambda} +## AWS Lambda のセットアップ {#set-up-aws-lambda} [AWS Lambda](https://aws.amazon.com/lambda/) はサーバーレスの Function-as-a-Service(FaaS)プラットフォームです。AWS Lambda を利用すると、サーバーを管理することなく、コードを実行することができます。このセクションでは、ローカルマシンから AWS Lambda にアクセスするための設定を行います。 @@ -22,7 +19,7 @@ lang: ja-jp ::: -**1. AWS アカウントを作成する** +### 1. AWS アカウントを作成する AWS アカウントをまだ持っていない場合は、[アカウントを作成](https://aws.amazon.com/)する必要があります。画面に表示される案内に沿って作成しましょう。 @@ -32,7 +29,7 @@ AWS アカウントをまだ持っていない場合は、[アカウントを作 ::: -**2. AWS のアクセスキーを作成する** +### 2. AWS のアクセスキーを作成する Lambda へのデプロイでは、プログラムから AWS アカウントにアクセスする手段が必要になります。AWS の世界では、このために**アクセスキー ID** と**シークレットアクセスキー**が必要です。 @@ -44,13 +41,13 @@ Lambda へのデプロイでは、プログラムから AWS アカウントに ::: -**3. AWS CLI をインストールする** +### 3. AWS CLI をインストールする AWS では [macOS、Windows、Linux](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) にインストールして利用できるコマンドラインインターフェイス(CLI)のツールが用意されています。 macOS では、[最新の .pkg インストーラーをダウンロード](https://awscli.amazonaws.com/AWSCLIV2.pkg)して AWS CLI をインストールできます。 -**4. AWS プロファイルを構成する** +### 4. AWS プロファイルを構成する AWS CLI を使ってプロファイルを構成します。プロファイルはローカルマシンに置かれ、アクセスキーのペアを保管します。この CLI やその他のツールは、このプロファイルを使って AWS にアクセスします。 @@ -74,12 +71,10 @@ aws configure --- -### Serverless Framework をセットアップする {#set-up-serverless-framework} +## Serverless Framework をセットアップする {#set-up-serverless-framework} [Serverless Framework](https://serverless.com/) では、AWS Lambda 向けのアプリの設定、デバッグ、デプロイを簡単に行うためのツールが用意されています。 -**1. Serverless Framework CLI をインストールする** - Serverless でも macOS、Windows、Linux にインストールして利用できるコマンドラインインターフェイス(CLI)のツールが用意されています。インストールするには Serverless の[入門ガイド(英語)](https://www.serverless.com/framework/docs/getting-started/) をお読みください。 インストールが完了したら Serverless CLI をテストするため、利用可能なコマンドを表示してみましょう。 @@ -92,7 +87,7 @@ Serverless のツールのセットアップが完了しました。次に、AWS --- -### Bolt Slack アプリを入手する {#get-a-bolt-slack-app} +## Bolt Slack アプリを入手する {#get-a-bolt-slack-app} まだ Bolt アプリを自分で作成したことがない場合は、[入門ガイド](/getting-started)を参照してください。テンプレートのアプリをクローンするには、以下のコマンドを実行します。 @@ -110,9 +105,9 @@ Bolt アプリを用意できました。次に AWS Lambda と Serverless Framew --- -### アプリをセットアップする {#prepare-the-app} +## アプリをセットアップする {#prepare-the-app} -**1. アプリを AWS Lambda に対応させる** +### 1. アプリを AWS Lambda に対応させる デフォルトでは、入門ガイドの Bolt サンプルアプリはソケットモードを使用しています。WebSocket イベントの代わりに HTTP リクエストをリッスンするため、 `app.js` の設定を変更しましょう。 @@ -174,7 +169,7 @@ module.exports.handler = async (event, context, callback) => { 完成したアプリのソースコードは、⚡️[deploy-aws-lambda](https://github.com/slackapi/bolt-js/tree/main/examples/deploy-aws-lambda/app.js) のサンプルのようになります。 -**2. serverless.yml を追加する** +### 2. serverless.yml を追加する Serverless Framework のプロジェクトでは、アプリの設定とデプロイに `serverless.yml` ファイルを使用します。 @@ -206,7 +201,7 @@ plugins: ::: -**3. serverless-offline モジュールをインストールする** +### 3. serverless-offline モジュールをインストールする ローカルでの開発を容易にするため、`serverless-offline` モジュールを使ってデプロイ対象の関数をエミュレートできるようにしましょう。 @@ -220,11 +215,11 @@ npm install --save-dev serverless-offline --- -### アプリをローカルで実行する {#run-the-app-locally} +## アプリをローカルで実行する {#run-the-app-locally} アプリを AWS Lambda 関数に応答させるための準備が完了したので、次にローカルでアプリを実行できるように環境を設定します。 -**1. ローカルのサーバーを起動する** +### 1. ローカルのサーバーを起動する まず、アプリの起動と AWS Lambda 関数のイベントをリッスンするため、`serverless offline` コマンドを実行します。 @@ -250,7 +245,7 @@ ngrok http 3000 ::: -**2. リクエスト URL を変更する** +### 2. リクエスト URL を変更する 次に、[Slack アプリの設定](https://api.slack.com/apps)を開き、**リクエスト URL** を ngrok のウェブアドレスに変更します。 @@ -268,7 +263,7 @@ ngrok http 3000 ![「Event Subscriptions」ページ](/img/event-subscriptions-page.png "「Event Subscriptions」ページ") -**3. Slack アプリをテストする** +### 3. Slack アプリをテストする Slack アプリをテストします。今作った Bolt アプリを Slack のチャンネルに招待し、半角の小文字で「hello」と入力してみましょう。[入門ガイド](/getting-started)のとおり、アプリから応答があるはずです。 @@ -285,13 +280,13 @@ Slack アプリをテストします。今作った Bolt アプリを Slack の --- -### アプリをデプロイする {#deploy-the-app} +## アプリをデプロイする {#deploy-the-app} 今までローカルでアプリを実行し、 Slack ワークスペースでテストをしてきました。さて、動作するアプリができたので、デプロイしてみましょう! AWS Lambda 向けのアプリのプロビジョニング、パッケージング、デプロイには、Serverless Framework のツールが利用できます。アプリのデプロイが完了したら、アプリのリクエスト URL を更新して、「hello」と入力した時にアプリが応答できるようにします。✨ -**1. AWS Lambda にアプリをデプロイする** +### 1. AWS Lambda にアプリをデプロイする 次のコマンドを使って AWS Lambda にアプリをデプロイします。 @@ -312,7 +307,7 @@ serverless deploy ::: -**2. Slack アプリの設定を更新する** +### 2. Slack アプリの設定を更新する Slack からのイベントやアクションの送信先となる**リクエスト URL** に、発行された AWS Lambda の**エンドポイント**を指定します。[Slack アプリの構成](https://api.slack.com/apps)を開き、先ほどコピーしたエンドポイントを**リクエスト URL** に貼りつけます。 @@ -324,7 +319,7 @@ Slack からのイベントやアクションの送信先となる**リクエス ![「Event Subscriptions」ページ](/img/event-subscriptions-page.png "「Event Subscriptions」ページ") -**3. Slack アプリをテストする** +### 3. Slack アプリをテストする アプリのデプロイと、Slack の設定の更新が完了しました。動作を試してみましょう。 @@ -333,7 +328,7 @@ Slack からのイベントやアクションの送信先となる**リクエス > 👩‍💻 hello
> 🤖 Hey there @Jane! -**4. 更新をデプロイする** +### 4. 更新をデプロイする Slack アプリの開発を継続していくなら、更新したアプリをデプロイする必要が出てくるでしょう。それをやってみるために、「goodbye」というメッセージに応答するようにアプリを変更してみましょう。 @@ -355,11 +350,15 @@ serverless deploy デプロイが完了したら、アプリを参加させた Slack チャンネルを開いて、半角の小文字で「goodbye」と入力してみましょう。Slack アプリに「See you later」と表示されるはずです。 -> ⛳️ 一つの関数に小さな変更を加える場合、その関数だけをデプロイするためにより高速な `serverless deploy function -f my-function` を実行することができます。より詳細なヘルプを見るには `serverless help deploy function` を実行してください。 +:::tip + +一つの関数に小さな変更を加える場合、その関数だけをデプロイするためにより高速な `serverless deploy function -f my-function` を実行することができます。より詳細なヘルプを見るには `serverless help deploy function` を実行してください。 + +::: --- -### 次のステップ {#next-steps} +## 次のステップ {#next-steps} ⚡️[AWS Lambda を使った最初の Bolt for JavaScript アプリ](https://github.com/slackapi/bolt-js/tree/main/examples/deploy-aws-lambda)をデプロイできました。🚀 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/deployments/heroku.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/deployments/heroku.md index 8eacde210..715e0ecd4 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/deployments/heroku.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/deployments/heroku.md @@ -3,16 +3,13 @@ title: Heroku へのデプロイ lang: ja-jp --- -# Heroku へのデプロイ - このガイドでは、Bolt for JavaScriptと[Heroku プラットフォーム](https://heroku.com/)を使ってSlack アプリを用意して、デプロイするまでの手順を説明します。全体の流れとしては、Bolt Slack アプリをダウンロードし、Heroku 用の準備を済ませ、デプロイする流れになります。 - この手順を全て終わらせたら、あなたはきっと️⚡️[getting-started-with-heroku](https://github.com/slackapi/bolt-js/tree/main/examples/deploy-heroku)のサンプルアプリを動作させたり、それに変更を加えたり、自分のアプリを作ったりすることができるようになるでしょう。 --- -### Bolt Slack アプリを入手する {#get-a-bolt-slack-app} +## Bolt Slack アプリを入手する {#get-a-bolt-slack-app} Bolt アプリを作るのが初めてという場合は、まず[Bolt 入門ガイド](/getting-started)に沿って進めてみましょう。または、以下のテンプレートアプリをクローンしてもよいでしょう。 @@ -30,11 +27,11 @@ cd bolt-js-getting-started-app/ --- -### アプリをHeroku で動かすための準備する {#prepare-the-app-for-heroku} +## アプリをHeroku で動かすための準備する {#prepare-the-app-for-heroku} Heroku は、作ったアプリをホストできる柔軟性の高いプラットフォームで、少し設定が必要です。このセクションでは、Bolt アプリに変更を加え、Heroku に対応させます。 -**1. Git リポジトリを使用する** +### 1. Git リポジトリを使用する Heroku にアプリをデプロイするには、まずGit リポジトリが必要です。まだGit を使ったことがない場合は、[Git をインストール](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)し、[Git リポジトリを作成](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository)します @@ -44,7 +41,7 @@ Heroku にアプリをデプロイするには、まずGit リポジトリが必 ::: -**2. Procfile を追加する** +### 2. Procfile を追加する Heroku アプリでは、必ず`Procfile`という専用のファイルが必要です。このファイルを使ってHeroku にアプリの起動方法を伝えます。Bolt Slack アプリは、公開されたWeb アドレスを持つWeb サーバーとして起動します。 @@ -77,11 +74,11 @@ git commit -m "Add Procfile" --- -### Heroku ツールをセットアップする {#set-up-the-heroku-tools} +## Heroku ツールをセットアップする {#set-up-the-heroku-tools} ローカルマシンでHeroku ツールのセットアップを行います。このツールは、Heroku プラットフォームを使用するアプリの管理、デプロイ、デバッグを行う場合に便利です。 -**1. Heroku CLI をインストールする** +### 1. Heroku CLI をインストールする Heroku ツールは、コマンドラインインターフェイス(CLI)の形で提供されています。さっそく[macOS、Windows、Linux 用のHeroku CLI](https://devcenter.heroku.com/articles/getting-started-with-nodejs#set-up)をインストールしましょう。macOS では次のコマンドを実行します。 @@ -101,7 +98,7 @@ heroku help ::: -**2. Heroku CLI にログインする** +### 2. Heroku CLI にログインする Heroku CLI では、ローカルマシンからHeroku アカウントに接続します。[無料のHeroku アカウントを新規登録](https://heroku.com)して、次のコマンドでHeroku CLI にログインします。 @@ -114,7 +111,7 @@ heroku login ::: -**3. Heroku CLI へのログインが成功したか確認する** +### 3. Heroku CLI へのログインが成功したか確認する ログインできたかどうか確認しましょう。次のコマンドを実行すると、Heroku CLI に現在接続されているアカウント名が表示されます。 @@ -126,7 +123,7 @@ heroku auth:whoami --- -### Heroku アプリを作成する {#create-an-app-on-heroku} +## Heroku アプリを作成する {#create-an-app-on-heroku} 先ほどインストールしたツールを使って、[Heroku アプリを作成](https://devcenter.heroku.com/articles/creating-apps)します。アプリを作成するときは、ユニークな名前を自分で指定するか、ランダムな名前を生成することができます。 @@ -136,7 +133,7 @@ heroku auth:whoami ::: -**1. Heroku アプリを作成する** +### 1. Heroku アプリを作成する ユニークな名前を指定してHeroku アプリを作成します。 @@ -158,7 +155,7 @@ Heroku アプリが作成されると、いくつかの情報が表示されま - Web アドレス: `https://sharp-rain-871.herokuapp.com/` - 空のリモートGit リポジトリ: `https://git.heroku.com/sharp-rain-871.git` -**2. Heroku のリモートGit リポジトリを確認する** +### 2. Heroku のリモートGit リポジトリを確認する Heroku CLI は、自動的に`heroku`という名前のリモートGit リポジトリをローカルに追加します。リモートGit リポジトリを一覧して、`heroku`が存在することを確認しましょう。 @@ -168,7 +165,7 @@ git remote -v # heroku https://git.heroku.com/sharp-rain-871.git (push) ``` -**3. アプリをデプロイする** +### 3. アプリをデプロイする Slack アプリの認証情報をHeroku アプリに設定します。 @@ -187,11 +184,11 @@ heroku config:set SLACK_BOT_TOKEN=xoxb- --- -### アプリをデプロイする {#deploy-the-app} +## アプリをデプロイする {#deploy-the-app} アプリをデプロイするため、ローカルのコードをHeroku にプッシュします。その後Slack アプリの設定を更新し、Heroku アプリに"hello" と声をかけてみましょう。 ✨ -**1. Heroku にアプリをデプロイする** +### 1. Heroku にアプリをデプロイする Heroku へのアプリのデプロイには、通常`git push`コマンドを使用します。これにより、ローカルリポジトリのコードがリモートの`heroku`リポジトリにプッシュされます。 @@ -214,7 +211,7 @@ Heroku deploys code that's pushed to the [master or main branches](https://devce heroku ps:scale web=1 ``` -**2. Slack アプリの設定を更新する** +### 2. Slack アプリの設定を更新する 次に、Heroku のWeb アドレスをリクエストURL に指定し、Slack からのイベントやアクションがこのURL に送信されるようにします。 @@ -250,7 +247,7 @@ heroku info ::: -**3. Slack アプリをテストする** +### 3. Slack アプリをテストする アプリのデプロイが完了し、Slack の設定変更も行いました。アプリを試してみましょう。 @@ -258,7 +255,7 @@ heroku info --- -### 変更をデプロイする {#deploy-an-update} +## 変更をデプロイする {#deploy-an-update} Slack アプリを構築するなかで、変更を加えてデプロイする必要があります。一般的な流れでは、変更を加え、コミットし、Heroku にプッシュするという順番です。 @@ -288,7 +285,7 @@ git push heroku main --- -### 次のステップ {#next-steps} +## 次のステップ {#next-steps} これではじめて️⚡Bolt for JavaScript アプリをHerokuへデプロイすることに成功しました。🚀 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/getting-started.mdx b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/getting-started.mdx index ccee79ded..86c59dc29 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/getting-started.mdx +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/getting-started.mdx @@ -5,15 +5,13 @@ slug: getting-started lang: ja-jp --- -# Bolt 入門ガイド - このガイドでは、Bolt を使用して Slack アプリを起動し実行する方法について説明します。その過程で、新しい Slack アプリを作成し、ローカル環境を設定し、Slack ワークスペースからのメッセージをリッスンして応答するアプリを開発します。 このガイドが終わったら、あなたはこの⚡️[Getting Started app](https://github.com/slackapi/bolt-js-getting-started-app)を実行したり、修正したり、自分で作ったりすることができます。 --- -### アプリを作成する {#create-an-app} +## アプリを作成する {#create-an-app} 最初にやるべきこと: Bolt で開発を始める前に、 [Slack アプリを作成](https://api.slack.com/apps/new)します。 :::tip @@ -32,7 +30,7 @@ lang: ja-jp --- -### トークンとアプリのインストール {#tokens-and-installing-apps} +## トークンとアプリのインストール {#tokens-and-installing-apps} Slack アプリは、[OAuth を使用して、Slack の API へのアクセスを管理](https://api.slack.com/docs/oauth)します。アプリがインストールされるとトークンが発行されます。そのトークンを使って、アプリは API メソッドを呼び出すことができます。 Slack アプリで使用できるトークンには、ユーザートークン(`xoxp`)とボットトークン(`xoxb`)、アプリレベルトークン(`xapp`)の 3 種類があります。 @@ -60,7 +58,7 @@ Slack アプリで使用できるトークンには、ユーザートークン --- -### ローカルプロジェクトの設定 {#setting-up-your-project} +## ローカルプロジェクトの設定 {#setting-up-your-project} 初期設定が完了したので、次は新しい Bolt プロジェクトを設定します。ここで、アプリのロジックを処理するコードを記述します。 プロジェクトをまだ作成していない場合は、新しいプロジェクトを作成しましょう。次のように、空のディレクトリを作成して、新しいプロジェクトを初期化します。 @@ -128,7 +126,7 @@ node app.js --- -### イベントの設定 {#setting-up-events} +## イベントの設定 {#setting-up-events} アプリはワークスペース内の他のメンバーと同じように振る舞い、メッセージを投稿したり、絵文字リアクションを追加したり、イベントをリッスンして返答したりできます。 @@ -192,7 +190,7 @@ import TabItem from '@theme/TabItem'; --- -### メッセージのリスニングと応答 {#listening-and-responding-to-a-message} +## メッセージのリスニングと応答 {#listening-and-responding-to-a-message} これで、アプリでいくつかのロジックを設定する準備が整いました。まずは `message()` メソッドを使用して、メッセージのリスナーをアタッチしましょう。 次の例では、あなたのアプリが追加されているチャンネルや DM で `hello` という単語を含むすべてのメッセージをリッスンし、 `Hey there @user!` と応答します。 @@ -261,7 +259,7 @@ app.message('hello', async ({ message, say }) => { --- -### アクションの送信と応答 {#sending-and-responding-to-actions} +## アクションの送信と応答 {#sending-and-responding-to-actions} ボタン、選択メニュー、日付ピッカー、モーダルなどの機能を使用するには、インタラクティブ機能を有効にする必要があります。イベントと同様に、Slack の URL を指定してアクション ( 「ボタン・クリック」など) を送信する必要があります。 @@ -517,7 +515,7 @@ app.action('button_click', async ({ body, ack, say }) => { --- -### 次のステップ {#next-steps} +## 次のステップ {#next-steps} これで最初の Bolt アプリが構築できました! 🎉 基本的なアプリの作成ができましたので、次回は是非もっといろいろな、 Bolt の機能を使ってアプリを作ってみましょう。下記のリンクを辿っていろいろアイデアを模索してみてください! @@ -526,4 +524,4 @@ app.action('button_click', async ({ body, ack, say }) => { * ボットが[`events()` メソッド](/concepts/event-listening)でリッスンできるさまざまなイベントを確認しましょう。イベントはすべて[API サイト](https://api.slack.com/events)にリストされています。 -* Bolt を使用すると、アプリにアタッチされているクライアントで [Web API メソッドを呼び出す](/concepts/web-api)ことができます。API サイトに [200 を超えるメソッド](https://api.slack.com/methods)を用意してあります。 +* Bolt を使用すると、アプリにアタッチされているクライアントで [Web API メソッドを呼び出す](/concepts/web-api)ことができます。API サイトに [200 を超えるメソッド](https://api.slack.com/methods)を用意してあります。 \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/hubot-migration.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/hubot-migration.md index 358171433..2be027651 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/hubot-migration.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/hubot-migration.md @@ -3,7 +3,6 @@ title: Hubot から Bolt に移行する方法 slug: hubot-migration lang: ja-jp --- -# Hubot のアプリを Bolt に移行する方法 Bolt は、Slack アプリを構築する時間と手間を減らすために作成されたフレームワークで、Slack 開発者のみなさんに最新機能とベストプラクティスを使用してアプリを構築できる単一のインターフェイスを提供します。このガイドでは、[Hubot で作成されたアプリを Bolt アプリに](https://hubot.github.com/docs/)移行するプロセスを順を追って説明します。 @@ -11,7 +10,7 @@ Bolt は、Slack アプリを構築する時間と手間を減らすために作 --- -### まずはじめに {#setting-the-stage} +## まずはじめに {#setting-the-stage} Hubot アプリを Bolt に変換するとき、それぞれが内部的にどのように機能しているかを把握しているとさらに理解を深めることができるでしょう。Slack の Hubot アダプターは、 WebSocket をベースとした [RTM API](https://api.slack.com/rtm) と接続するように実装されているので、Hubot アプリには一連のワークスペースイベントが一気にストリーミングされます。そして、RTM API は、新しいプラットフォーム機能をサポートしておらず、特にアプリが複数のまたは大規模な Slack チームにインストールされる場合には、膨大なリソースを消費する可能性があるため、ほとんどのユースケースでおすすめできません。 デフォルトの Bolt レシーバーは、[Events API](https://api.slack.com/events-api) をサポートするように構築されています。これは、HTTP ベースのイベントサブスクリプションを使用して Bolt アプリに JSON ペイロードを送信します。Events API には、RTM にはない新機能のイベントも含まれており、より細かい制御が可能でスケーラブルですのでほとんどのユースケースで推奨されています。しかし例外として、RTM API を使用し続けなければならない理由の 1 つに、アプリをホストしているサーバーにファイアウォールがあり、HTTP 送信リクエストのみを許可して、受信リクエストを許可しないというようなケースが挙げられます。 @@ -23,10 +22,10 @@ Bolt アプリを作成する前に考慮に入れた方がよい違いがほか --- -### ボットの設定 {#configuring-your-bot} -ボットユーザーを持つ既存の Slack アプリをお持ちの方は, 次のセクションに進むことができます。わからない場合は、[App Management ページ](https://api.slack.com/apps) に移動し、自分の Hubot アプリがあるかどうかを確認してください。ある場合は、そのアプリの認証情報をそのまま使用できます (次のセクションに進んでください)。ない場合は、下記の手順通りに進めていきましょう。 +## ボットの設定 {#configuring-your-bot} +ボットユーザーを持つ既存の Slack アプリをお持ちの方は, 次のセクションに進むことができます。わからない場合は、[app settings ページ](https://api.slack.com/apps) に移動し、自分の Hubot アプリがあるかどうかを確認してください。ある場合は、そのアプリの認証情報をそのまま使用できます (次のセクションに進んでください)。ない場合は、下記の手順通りに進めていきましょう。 -#### Slack アプリを作成する +## Slack アプリを作成する まず最初に、Slack アプリを作成します。 :::tip @@ -41,17 +40,21 @@ Bolt アプリを作成する前に考慮に入れた方がよい違いがほか ひと通り確認し、アプリのアイコンと説明を追加したら、アプリの構成 🔩 を始めましょう。 -#### ボットユーザーを追加する +### ボットユーザーを追加する Slack では、Hubot アプリはユーザーとの対話型のボットユーザーを採用しています。 新しいアプリにボットユーザーを追加するには、左側のサイドバーの **Bot Users** をクリックしてから、**Add A Bot User** をクリックします。表示名とユーザー名を指定して、**Add Bot User** をクリックします。その他のフィールドの詳しい情報は、[API サイト](https://api.slack.com/bot-users#creating-bot-user) をご覧ください。 -### ボットの設定 {#configure-what-your-bot-will-hear} +## ボットの設定 {#configure-what-your-bot-will-hear} [Events API](https://api.slack.com/bot-users#app-mentions-response) は、ボットの目と耳に相当します。これによりボットは、投稿されたメッセージ、チャンネルの変更、Slack で発生するその他のアクティビティに反応することができます。 -> ⚠️ボットのイベントを設定する前に、パブリック URL が必要です。Bolt アプリを作成したことがない場合、または Events API を使用したことがない場合は、『Getting Started ガイド』の [ローカル Bolt プロジェクトの設定](/getting-started) と [イベントの設定](/getting-started#setting-up-events) を参考にしてください。 +:::warning -#### メッセージのリスニング +ボットのイベントを設定する前に、パブリック URL が必要です。Bolt アプリを作成したことがない場合、または Events API を使用したことがない場合は、『Getting Started ガイド』の [ローカル Bolt プロジェクトの設定](/getting-started) と [イベントの設定](/getting-started#setting-up-events) を参考にしてください。 + +::: + +### メッセージのリスニング すべての Hubot アプリは、デフォルトでメッセージをリッスンできるので、ボットユーザーがそうするように設定する必要があります。 [イベントの設定](/getting-started#setting-up-events) を行ってから、リクエスト URL を入力、そして検証されたことを確認したら、**Subscribe to Bot Events** にスクロールダウンします。メッセージに関連する次の 4 つのイベントがあります `message channel` (パブリックチャンネルのメッセージをリッスン)、`message group` (プライベートチャンネルのメッセージをリッスン)、`message.im` (アプリのホーム/DM スペースのメッセージをリッスン)、`message.mpim` (マルチパーソン DM のメッセージをリッスン)。 @@ -60,7 +63,7 @@ Slack では、Hubot アプリはユーザーとの対話型のボットユー ボットにリッスンさせるメッセージイベントの種類を追加して、**Save Changes** をクリックします。 -#### その他のイベントのリッスン +### その他のイベントのリッスン 使用していた機能に応じて、Hubot アプリはほかのイベントにも応答していたかもしれません。スクリプトを調べて、`react`、`respond`、`presenceChange` が使用されている箇所を特定してください。 - アプリで `respond` が使用されている場合、`app_mention` イベントをサブスクライブします。これで、ボットユーザーがメンションされる時をリッスンします。 - アプリで `react` が使用されている場合、`reaction_added` イベントをサブスクライブします。これにより、ボットユーザーがいるチャンネルのメッセージにリアクションが追加される時をリッスンします。 @@ -74,41 +77,57 @@ Bolt に追加された利点として、どの [Events API イベント](https: アプリの機能に対応するイベントを追加 し終えたら、**Save Changes** をクリックします。 -### スクリプトインターフェイスの変更 {#changes-to-script-interfaces} +## スクリプトインターフェイスの変更 {#changes-to-script-interfaces} Bolt のインターフェイスは、可能な限り Slack API 言語に適合するように設計されましたが、Hubot は複数のサービスを抽象化するために一般化された言語を使用して設計されました。インターフェイスは似ていますが、Hubot スクリプトを Bolt スクリプトに変換するには、いくらかコードを変更する必要があります。 Bolt は、`res` を使用せず、Slack からの raw リクエストを公開しません。代わりに、`payload` 使ってペイロードボディを取得したり、`say()` を使ってメッセージを送信するといった一般的な機能を使用したりできます。 -> ⚙わかりやすくするために、サンプルスクリプトを Github 上に作成しました。このスクリプトは、[Bolt 用に書かれた機能と同等のものを使用している Hubot のコア機能を紹介しています。](https://github.com/slackapi/bolt-js/blob/master/examples/hubot-example/script.js) +:::tip + +⚙わかりやすくするために、サンプルスクリプトを Github 上に作成しました。このスクリプトは、[Bolt 用に書かれた機能と同等のものを使用している Hubot のコア機能を紹介しています。](https://github.com/slackapi/bolt-js/blob/master/examples/hubot-example/script.js) -#### `message()` を使用したパターンのリスニング +::: + +### `message()` を使用したパターンのリスニング Hubot スクリプトは、`hear()` を使用して、一致するパターンを持つメッセージをリッスンします。代わりに、 Bolt は `message()` を使用して、そのパターンの `string` または `RegExp` を受け入れます。 -> 👨‍💻👩‍💻コードで `hear()` を使用している箇所はすべて、`message()` を使用するように変更してください。 +:::tip + +👨‍💻👩‍💻コードで `hear()` を使用している箇所はすべて、`message()` を使用するように変更してください。 + +::: [メッセージのリスニングについてもっと詳しく読む](/concepts/message-listening). -#### `say()` および `respond()` を使用したメッセージで応答する +### `say()` および `respond()` を使用したメッセージで応答する Hubot スクリプトは、`send()` を使用してメッセージを同じ会話に送信し、`reply()` を使用して、元のメッセージを送信したユーザー宛の@メンションを付けて、メッセージを同じ会話上に送信します。 Bolt は、`send()` の代わりに `say()` を使用し、`respond()` を使用して `response_url` で返信を送信します。返信の冒頭にメンションを追加するには、`context` オブジェクトにあるユーザー ID を使用できます。たとえば、メッセージイベントの場合は次のようにできます: `say('<@${message.user}>Hello :wave:')` Hubot の `send()` と Bolt の `say()` はほとんど同じですが、`say()` を使用すると [ボタン、メニューの選択、デートピッカー](https://api.slack.com/messaging/interactivity#interaction) といったインタラクティブなコンポーネントを付けてメッセージを送信できます。 -> 👨‍💻👩‍💻コードで `send()` が使用されている箇所はすべて `say()` に変更してください +:::tip + +👨‍💻👩‍💻コードで `send()` が使用されている箇所はすべて `say()` に変更してください + +::: [メッセージへの応答についてもっと詳しく読む](/concepts/message-sending). -#### `respond` と `react` +### `respond` と `react` 前のセクションで、Hubot スクリプトで `respond()` が使用されている場合は `app_mention` イベントを、`react()` が使用されている場合は `reaction_added` をサブスクライブするようにアプリを設定しました。 Bolt は、`event()` と呼ばれるメソッドを使用して、任意の [Events API イベント](https://api.slack.com/events) をリッスンできます。コードを変更するには、`respond()` を app.event(‘app_mention’) に、`react()` を `app.event(‘reaction_added’)` に変更するだけです。この点は、[サンプルスクリプト](https://github.com/slackapi/bolt-js/blob/master/examples/hubot-example/script.js) で詳しく説明されています。 -> 👨‍💻👩‍💻コードで `respond()` が使用されている箇所はすべて、app.event ('app_mention') を使用するように変更してください。`react` が使用されている箇所はすべて `app.event('reaction_added')` に変更してください。 +:::tip + +👨‍💻👩‍💻コードで `respond()` が使用されている箇所はすべて、app.event ('app_mention') を使用するように変更してください。`react` が使用されている箇所はすべて `app.event('reaction_added')` に変更してください。 + +::: [イベントのリッスンについてもっと詳しく読む](/concepts/event-listening). -### Bolt で Web API メソッドを使用する {#using-web-api-methods-with-bolt-for-javascript} +## Bolt で Web API メソッドを使用する {#using-web-api-methods-with-bolt-for-javascript} Hubot では、`@slack/client` から `WebClient` パッケージをインポートする必要がありました。Bolt では、`app.client` からアクセスできる `WebClient` インスタンスがデフォルトでインポートされます。 組み込みの `WebClient` を使用するには、アプリをインスタンス化するために使用されるトークン、またはリクエストの送信元のチームに関連付けられているトークンを渡す必要があります。これは、リスナー関数に渡された `context` オブジェクトにあります。たとえば、メッセージにリアクションを追加するには、次を使用します: @@ -129,11 +148,15 @@ app.message('react', async ({ message, context, logger }) => { }); ``` -> 👨‍💻👩‍💻`app.client` で組み込みのクライアントを使用するように、Web API 呼び出しを変更してください。 +:::tip + +👨‍💻👩‍💻`app.client` で組み込みのクライアントを使用するように、Web API 呼び出しを変更してください。 + +::: [Bolt での Web API の使用についてもっと詳しく読む。](/concepts/web-api) -### Bolt でのミドルウェアの使用 {#using-middleware-with-bolt-for-javascript} +## Bolt でのミドルウェアの使用 {#using-middleware-with-bolt-for-javascript} Hubot には、受信 (リスナーが呼び出される前に実行される)、リスナー (一致するすべてのリスナーに対して実行される)、応答 (送信されるすべての応答に対して実行される) という 3 種類のミドルウェアがあります。 Bolt には、グローバルとリスナーという 2 種類のミドルウェアしかありません。 @@ -146,7 +169,7 @@ Bolt では、グローバルとリスナーというミドルウェアはいず ミドルウェアがイベントの後処理を実行する必要がある場合、`undefined` で呼び出すのではなく、後処理関数を使用して `await next()` を呼び出すことができます。後処理関数は、ミドルウェア関数が `await next()` を呼び出すのと同じ方法で` done()` を呼び出す必要があります(`Error` で呼び出すことも可能) 。 -### Brain を conversation store に移行する {#migrating-the-brain-to-the-conversation-store} +## Brain を conversation store に移行する {#migrating-the-brain-to-the-conversation-store} Hubot には、brain と呼ばれるメモリ内ストレージがあります。これによって、Hubot スクリプトはデータの基本部分を `get` および `set` することができます。Bolt は、conversation store と呼ばれる、`get()`/`set()` インターフェイスを含むグローバルミドルウェアを使用します。 デフォルトの組み込み conversation store は Hubot に似たメモリ内ストレージを使用し、ミリ秒単位で有効期限を設定できます。conversation の状態情報を get および set する方法は 2 つあります。 @@ -157,7 +180,7 @@ Hubot には、brain と呼ばれるメモリ内ストレージがあります [会話ストアについてもっと詳しく読む](/concepts/conversation-store). -### 次のステップ {#next-steps} +## 次のステップ {#next-steps} ここまで来れば、きっと Hubot アプリを Bolt アプリに変換できているはずです!✨⚡ 新しくなってよりクールになった Bolt アプリを、さらにパワーアップしていくこともできます。 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/steps-from-apps.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/steps-from-apps.md index a131e4320..867785076 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/steps-from-apps.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/legacy/steps-from-apps.md @@ -1,7 +1,7 @@ --- title: ワークフローステップの概要 lang: ja-jp -slug: /concepts/steps-from-apps +slug: /legacy/steps-from-apps --- (アプリによる)ワークフローステップ(Workflow Steps from Apps) は、[ワークフロービルダー](https://api.slack.com/workflows)におけるワークフローに組み込み可能なカスタムのワークフローステップを任意の Slack アプリが提供することを可能とします。 diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v2.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v2.md index 1361e1f5a..e105b15ba 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v2.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v2.md @@ -4,15 +4,13 @@ slug: /tutorial/migration-v2 lang: ja-jp --- -# 2.x マイグレーションガイド +`@slack/bolt@1.x` End of life は **2021 年 4 月 30 日** の予定です。この日からは `@slack/bolt@1.x` の開発は完全に終了となり、残っている open issue や pull request もクローズされます。 このガイドは Bolt 1.x を利用しているアプリを 2.x にアップグレードするための手順について説明します。いくつかの変更が必要とはなりますが、ほとんどのアプリの場合で、おそらく対応に必要な時間は 5 〜 15 分程度です。 -*注: もしすぐにアップグレードをしない場合は、[Bolt 1.x に関するサポートスケジュール](#slackbolt1x-support-schedule)をご確認ください* - --- -### リスナー関数を `async` 関数に変更 {#upgrading-your-listeners-to-async} +## リスナー関数を `async` 関数に変更 {#upgrading-your-listeners-to-async} Bolt アプリ内のリスナー関数は、全て `async` 関数に変更する必要があります。そして、そのリスナー関数内の `say()`、`respond()`、`ack()` メソッドの呼び出しも全て `await` を呼び出しの前につける必要があります。 @@ -34,11 +32,11 @@ app.action('some-action-id', async ({action, ack, say}) => { }) ``` -### エラーハンドリング {#error-handling} +## エラーハンドリング {#error-handling} Bolt for JavaScript 2.x では、より多くのユースケースで、必要に応じてエラーをキャッチし、グローバルエラーハンドラーにそれを送るかを制御できるよう改善されました。これまでと同様、グローバルエラーハンドラーに全て任せるよりは、可能な限り、リスナー関数の内部でエラーに対処することをおすすめします。 -#### リスナー関数内で `try`/`catch` 節を用いたエラーハンドリング +### リスナー関数内で `try`/`catch` 節を用いたエラーハンドリング ```javascript app.action('some-action-id', async ({action, ack, say, logger}) => { @@ -52,7 +50,7 @@ app.action('some-action-id', async ({action, ack, say, logger}) => { }) ``` -#### グローバルエラーハンドラーによるエラーハンドリング +### グローバルエラーハンドラーによるエラーハンドリング ```javascript app.error(async (error) => { @@ -66,7 +64,7 @@ app.error(async (error) => { - リスナー関数が `ack()` メソッドを 3 秒間のうちに呼び出さなかった場合、これまでのように例外を投げるのではなくログを出力するようになりました - もし一つのイベントに対して複数のリスナー関数を実行中に複数のエラーが発生した場合、Bolt for JavaScript は `ErrorCode.MultipleListenerError` の値での `code` と、発生した個々のエラーの配列を含む `originals` というパラメーターをラップしたエラーを返します -### メッセージショートカット {#message-shortcuts} +## メッセージショートカット {#message-shortcuts} [メッセージショートカット](https://api.slack.com/interactivity/shortcuts/using#message_shortcuts) (以前はメッセージアクションと呼ばれていました)は、これまで `action()` メソッドでハンドリングしていましたが `shortcut()` メソッドを使うようになりました。 @@ -88,7 +86,7 @@ app.shortcut('message-action-callback', async ({shortcut, ack, context}) => { }) ``` -### ミドルウェアに関する変更 {#upgrading-middleware} +## ミドルウェアに関する変更 {#upgrading-middleware} もしカスタムのミドルウェアを書いている場合は、その関数を `async` に変更し、さらに `next()` の呼び出しを `await next()` に変更してください。もし後続の処理がある場合は、関数を `next()` に渡す代わりに、その後続の処理を `await next()` の後に実行してください。 @@ -116,10 +114,6 @@ async function noBotMessages({message, next }) { } ``` -### Bolt 1.x のサポートスケジュール {#slackbolt1x-support-schedule} - -`@slack/bolt@1.x` は **2020 年 6 月 30 日** より非推奨となります。それまでの期間はケースバイケースでバグ修正や新機能のバックポートを対応を継続します。`@slack/bolt@1.x` が非推奨となった後は、End of life(正式サポートの終了日)まで **クリティカルなバグ修正のみ** を実装し、クリティカルではない issue や pull request はクローズします。End of life は **2021 年 4 月 30 日** の予定です。この日からは `@slack/bolt@1.x` の開発は完全に終了となり、残っている open issue や pull request もクローズされます。 - -### TypeScript の最低必須バージョン {#minimum-typescript-version} +## TypeScript の最低必須バージョン {#minimum-typescript-version} TypeScript 利用ガイド でも説明していますが、`@slack/bolt@2.x` は TypeScript 3.7 以上が必須バージョンです。 \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v3.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v3.md index cc795ed16..f644355d1 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v3.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/migration/migration-v3.md @@ -3,15 +3,14 @@ title: 3.x マイグレーションガイド slug: /tutorial/migration-v3 lang: ja-jp --- -# 3.x マイグレーションガイド -このガイドは Bolt 2.x を利用しているアプリを 3.x にアップグレードするための手順について説明します。いくつかの変更が必要とはなりますが、ほとんどのアプリの場合で、おそらく対応に必要な時間は 5 〜 15 分程度です。 +`@slack/bolt@2.x` End of life は **2021 年 5 月 31 日** の予定です。この日からは `@slack/bolt@2.x` の開発は完全に終了となり、残っている open issue や pull request もクローズされます。 -*注: もしすぐにアップグレードをしない場合は、[Bolt 2.x に関するサポートスケジュール](#slackbolt2x-support-schedule)をご確認ください* +このガイドは Bolt 2.x を利用しているアプリを 3.x にアップグレードするための手順について説明します。いくつかの変更が必要とはなりますが、ほとんどのアプリの場合で、おそらく対応に必要な時間は 5 〜 15 分程度です。 --- -### InstallationStore と orgAuthorize での OrG レベルでのインストール対応に関する変更 {#org-wide-app-installation-changes-to-installationstore--orgauthorize} +## InstallationStore と orgAuthorize での OrG レベルでのインストール対応に関する変更 {#org-wide-app-installation-changes-to-installationstore--orgauthorize} [Bolt for JavaScript 2.5.0](https://github.com/slackapi/bolt-js/releases/tag/%40slack%2Fbolt%402.5.0) で、私たちは [OrG レベルでのインストール](https://api.slack.com/enterprise/apps)のサポートを追加しました。このサポートをあなたのアプリケーションに追加するには、OAuth フローの中で使用される `fetchOrgInstallation`、`storeOrgInstallation` という二つの新しいメソッドを導入する必要がありました。 3.x では、よりシンプルなインタフェースの実現と Bolt for Python、Bolt for Java との互換性を考慮して、これらの二つの新しいメソッドのサポートを廃止しました。マイグレーションに必要となる変更については以下のコード例を参考にしてください。 @@ -93,18 +92,14 @@ const authorizeFn = async ({ teamId, enterpriseId, isEnterpriseInstall}) => { } ``` -### デフォルトのレシーバーを HTTPReceiver に変更 {#http-receiver-as-default} +## デフォルトのレシーバーを HTTPReceiver に変更 {#http-receiver-as-default} 3.x から新しい [`HTTPReceiver`](https://github.com/slackapi/bolt-js/issues/670) というレシーバーを導入し、デフォルトのレシーバー実装を、これまでの `ExpressReceiver` からこのレシーバーに変更します。この変更は、Bolt for JavaScript を Express.js 以外の人気のある Web フレームワーク(Hapi.js や Koa など)とともに動作させることを容易にします。`ExpressReceiver` は引き続き Bolt for JavaScript のリリースに含まれます。また、`HTTPReceiver` は `ExpressReceiver` が提供する全ての機能を提供するわけではありません。例えば、一つのユースケースとしては、`HTTPReceiver` ではカスタムの HTTP ルート(例: ヘルスチェックのための URL を追加する)を追加する機能はサポートされていません。このようなユースケースに対応するためには、引き続き `ExpressReceiver` を利用することを推奨します。その場合はクラスを import して、インスタンス化したものを `App` のコンストラクタに渡してください。詳細は[カスタム HTTP ルートの追加](/concepts/custom-routes)を参考にしてください。 -### Bolt 2.x のサポートスケジュール {#slackbolt2x-support-schedule} - -`@slack/bolt@2.x` は **2021 年 1 月 12 日** より非推奨となります。それまでの期間はケースバイケースでバグ修正や新機能のバックポートを対応を継続します。`@slack/bolt@2.x` が非推奨となった後は、End of life(正式サポートの終了日)まで **クリティカルなバグ修正のみ** を実装し、クリティカルではない issue や pull request はクローズします。End of life は **2021 年 5 月 31 日** の予定です。この日からは `@slack/bolt@2.x` の開発は完全に終了となり、残っている open issue や pull request もクローズされます。 - -### Node の最低必須バージョン {#minimum-node-version} +## Node の最低必須バージョン {#minimum-node-version} `@slack/bolt@3.x` は Node は `12.13.0` 以上、npm は `6.12.0` 以上が必須バージョンです。 -### TypeScript の最低必須バージョン {#minimum-typescript-version} +## TypeScript の最低必須バージョン {#minimum-typescript-version} TypeScript 利用ガイド でも説明していますが、`@slack/bolt@3.x` は TypeScript 4.1 以上が必須バージョンです。 \ No newline at end of file diff --git a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/reference.md b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/reference.md index ddf47a638..c0fbed56a 100644 --- a/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/reference.md +++ b/docs/i18n/ja-jp/docusaurus-plugin-content-docs/current/reference.md @@ -1,11 +1,10 @@ --- -title: リファレンス +title: リファレンス(Appインターフェイスと設定) +sidebar_label: リファレンス slug: reference permalink: /reference --- -# リファレンス(Appインターフェイスと設定) - このガイドでは、Bolt インターフェイスのリスナー関数、リスナー関数の引数、初期化オプション、エラーについて詳しく説明します。⚡[入門ガイド](/getting-started)をまだ完了していない場合は、先にそちらで Bolt for JavaScript アプリ開発の基本を確認しておきましょう。 ## リスナー関数 {#listener-functions} @@ -108,7 +107,11 @@ App オプションは、`App` のコンストラクターに渡します。`rec | `deferInitialization` | アプリの初期化を遅延させる真偽値です。有効にすると非同期の `App#init()` メソッドを手動で呼び出す必要があります。 また `init()` メソッドは `App#start()` を実行する前に呼び出さなければなりません。 デフォルトは `false` です。 | | `signatureVerification` | Boltが着信リクエストでSlackの署名を検証する必要があるかどうかを決定するブール値。 デフォルトは`true`です。 | -> Bolt のclientは [Node Slack SDK](https://tools.slack.dev/node-slack-sdk) の `WebClient` のインスタンスです。そのため、Node Slack SDK のドキュメントも合わせて参照すると、開発時の理解に役立つでしょう。 +:::tip + +Bolt のclientは [Node Slack SDK](https://tools.slack.dev/node-slack-sdk) の `WebClient` のインスタンスです。そのため、Node Slack SDK のドキュメントも合わせて参照すると、開発時の理解に役立つでしょう。 + +::: ## フレームワークのエラー {#framework-error-types} From 9addeda9799663e79a186c0f3c64587b9ea33d00 Mon Sep 17 00:00:00 2001 From: Luke Russell <31357343+lukegalbraithrussell@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:31:06 -0700 Subject: [PATCH 10/17] Docs: salesforce compliance adjustment (#2311) --- docs/README.md | 4 +- docs/docusaurus.config.js | 110 ++------------------------------------ docs/footerConfig.js | 19 +++++++ docs/navbarConfig.js | 88 ++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 107 deletions(-) create mode 100644 docs/footerConfig.js create mode 100644 docs/navbarConfig.js diff --git a/docs/README.md b/docs/README.md index 4d5186390..5c8194dac 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,7 +26,9 @@ docs/ ├── src/ │ ├── pages/ (stuff that isn't docs content. This is empty for this repo!) │ └── theme (only contains the 404 page) -├── docusaurus.config.js (main config file. also where to set navbar/footer) +├── docusaurus.config.js (main config file) +├── footerConfig.js (footer. go to main repo to change) +├── navbarConfig.js (navbar. go to main repo to change) └── sidebar.js (manually set where the content docs are in the sidebar.) ``` diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 7be0d2e44..c5b680f27 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -1,17 +1,12 @@ -// @ts-check -// `@type` JSDoc annotations allow editor autocompletion and type checking -// (when paired with `@ts-check`). -// There are various equivalent ways to declare your Docusaurus config. -// See: https://docusaurus.io/docs/api/docusaurus-config - import { themes as prismThemes } from 'prism-react-renderer'; +const footer = require('./footerConfig'); +const navbar = require('./navbarConfig'); /** @type {import('@docusaurus/types').Config} */ const config = { title: 'Bolt for JavaScript', tagline: 'Official frameworks, libraries, and SDKs for Slack developers', favicon: 'img/favicon.ico', - url: 'https://tools.slack.dev', baseUrl: '/bolt-js/', organizationName: 'slackapi', @@ -42,9 +37,6 @@ const config = { theme: { customCss: './src/css/custom.css', }, - gtag: { - trackingID: 'G-9H1YZW28BG', - }, }), ], ], @@ -93,102 +85,8 @@ const config = { autoCollapseCategories: true, }, }, - navbar: { - title: 'Slack Developer Tools', - logo: { - alt: 'Slack logo', - src: 'img/slack-logo.svg', - href: 'https://tools.slack.dev', - target: '_self', - }, - items: [ - { - type: 'dropdown', - label: 'Bolt', - position: 'left', - items: [ - { - label: 'Java', - to: 'https://tools.slack.dev/java-slack-sdk/guides/bolt-basics', - target: '_self', - }, - { - label: 'JavaScript', - to: 'https://tools.slack.dev/bolt-js', - target: '_self', - }, - { - label: 'Python', - to: 'https://tools.slack.dev/bolt-python', - target: '_self', - }, - ], - }, - { - type: 'dropdown', - label: 'SDKs', - position: 'left', - items: [ - { - label: 'Java Slack SDK', - to: 'https://tools.slack.dev/java-slack-sdk/', - target: '_self', - }, - { - label: 'Node Slack SDK', - to: 'https://tools.slack.dev/node-slack-sdk/', - target: '_self', - }, - { - label: 'Python Slack SDK', - to: 'https://tools.slack.dev/python-slack-sdk/', - target: '_self', - }, - { - label: 'Deno Slack SDK', - to: 'https://api.slack.com/automation/quickstart', - target: '_self', - }, - ], - }, - { - type: 'dropdown', - label: 'Community', - position: 'left', - items: [ - { - label: 'Community tools', - to: 'https://tools.slack.dev/community-tools', - target: '_self', - }, - { - label: 'Slack Community', - to: 'https://slackcommunity.com/', - target: '_self', - }, - ], - }, - { - to: 'https://api.slack.com/docs', - label: 'API Docs', - target: '_self', - }, - { - type: 'localeDropdown', - position: 'right', - }, - { - 'aria-label': 'GitHub Repository', - className: 'navbar-github-link', - href: 'https://github.com/slackapi/bolt-js', - position: 'right', - target: '_self', - }, - ], - }, - footer: { - copyright: '

Made with ♡ by Slack and pals like you

', - }, + navbar, + footer, prism: { // switch to alucard when available in prism? theme: prismThemes.github, diff --git a/docs/footerConfig.js b/docs/footerConfig.js new file mode 100644 index 000000000..e3e10c571 --- /dev/null +++ b/docs/footerConfig.js @@ -0,0 +1,19 @@ +const footer = { + links: [ + { + items: [ + { + html: ` +

+ ©2024 Slack Technologies, LLC, a Salesforce company. All rights reserved. Various trademarks held by their respective owners. + `, + }, + ], + }, + ], +}; + +module.exports = footer; diff --git a/docs/navbarConfig.js b/docs/navbarConfig.js new file mode 100644 index 000000000..f4277367a --- /dev/null +++ b/docs/navbarConfig.js @@ -0,0 +1,88 @@ +const navbar = { + title: 'Slack Developer Tools', + logo: { + src: 'img/slack-logo.svg', + }, + items: [ + { + type: 'dropdown', + label: 'Bolt', + position: 'left', + items: [ + { + label: 'Java', + to: 'https://tools.slack.dev/java-slack-sdk/guides/bolt-basics', + target: '_self', + }, + { + label: 'JavaScript', + to: 'https://tools.slack.dev/bolt-js', + target: '_self', + }, + { + label: 'Python', + to: 'https://tools.slack.dev/bolt-python', + target: '_self', + }, + ], + }, + { + type: 'dropdown', + label: 'SDKs', + position: 'left', + items: [ + { + label: 'Java Slack SDK', + to: 'https://tools.slack.dev/java-slack-sdk/', + target: '_self', + }, + { + label: 'Node Slack SDK', + to: 'https://tools.slack.dev/node-slack-sdk/', + target: '_self', + }, + { + label: 'Python Slack SDK', + to: 'https://tools.slack.dev/python-slack-sdk/', + target: '_self', + }, + { + label: 'Deno Slack SDK', + to: 'https://api.slack.com/automation/quickstart', + target: '_self', + }, + ], + }, + { + type: 'dropdown', + label: 'Community', + position: 'left', + items: [ + { + label: 'Community tools', + to: 'https://tools.slack.dev/community-tools', + target: '_self', + }, + { + label: 'Slack Community', + to: 'https://slackcommunity.com/', + target: '_self', + }, + ], + }, + { + to: 'https://api.slack.com/docs', + label: 'API Docs', + target: '_self', + }, + { + 'aria-label': 'GitHub Repository', + className: 'navbar-github-link', + href: 'https://github.com/slackapi', + position: 'right', + target: '_self', + }, + ], +}; + +module.exports = navbar; From a839aaf9f1f1ddd75b2e9b3628ac1f59c9f502fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:18:48 -0400 Subject: [PATCH 11/17] chore(deps-dev): bump stylelint from 16.9.0 to 16.10.0 in /docs (#2312) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package-lock.json | 136 +++++++++++++++++++++-------------------- docs/package.json | 2 +- 2 files changed, 72 insertions(+), 66 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 913b4c790..51cad0622 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -22,7 +22,7 @@ "devDependencies": { "@docusaurus/module-type-aliases": "3.5.2", "@docusaurus/types": "3.5.2", - "stylelint": "^16.9.0", + "stylelint": "^16.10.0", "stylelint-config-standard": "^36.0.1" }, "engines": { @@ -4966,9 +4966,10 @@ } }, "node_modules/css-functions-list": { - "version": "3.2.2", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz", + "integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12 || >=16" } @@ -5692,10 +5693,11 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.3.6", - "license": "MIT", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -6516,9 +6518,10 @@ } }, "node_modules/file-entry-cache": { - "version": "9.0.0", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz", + "integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==", "dev": true, - "license": "MIT", "dependencies": { "flat-cache": "^5.0.0" }, @@ -6677,8 +6680,9 @@ }, "node_modules/flat-cache": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz", + "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==", "dev": true, - "license": "MIT", "dependencies": { "flatted": "^3.3.1", "keyv": "^4.5.4" @@ -6689,8 +6693,9 @@ }, "node_modules/flatted": { "version": "3.3.1", - "dev": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true }, "node_modules/follow-redirects": { "version": "1.15.6", @@ -10433,8 +10438,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "license": "MIT" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -10891,8 +10897,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "license": "ISC" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -10979,9 +10986,9 @@ } }, "node_modules/postcss": { - "version": "8.4.44", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.44.tgz", - "integrity": "sha512-Aweb9unOEpQ3ezu4Q00DPvvM2ZTUitJdNKeP/+uQgr1IBIqu574IaZoURId7BKtWMREwzKa9OgzPzezWGPWFQw==", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "funding": [ { "type": "opencollective", @@ -10998,8 +11005,8 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -11452,7 +11459,9 @@ "dev": true }, "node_modules/postcss-safe-parser": { - "version": "7.0.0", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", "dev": true, "funding": [ { @@ -11468,7 +11477,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "engines": { "node": ">=18.0" }, @@ -12610,11 +12618,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, "node_modules/send/node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -12931,8 +12934,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "license": "BSD-3-Clause", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "engines": { "node": ">=0.10.0" } @@ -13138,9 +13142,9 @@ } }, "node_modules/stylelint": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.9.0.tgz", - "integrity": "sha512-31Nm3WjxGOBGpQqF43o3wO9L5AC36TPIe6030Lnm13H3vDMTcS21DrLh69bMX+DBilKqMMVLian4iG6ybBoNRQ==", + "version": "16.10.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.10.0.tgz", + "integrity": "sha512-z/8X2rZ52dt2c0stVwI9QL2AFJhLhbPkyfpDFcizs200V/g7v+UYY6SNcB9hKOLcDDX/yGLDsY/pX08sLkz9xQ==", "dev": true, "funding": [ { @@ -13161,17 +13165,17 @@ "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", - "css-functions-list": "^3.2.2", - "css-tree": "^2.3.1", - "debug": "^4.3.6", + "css-functions-list": "^3.2.3", + "css-tree": "^3.0.0", + "debug": "^4.3.7", "fast-glob": "^3.3.2", "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^9.0.0", + "file-entry-cache": "^9.1.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.3.1", - "ignore": "^5.3.2", + "ignore": "^6.0.2", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", "known-css-properties": "^0.34.0", @@ -13180,14 +13184,13 @@ "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "picocolors": "^1.0.1", - "postcss": "^8.4.41", + "postcss": "^8.4.47", "postcss-resolve-nested-selector": "^0.1.6", - "postcss-safe-parser": "^7.0.0", + "postcss-safe-parser": "^7.0.1", "postcss-selector-parser": "^6.1.2", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", - "strip-ansi": "^7.1.0", "supports-hyperlinks": "^3.1.0", "svg-tags": "^1.0.0", "table": "^6.8.2", @@ -13275,11 +13278,39 @@ } } }, + "node_modules/stylelint/node_modules/css-tree": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.0.0.tgz", + "integrity": "sha512-o88DVQ6GzsABn1+6+zo2ct801dBO5OASVyxbbvA2W20ue2puSh/VOuqUj90eUeMSX/xqGqBmOKiRQN7tJOuBXw==", + "dev": true, + "dependencies": { + "mdn-data": "2.10.0", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/stylelint/node_modules/emoji-regex": { "version": "8.0.0", "dev": true, "license": "MIT" }, + "node_modules/stylelint/node_modules/ignore": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz", + "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/stylelint/node_modules/mdn-data": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.10.0.tgz", + "integrity": "sha512-qq7C3EtK3yJXMwz1zAab65pjl+UhohqMOctTgcqjLOWABqmwj+me02LSsCuEUxnst9X1lCBpoE0WArGKgdGDzw==", + "dev": true + }, "node_modules/stylelint/node_modules/resolve-from": { "version": "5.0.0", "dev": true, @@ -13312,31 +13343,6 @@ "node": ">=8" } }, - "node_modules/stylelint/node_modules/strip-ansi": { - "version": "7.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/stylelint/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/supports-color": { "version": "7.2.0", "license": "MIT", diff --git a/docs/package.json b/docs/package.json index 0d07ca10a..3beba2f94 100644 --- a/docs/package.json +++ b/docs/package.json @@ -28,7 +28,7 @@ "devDependencies": { "@docusaurus/module-type-aliases": "3.5.2", "@docusaurus/types": "3.5.2", - "stylelint": "^16.9.0", + "stylelint": "^16.10.0", "stylelint-config-standard": "^36.0.1" }, "browserslist": { From a17ec04976a901e2050ca1bafcfeca08474d6b09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:21:19 -0400 Subject: [PATCH 12/17] chore(deps): bump @mdx-js/react from 3.0.1 to 3.1.0 in /docs (#2313) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/package-lock.json | 7 ++++--- docs/package.json | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 51cad0622..50db73f50 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -11,7 +11,7 @@ "@docusaurus/core": "3.5.2", "@docusaurus/plugin-client-redirects": "^3.5.2", "@docusaurus/preset-classic": "3.5.2", - "@mdx-js/react": "^3.0.0", + "@mdx-js/react": "^3.1.0", "clsx": "^2.0.0", "css-minimizer-webpack-plugin": "^7.0.0", "docusaurus-theme-github-codeblock": "^2.0.2", @@ -2947,8 +2947,9 @@ } }, "node_modules/@mdx-js/react": { - "version": "3.0.1", - "license": "MIT", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz", + "integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==", "dependencies": { "@types/mdx": "^2.0.0" }, diff --git a/docs/package.json b/docs/package.json index 3beba2f94..81862610d 100644 --- a/docs/package.json +++ b/docs/package.json @@ -17,7 +17,7 @@ "@docusaurus/core": "3.5.2", "@docusaurus/plugin-client-redirects": "^3.5.2", "@docusaurus/preset-classic": "3.5.2", - "@mdx-js/react": "^3.0.0", + "@mdx-js/react": "^3.1.0", "clsx": "^2.0.0", "css-minimizer-webpack-plugin": "^7.0.0", "docusaurus-theme-github-codeblock": "^2.0.2", From 9bcc68025c5c1e30c0b82248cb25204905844a9c Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Fri, 1 Nov 2024 14:56:40 -0400 Subject: [PATCH 13/17] Publish `@slack/bolt@4.1.0` (#2314) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7f23f3186..371313348 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@slack/bolt", - "version": "4.0.1", + "version": "4.1.0", "description": "A framework for building Slack apps, fast.", "author": "Slack Technologies, LLC", "license": "MIT", From 3d7f242755f1924385fbc0ff0962c4b9aead30f4 Mon Sep 17 00:00:00 2001 From: Luke Russell <31357343+lukegalbraithrussell@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:34:36 -0700 Subject: [PATCH 14/17] Docs: agents and assistants (#2295) Co-authored-by: Alissa Renz --- docs/content/concepts/assistant.md | 175 +++++++++++++++++++++++++++++ docs/content/reference.md | 22 ++++ docs/sidebars.js | 1 + 3 files changed, 198 insertions(+) create mode 100644 docs/content/concepts/assistant.md diff --git a/docs/content/concepts/assistant.md b/docs/content/concepts/assistant.md new file mode 100644 index 000000000..7a878220e --- /dev/null +++ b/docs/content/concepts/assistant.md @@ -0,0 +1,175 @@ +--- +title: Agents & Assistants +lang: en +slug: /concepts/assistant +--- + +:::info[This feature requires a paid plan] +If you don't have a paid workspace for development, you can join the [Developer Program](https://api.slack.com/developer-program) and provision a sandbox with access to all Slack features for free. +::: + +Agents and assistants comprise a new messaging experience for Slack. If you're unfamiliar with using agents and assistants within Slack, you'll want to read the [API documentation on the subject](https://api.slack.com/docs/apps/ai). Then come back here to implement them with Bolt! + +## Configuring your app to support assistants + +1. Within [App Settings](https://api.slack.com/apps), enable the **Agents & Assistants** feature. + +2. Within the App Settings **OAuth & Permissions** page, add the following scopes: + * [`assistant:write`](https://api.slack.com/scopes/assistant:write) + * [`chat:write`](https://api.slack.com/scopes/chat:write) + * [`im:history`](https://api.slack.com/scopes/im:history) + +3. Within the App Settings **Event Subscriptions** page, subscribe to the following events: + * [`assistant_thread_started`](https://api.slack.com/events/assistant_thread_started) + * [`assistant_thread_context_changed`](https://api.slack.com/events/assistant_thread_context_changed) + * [`message.im`](https://api.slack.com/events/message.im) + +:::info +You _could_ implement your own assistants by [listening](/concepts/event-listening) for the `assistant_thread_started`, `assistant_thread_context_changed`, and `message.im` events. That being said, using the `Assistant` class will streamline the process. And we already wrote this nice guide for you! +::: + +## The `Assistant` class instance + +The [`Assistant`](/reference#the-assistantconfig-configuration-object) can be used to handle the incoming events expected from a user interacting with an assistant in Slack. A typical flow would look like: + +1. [The user starts a thread](#handling-new-thread). The `Assistant` class handles the incoming [`assistant_thread_started`](https://api.slack.com/events/assistant_thread_started) event. +2. [The thread context may change at any point](#handling-thread-context-changes). The `Assistant` class can handle any incoming [`assistant_thread_context_changed`](https://api.slack.com/events/assistant_thread_context_changed) events. The class also provides a default `context` store to keep track of thread context changes as the user moves through Slack. +3. [The user responds](#handling-user-response). The `Assistant` class handles the incoming [`message.im`](https://api.slack.com/events/message.im) event. + +```ts +const assistant = new Assistant({ + // If you prefer to not use the provided DefaultThreadContextStore, + // you can use your own optional threadContextStore + threadContextStore: { + get: async ({ context, client, payload }) => {}, + save: async ({ context, client, payload }) => {}, + }, + threadStarted: async ({ say, saveThreadContext, setStatus, setSuggestedPrompts, setTitle }) => {}, + // threadContextChanged is optional + // If you use your own optional threadContextStore you likely won't use it + threadContextChanged: async ({ say, setStatus, setSuggestedPrompts, setTitle }) => {}, + userMessage: async ({ say, getThreadContext, setStatus, setSuggestedPrompts, setTitle }) => {}, +}); +``` + +While the `assistant_thread_started` and `assistant_thread_context_changed` events do provide Slack-client thread context information, the `message.im` event does not. Any subsequent user message events won't contain thread context data. For that reason, Bolt not only provides a way to store thread context — the `threadContextStore` property — but it also provides a `DefaultThreadContextStore` instance that is utilized by default. This implementation relies on storing and retrieving [message metadata](https://api.slack.com/metadata/using) as the user interacts with the assistant. + +If you do provide your own `threadContextStore` property, it must feature `get` and `save` methods. + +:::tip +Be sure to give the [assistants reference docs](/reference#assistants) a look! +::: + +## Handling a new thread {#handling-new-thread} + +When the user opens a new thread with your assistant, the [`assistant_thread_started`](https://api.slack.com/events/assistant_thread_started) event will be sent to your app. Capture this with the `threadStarted` handler to allow your app to respond. + +In the example below, the app is sending a message — containing thread context [message metadata](https://api.slack.com/metadata/using) behind the scenes — to the user, along with a single [prompt](https://api.slack.com/methods/assistant.threads.setSuggestedPrompts). + +```js +... + threadStarted: async ({ event, say, setSuggestedPrompts, saveThreadContext }) => { + const { context } = event.assistant_thread; + + await say('Hi, how can I help?'); + + const prompts = [{ + title: 'Fun Slack fact', + message: 'Give me a fun fact about Slack, please!', + }]; + + // Provide the user up to 4 optional, preset prompts to choose from. + await setSuggestedPrompts({ prompts, title: 'Here are some suggested options:' }); + }, +... +``` + +:::tip +When a user opens an assistant thread while in a channel, the channel info is stored as the thread's `AssistantThreadContext` data. You can grab that info using the `getThreadContext()` utility, as subsequent user message event payloads won't include the channel info. +::: + +## Handling thread context changes {#handling-thread-context-changes} + +When the user switches channels, the [`assistant_thread_context_changed`](https://api.slack.com/events/assistant_thread_context_changed) event will be sent to your app. Capture this with the `threadContextChanged` handler. + +```js +... + threadContextChanged: async ({ saveThreadContext }) => { + await saveThreadContext(); + }, +... +``` + +If you use the built-in `AssistantThreadContextStore` without any custom configuration, you can skip this — the updated thread context data is automatically saved as [message metadata](https://api.slack.com/metadata/using) on the first reply from the assistant bot. + +## Handling the user response {#handling-user-response} + +When the user messages your assistant, the [`message.im`](https://api.slack.com/events/message.im) event will be sent to your app. Capture this with the `userMessage` handler. + +Messages sent to the assistant do not contain a [subtype](https://api.slack.com/events/message#subtypes) and must be deduced based on their shape and any provided [message metadata](https://api.slack.com/metadata/using). + +There are three [utilities](/reference#the-assistantconfig-configuration-object) that are particularly useful in curating the user experience: +* `say` +* `setTitle` +* `setStatus` + +The following example uses the [OpenAI API client](https://platform.openai.com/docs/api-reference/introduction), but you can substitute it with the AI client of your choice. + + ```js + ... + userMessage: async ({ client, message, say, setTitle, setStatus }) => { + const { channel, thread_ts } = message; + + try { + // Set the status of the Assistant to give the appearance of active processing. + await setStatus('is typing..'); + + // Retrieve the Assistant thread history for context of question being asked + const thread = await client.conversations.replies({ + channel, + ts: thread_ts, + oldest: thread_ts, + }); + + // Prepare and tag each message for LLM processing + const userMessage = { role: 'user', content: message.text }; + const threadHistory = thread.messages.map((m) => { + const role = m.bot_id ? 'assistant' : 'user'; + return { role, content: m.text }; + }); + + const messages = [ + { role: 'system', content: DEFAULT_SYSTEM_CONTENT }, + ...threadHistory, + userMessage, + ]; + + // Send message history and newest question to LLM + const llmResponse = await openai.chat.completions.create({ + model: 'gpt-4o-mini', + n: 1, + messages, + }); + + // Provide a response to the user + await say(llmResponse.choices[0].message.content); + + } catch (e) { + console.error(e); + + // Send message to advise user and clear processing status if a failure occurs + await say('Sorry, something went wrong!'); + } + }, +}); + +app.assistant(assistant); +``` + +## Full example : App Agent & Assistant Template + +Below is the `app.js` file of the [App Agent & Assistant Template repo](https://github.com/slack-samples/bolt-js-assistant-template/) we've created for you to build off of. + +```js reference title="app.js" +https://github.com/slack-samples/bolt-js-assistant-template/blob/main/app.js +``` \ No newline at end of file diff --git a/docs/content/reference.md b/docs/content/reference.md index a71dab74b..7b0f0324b 100644 --- a/docs/content/reference.md +++ b/docs/content/reference.md @@ -151,6 +151,28 @@ Bolt's client is an instance of `WebClient` from the [Node Slack SDK](https://to ::: +## Agents & Assistants + +### The `AssistantConfig` configuration object + +| Property | Required? | Description | +|---|---|---| +|`threadContextStore` | Optional | When provided, must have the required methods to get and save thread context, which will override the `getThreadContext` and `saveThreadContext` utilities.

If not provided, a `DefaultAssistantContextStore` instance is used. +| `threadStarted` | Required | Executes when the user opens the assistant container or otherwise begins a new chat, thus sending the [`assistant_thread_started`](https://api.slack.com/events/assistant_thread_started) event. +| `threadContextChanged` | Optional | Executes when a user switches channels while the assistant container is open, thus sending the [`assistant_thread_context_changed`](https://api.slack.com/events/assistant_thread_context_changed) event.

If not provided, context will be saved using the AssistantContextStore's `save` method (either the `DefaultAssistantContextStore` instance or provided `threadContextStore`). +| `userMessage` | Required | Executes when a [message](https://api.slack.com/events/message) is received, thus sending the [`message.im`](https://api.slack.com/events/message.im) event. These messages do not contain a subtype and must be deduced based on their shape and metadata (if provided). Bolt handles this deduction out of the box for those using the `Assistant` class. + +### Assistant utilities + +Utility | Description +|---|---| +| `getThreadContext` | Alias for `AssistantContextStore.get()` method. Executed if custom `AssistantContextStore` value is provided.

If not provided, the `DefaultAssistantContextStore` instance will retrieve the most recent context saved to the instance. +| `saveThreadContext` | Alias for `AssistantContextStore.save()`. Executed if `AssistantContextStore` value is provided.

If not provided, the `DefaultAssistantContextStore` instance will save the `assistant_thread.context` to the instance and attach it to the initial assistant message that was sent to the thread. +| `say(message: string)` | Alias for the `postMessage` method.

Sends a message to the current assistant thread. +| `setTitle(title: string)` | [Sets the title](https://api.slack.com/methods/assistant.threads.setTitle) of the assistant thread to capture the initial topic/question. +| `setStatus(status: string)` | Sets the [status](https://api.slack.com/methods/assistant.threads.setStatus) of the assistant to give the appearance of active processing. +| `setSuggestedPrompts({ prompts: [{ title: string; message: string; }] })` | Provides the user up to 4 optional, preset [prompts](https://api.slack.com/methods/assistant.threads.setSuggestedPrompts) to choose from. + ## Framework error types Bolt includes a set of error types to make errors easier to handle, with more specific contextual information. Below is a non-exhaustive list of error codes you may run into during development: diff --git a/docs/sidebars.js b/docs/sidebars.js index e5442a016..9bbd80361 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -33,6 +33,7 @@ const sidebars = { 'concepts/publishing-views', ], }, + 'concepts/assistant', 'concepts/custom-steps', { type: 'category', From 015a91836d97e605d40e0836bf02830be61132fd Mon Sep 17 00:00:00 2001 From: "slackapi[bot]" <186980925+slackapi[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 17:19:11 -0700 Subject: [PATCH 15/17] Docs: CSS fixes and their propagations (#2315) Co-authored-by: slackapi[bot] <186980925+slackapi[bot]@users.noreply.github.com> Co-authored-by: @zimeg --- docs/navbarConfig.js | 1 + docs/src/css/custom.css | 126 ++++++++++++++++++++++++++-------------- 2 files changed, 82 insertions(+), 45 deletions(-) diff --git a/docs/navbarConfig.js b/docs/navbarConfig.js index f4277367a..e9deaab7d 100644 --- a/docs/navbarConfig.js +++ b/docs/navbarConfig.js @@ -2,6 +2,7 @@ const navbar = { title: 'Slack Developer Tools', logo: { src: 'img/slack-logo.svg', + href: 'https://tools.slack.dev', }, items: [ { diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index c6cc91b1a..85adb3538 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -1,32 +1,16 @@ -/** - * Any CSS included here will be global. The classic template - * bundles Infima by default. Infima is a CSS framework designed to - * work well for content-centric websites. - */ - :root { /* set hex colors here pls */ --aubergine: #4a154b; - /* aubergine-active is used in light mode. use something like #853c8c if you use as a link vs black text ( 3:1 contr) */ --aubergine-active: #7c3085; - - /* aubergine-light is used in dark mode. #b681b5 is another one. i just made both up */ - --aubergine-light: #ce70cc; - /* horchata is that beige color we use a lot */ --horchata: #f4ede4; - - /* slack-blue is 36C5F0. used for dark-mode links */ - --slack-link: #36c5f0; - --slack-blue: #36c5f0; + /* cloud blue from slack.dev. used for dark-mode links */ + --slack-cloud-blue: #1ab9ff; /* slack marketing color for links 1264A3. used for light-mode links */ --slack-dark-blue: #1264a3; - - --grey: #868686; --dim: #eef2f6; - --white: #ffffff; } /* resets striped tables that hurt me eyes */ @@ -34,13 +18,13 @@ table tr:nth-child(even) { background-color: inherit; } -p a { - text-decoration: underline; +/* changing the links to blue for accessibility */ +p a, .markdown a { + color: var(--slack-cloud-blue); } -.markdown a { - color: var(--slack-link); - text-decoration: underline; +a:hover { + color: var(--slack-cloud-blue); } /* adjusting for light and dark modes */ @@ -48,29 +32,41 @@ p a { --docusaurus-highlighted-code-line-bg: var(--dim); --ifm-color-primary: var(--aubergine-active); --ifm-footer-background-color: var(--horchata); - --slack-link: var(--slack-dark-blue); + --ifm-footer-color: black; + --slack-cloud-blue: var(--slack-dark-blue); + --ifm-table-stripe-background: var(--horchata); } [data-theme="dark"] { - --ifm-color-primary: var(--aubergine-light); - --ifm-navbar-background-color: var(--aubergine); - --ifm-footer-background-color: var(--aubergine); - --slack-link: var(--slack-blue); -} - -html[data-theme="dark"] { --docusaurus-highlighted-code-line-bg: rgb(0 0 0 / 30%); + --ifm-color-primary: var(--slack-cloud-blue); + --ifm-navbar-background-color: var(--aubergine) !important; + --ifm-footer-background-color: var(--aubergine) !important; + --ifm-footer-color: white; } -/* bolding Toc for contrast */ +/* bolding ToC for contrast */ .table-of-contents__link--active { font-weight: bold; } -/* only uncomment for home page -- colors white space on v tall screens */ -/* .main-wrapper { - background: var(--horchata); -} */ +/* removing ToC line */ +.table-of-contents__left-border { + border-left: none !important; +} + +/* increasing name of SDK in sidebar */ +.sidebar-title { + font-size: 1.25em; /* Adjust the size as needed */ + font-weight: bold; + color: #000; +} + +/* removing sidebar line and adding space to match ToC */ +.theme-doc-sidebar-container { + border-right: none !important; + margin-right: 2rem; +} /* announcement bar up top */ div[class^="announcementBar_"] { @@ -79,8 +75,7 @@ div[class^="announcementBar_"] { background: var(--horchata); } -/* navbar */ - +/* navbar github link */ .navbar-github-link { width: 32px; height: 32px; @@ -108,14 +103,55 @@ html[data-theme="dark"] .navbar-github-link::before { no-repeat; } -.sidebar-title { - font-size: 1.25em; /* Adjust the size as needed */ - font-weight: bold; - color: #000; -} - +/* Delineate tab blocks */ .tabs-container { - border: 2px solid var(--ifm-hr-background-color); /* Adjust the color and thickness as needed */ + border: 1px solid var(--ifm-color-primary); /* Adjust the color and thickness as needed */ border-radius: 5px; /* To give rounded corners */ padding: 0.5em; /* To add spacing inside the tab */ } + +/* Docs code bubbles */ +[data-theme="light"] { + --code-link-background: #CFE9FE; + --code-link-text: rgb(21, 50, 59); + + --method-link-background: #CDEFC4; + --method-link-text: rgb(0, 41, 0); + + --scope-link-background: #FBF3E0; + --scope-link-text: rgb(63, 46, 0); + + --event-link-background: #FDDDE3; + --event-link-text: rgb(74, 21, 75); +} + +[data-theme="dark"] { + --code-link-text: white; + --method-link-text: white; + --scope-link-text: white; + --event-link-text: white; + --code-link-background: #1AB9FF50; + --method-link-background: #41B65850; + --scope-link-background: #FCC00350; + --event-link-background: #E3066A50; +} + +a code { + background-color: var(--code-link-background); + color: var(--code-link-text); +} + +a[href^="https://api.slack.com/methods"] > code { + background-color: var(--method-link-background); + color: var(--method-link-text); +} + +a[href^="https://api.slack.com/scopes"] > code { + background-color: var(--scope-link-background); + color: var(--scope-link-text); +} + +a[href^="https://api.slack.com/events"] > code { + background-color: var(--event-link-background); + color: var(--event-link-text); +} \ No newline at end of file From 874b8e702984a965866b1b41eaa8f93de9acc5e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:46:27 -0500 Subject: [PATCH 16/17] chore(deps-dev): bump @types/node from 22.8.1 to 22.8.7 (#2320) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 371313348..0ff1e3110 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@tsconfig/node18": "^18.2.4", "@types/chai": "^4.1.7", "@types/mocha": "^10.0.1", - "@types/node": "22.8.1", + "@types/node": "22.8.7", "@types/sinon": "^7.0.11", "@types/tsscmp": "^1.0.0", "c8": "^10.1.2", From bfe9277704131909aa85a71c17cee4dc7d08c8e5 Mon Sep 17 00:00:00 2001 From: William Bergamin Date: Mon, 4 Nov 2024 15:57:36 -0500 Subject: [PATCH 17/17] Update test/unit/helpers/events.ts Co-authored-by: Fil Maj --- test/unit/helpers/events.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/helpers/events.ts b/test/unit/helpers/events.ts index 5fc3c7a1a..d632b6539 100644 --- a/test/unit/helpers/events.ts +++ b/test/unit/helpers/events.ts @@ -353,7 +353,7 @@ export function createDummyCustomFunctionMiddlewareArgs< options?: Options; } = { callbackId: 'reverse', inputs: { stringToReverse: 'hello' }, options: { autoAcknowledge: true } as Options }, ): SlackCustomFunctionMiddlewareArgs { - data.callbackId = data.callbackId ? data.callbackId : 'reverse'; + data.callbackId = data.callbackId || 'reverse'; data.inputs = data.inputs ? data.inputs : { stringToReverse: 'hello' }; data.options = data.options ? data.options : ({ autoAcknowledge: true } as Options); const testFunction = {