SlackのHome tabがBeta版で使えるようになっていたのでSlack BoltでTODOアプリを作ってみました
こんにちは。最近RELATIONSにジョインしました鍋山です。
RELATIONSではSlackを連絡手段として使っていて、エンジニアや大多数を占める非エンジニア全員で活発にやりとりしてます。
さて、僕自身がSlackに入門して1ヶ月ほど経ちましたので、どんなことができるのかを試してみる目的でとりあえずTODOアプリを作ってみました。
今回使用した機能はHome tabというBeta版(2019/11/11時点)でリリースされた、Slack上で表示できるWEBアプリライクな機能です。
実際に便利なものだと思っているのですが、Beta版なので今後どうなるかはわかりません。
Home tabとは
従来はアプリのアカウントを選択すると、DMができるようになっていました。
同じページで「ホーム」タブが追加されるようになります。
「ホーム」タブを表示するには、設定ページのFeaturesのApp Homeの設定をオンにする必要があります。(後述します)
参考ページ:Home is where the tabs are | Slack
Block Kit Builderでも対応
Block kit BuilderでもHome tabの対応がされており、「App Home Preview」を選択することができます。 そうすると、GUIの操作でHome tab用のblockを構築していくことができます。
参考ページ:https://api.slack.com/tools/block-kit-builder?mode=appHome
サインインしないと見られない可能性があります
Slack BoltでTODOアプリを作ってみる
今回はNode.jsでBoltというSlackのアプリを開発しやすくしたライブラリを使って開発してみました。 Boltについては公式ドキュメント(https://slack.dev/bolt/ja-jp/tutorial/getting-started)を参考にしています。
完成したアプリの動作はこちらのようになりました。
完成後のコードはこちらになります。
今回はmacOSで開発しています。
Home tabを使う為の設定
Boltを使用する為なのか、botのscopeが必要となりますが、今回のTODOアプリでは対話は発生しません。
今回の最低限の設定はこちらのようになりました。
Block Kit BuilderでHome tab用のblockを作る
Block KitというのはSlackアプリのUIフレームワークとのことです。
blockはSlackアプリを構築する際に機能する再利用可能なコンポーネントです。
Block Kit BuilderでHome tabで表示するUIを作ると、実際のコードに埋め込む為のオブジェクトが生成されていますのでコピーして使用することができます。
参考ページ:https://api.slack.com/tools/block-kit-builder?mode=appHome
サインインしないと見られない可能性があります
TODOアプリでは固定された部分と、動的に変化する一覧部分がありましたので二つに切り分けて作りました。
固定されたblock部分。
内容を仮とした動的に変化するblock部分。
利用者が「ホーム」タブを選択した際に、Home tabのviewを表示する
ここからは具体的なコードを示しますが、より全体を見たい方はGitHubのリポジトリ(https://github.com/relationslab/slack-home-todo)をご覧ください。 本記事では要所要所のみ切り取って紹介させていただきます。
「ホーム」タブを選択した際にapp_home_tab
イベントを受け取り、Home tab内容を表示します。
ここでのapp_home_tab
というイベント名はHome tab用のイベントのようです。
// ホームタブを開いた際に発生するイベントをキャッチする app.event('app_home_opened', async ({ event, context }) => { if ('home' === event.tab) { // HomeTabを表示する await app.client.views.publish({ token: context.botToken, user_id: event.user, view: {/* home用のオブジェクトを渡す */}, }); } });
ここではHome tabを表示する際にviews.publish
メソッドを使用していますが、更新する場合も同じようにviews.publish
メソッドを使います。(後述します)
Block Kit Builderでモーダル用のblockを作る
Home tab用のblockを作ったように、モーダル用のblockを作ります。
先ほどとは違い、左上のプルダウンメニューから「Modal Preview」に切り替えるようにする必要があります。
利用者が「TODOを作る」ボタンをクリックした際に、モーダルを表示する
Home tabから「TODOを作る」ボタンをクリックした際に、そのアクションを受け取り、モーダルを表示させます。
ここでは、Home tabのblockのaction_id
にアクションIDを埋め込んでいます。
「TODOを作る」のblockにはhome_todo_add
というアクションIDを埋め込みましたので、そのアクションをキャッチする必要があります。
// HomeTabから「TODOを作る」を選択した場合、モーダルを表示させる app.action('home_todo_add', async ({ body, ack, context }) => { ack(); // モーダルを表示させる await app.client.views.open({ token: context.botToken, trigger_id: body.trigger_id, view: {/* モーダル用のオブジェクトを渡す */}, }); });
利用者が「この内容で作成する」ボタンをクリックした際に、入力内容を取得してHome tabのviewを更新する
モーダルからTODOの内容を記入後、確定させる為に「この内容で作成する」をクリックした際に、そのイベントを受け取り、Home tabのTODO一覧を更新します。
モーダルの場合は、モーダルのblockに埋め込んだcallback_id
をイベント名としてキャッチする必要があります。
新規TODOの作成のモーダルにはmodal_todo_add_done
というcallback_id
を埋め込みましたので、そのイベントをキャッチします。
// 新規TODOの作成モーダルで「この内容で作成する」を選択した場合 app.view('modal_todo_add_done', async ({ ack, body, context, view }) => { ack(); // モーダル入力値取得 const val = _.get(view.state.values, ['todo_input', 'input_value', 'value']); // HomeTabを更新する await app.client.views.publish({ token: context.botToken, user_id: body.user.id, view: {/* Home tab用のオブジェクトを渡す */}, }); });
利用者がTODO一覧から「完了」ボタンをクリックした際に、対象に斜線を付けてHome tabのviewを更新する
Home tabの動的内容となるTODO一覧から「完了」ボタンをクリックした際に、Home tabeからのアクションを受け取り、対象に斜線を付けてHome tabのTODO一覧を更新します。
Home tabの「完了」のアクションIDにはhome_todo_complete
を埋め込んでいますので、それをキャッチします。
// HomeTabのTODO一覧からタスクの「完了」を選択した場合 app.action('home_todo_complete', async ({ ack, body, context }) => { ack(); // HomeTabを更新する await app.client.views.publish({ token: context.botToken, user_id: body.user.id, view: {/* Home tab用のオブジェクトを渡す */}, }); });
完成!
ワークスペース単位で管理するTODOアプリが完成しました!
完成後のコードはこちらになります。
本記事に載せていないコードもありますので、実際に試してみたい方はGitHubのリポジトリを見てみてください。
試してみた感想
だいぶエンドユーザーに寄り添った機能だと思いました。
社内用のボットを作ろうとしていたのですが、最初にエンドユーザーがアプリ/ボットを操作する際のトリガーをどうしようかと悩んでいたところにHome tab機能が出てきました。
ちょっとこれはすごいかも!試してみよう!と思ったことが今回のTODOアプリを作ったきっかけでした。
Beta版としてのリリースということからかモバイルアプリでは使用できない機能ですが、まだ機能拡張があるのではないかと今後の様子を注視したいと思いました。