Slackのマルチステップモーダルの画面遷移を試してみた
はじめに
Slack Advent Calendar 2019 2日目の記事です。
Slackの公式ブログで紹介されていた「2.マルチステップモーダル:情報の表示・収集がもっと簡単に」について、モーダルの画面遷移を実装して試してみました。
実際に、検索機能を設けたSlackアプリケーションのUIを作るために使っています(まだ開発中ですけど)。
大きく進化した Slack アプリツールキットのご紹介
https://slackhq.com/intl-ja-jp-introducing-a-dramatically-upgraded-slack-app-toolkit
上記紹介ページより、引用
モーダルとは Slack インターフェースの上に出てくるウィンドウのことです。このツールはさまざまなフォームでデータを集めたり、インタラクティブな選択肢や結果を表示したりするときにとても便利なものです。今回、開発者はカスタム情報やより複雑なものに対応できるよう、必要な数の画面を追加表示できるようになりました。これで長々とした bot とのやり取りをしなくて済むようになります!
マルチステップモーダルを試す際に参考にしたドキュメント
Slackアプリでのモーダルの使用 - Slack API
https://api.slack.com/surfaces/modals/using
Slackアプリケーションのモーダルはどんなものなのか。まず機能とAPIを知る上で読むと良いです。
モーダルビューの更新と多重表示 - Bolt API
https://slack.dev/bolt/ja-jp/concepts#updating-pushing-views
Bolt入門ガイドです。Boltフレームワークを使って、モーダルの実装をする際に、日本語による説明とサンプルコードから学べます。
Slack API 新機能を使ってアプリのホーム・ヴューを活用しよう?
https://qiita.com/girlie_mac/items/fae66bcc2ec3ccf25db6
日本語のApp Homeチュートリアルです。チュートリアルを通して、ノートアプリの開発をします。
Slackアプリの設定、モーダル(シングル)の実装を学べます。
マルチステップモーダルの画面遷移を試してみた
モーダルのオープンと view.push
, view.update
による画面遷移のコードについて紹介します。説明のために、画面遷移以外のフォームの値の参照などのコードは省いています。
なお、紹介するコードはこちらで全体を公開しています。
https://github.com/shoito/slack-app-examples
マルチステップの動きとしては、このようになっています(アニメーションGIFだとカクカクしてる...)。
ファイル構成としては、分かりやすいように以下のようにしています。
$ tree -L 2 . ├── README.md ├── appHome.js - App Homeを構成するUI定義 ├── index.js - アプリのメイン実装 ├── modals │ ├── detail.js - ステップ3を構成するUI定義 │ ├── detail_expand.js - ステップ3のview.updaet後のUIを構成するUI定義 │ ├── input.js - モーダルのステップ1を構成するUI定義 │ └── result.js - ステップ2を構成するUI定義 ├── package-lock.json └── package.json
まずは、App Home画面を表示するコードですが、以下のように app.event("app_home_opened", ...)
app_home_openedイベントをハンドリングします。 appHome()
ファンクションで appHome.js
に定義されているブロックを返しています。
app.event("app_home_opened", async ({ event, context, payload }) => { try { const result = await app.client.apiCall("views.publish", { token: context.botToken, user_id: event.user, view: appHome() }); } catch (e) { console.log(e); app.error(e); } });
App HomeはBlock Kit Builderで作ったJSONを返すようにしています。
18行目の action_id
はOpen modalボタンをクリックしたときのアクションの定義先のIDです。
module.exports = () => { return { type: "home", callback_id: "home_view", title: { type: "plain_text", text: "Modal" }, blocks: [ { type: "section", text: { type: "mrkdwn", text: "*Welcome!*" }, accessory: { type: "button", action_id: "open_modal_clicked", text: { type: "plain_text", text: "Open modal" } } } ] }; };
Open modalボタンがクリックされたときに、こちらのアクションがフックされます。
views.open
している部分で、modals/input.js
で定義されているモーダルを表示します。
app.action("open_modal_clicked", async ({ ack, body, context }) => { ack(); try { const result = await app.client.views.open({ token: context.botToken, trigger_id: body.trigger_id, view: inputModal() }); } catch (e) { console.log(e); app.error(e); } });
モーダルを閉じずに、画面遷移する場合は、 views.push
で新たなレイヤを構築します。
ここでは modals/result.js
で定義した画面が、前のモーダルの上に表示されます。
app.action("show_result_clicked", async ({ ack, body, context }) => { ack(); try { const result = await app.client.views.push({ token: context.botToken, trigger_id: body.trigger_id, view: resultModal() }); } catch (e) { console.log(e); app.error(e); } });
modals/details.js
では、 views.push
による画面の遷移ではなく、 views.update
による画面内の更新を行っています。
app.action("expand_clicked", async ({ ack, body, context }) => { ack(); try { const result = await app.client.views.update({ token: context.botToken, view_id: body.view.id, view: detailExpandModal() }); } catch (e) { console.log(e); app.error(e); } });
さいごに
今回 view.push
を使ったマルチステップモーダルのコードがなかなか見当たらなかったので、参考にシンプルなコードを紹介しました。
マルチステップモーダルにより、これまでSlackアプリケーションではできないと諦めていたインタラクションが実現できそうなので、個人的にとても嬉しい機能です。