今更ながらSlackBotを作ってみた：Interactive Components

前回、前々回に引き続き、SlackBotをカスタマイズしていきます。
　[今更ながらSlackBotを作ってみた](https://qiita.com/poruruba/items/ac147fbf0de92f6fad42)
　[今更ながらSlackBotを作ってみた：Slach Commands](https://qiita.com/poruruba/items/b386247d8ace78488f67)

今回は、Interactive Componentsです。
絵文字や文字装飾でもある程度表現できますが、やはりボタンやセレクトや画像を使った方がより直感的にやりとりできます。

前々回の環境をそのまま使います。まだの方はぜひご参照ください。


(参考情報)
Making messages interactive
　https://api.slack.com/interactive-messages

# Interactive Componentsを有効化する

いつものslack apiのSettings－Basic Informationから行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/75861767-82a4-a04a-7fb0-26fc62b7c006.png)
 
Interactive Componentsを選択し、InteractivityをOnにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/44f1e2da-6530-5e72-efb4-156f1a7f3e4f.png)

入力欄「Request URL」に立ち上げたサーバのURLをフルパスで入力します。「/slack-testbot-cmd」の方です。最後にSave Changesボタンを押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/6b3a086a-dd5c-d03f-e89c-b11cecaff083.png)

これで、表現力豊かなUIからの通知を受けることができました。

# UIを作成する

UIを配置していきたいのですが、便利なツールがあります。
GUIで配置結果を見ながら作れるので便利です。（少々使いにくいですが）

Block Kit Builder
　https://api.slack.com/tools/block-kit-builder

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/a013a0de-1eac-9647-aee5-20316ef5f033.png)
 
以下のようなUIを作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/5d0c3c98-f6a4-f8c5-33da-5a9e6264299c.png)


```
[
	{
		"type": "actions",
		"elements": [
			{
				"type": "static_select",
				"placeholder": {
					"type": "plain_text",
					"text": "Select an item"
				},
                "action_id": "select1",
				"options": [
					{
						"text": {
							"type": "plain_text",
							"text": "アイテム1"
						},
						"value": "item1"
					},
					{
						"text": {
							"type": "plain_text",
							"text": "アイテム2"
						},
						"value": "item2"
					},
					{
						"text": {
							"type": "plain_text",
							"text": "アイテム3"
						},
						"value": "item3"
					}
				]
			}
        ]
    },
    {
        "type": "actions",
        "elements":[
            {
              "type": "button",
              "text": {
                "type": "plain_text",
                "text": "ボタン1"
              },
              "action_id": "button1"
            },
            {
              "type": "button",
              "text": {
                "type": "plain_text",
                "text": "ボタン2"
              },
              "action_id": "button2"
            }
		]
	}
]
```

#サーバ側の実装

その前に、Interactive ComponentsのUIを表示させるトリガーを用意します。
なんでもよいのですが、もう一つSlashCommandsを作って、それを呼び出すとUIを表示するようにしたいと思います。

例えば、以下のように、「/query」というコマンドを作ってみましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/b699e53e-872b-aa9d-1a74-101f0bf2b53a.png)

それではさっそく、サーバ側の実装です。
app.commandは変更で、それ以外は追加です。

```controllers\slack_testbot\index.js
app.command(async (body, web) =>{
    if(body.command == '/hi'){
        var hour = new Date().getHours();

        var greeting = 'こんにちは';
        if( 5 <= hour && hour <= 9 )
            greeting = 'おはよう';
        else if( 18 <= hour && hour < 5 )
            greeting = 'こんにちは';

        var message = {
            text: greeting + '！' + (body.text ? (' ' + body.text + " です。") : '')
        };
        app.responseMessage(body.response_url, message );
    }else if( body.command == '/query'){
        var message = {
            text: "選択肢を表示します。",
            blocks: blocks,
        };
        app.responseMessage(body.response_url, message );
    }
});

app.action(async (body, web) =>{
    var text = '';
    for( var i = 0 ; i < body.actions.length ; i++ ){
        var action = body.actions[i];
        text += action.action_id;
        if( action.type == 'static_select')
            text += 'の' + action.selected_option.value;
        text += 'が選択されました。\n';
    }
    var message = {
        text: text
    };
    app.responseMessage(body.response_url, message );
});

var blocks = [
	{
		"type": "actions",
		"elements": [
			{
				"type": "static_select",
				"placeholder": {
					"type": "plain_text",
					"text": "Select an item"
				},
                "action_id": "select1",
				"options": [
					{
						"text": {
							"type": "plain_text",
							"text": "アイテム1"
						},
						"value": "item1"
					},
					{
						"text": {
							"type": "plain_text",
							"text": "アイテム2"
						},
						"value": "item2"
					},
					{
						"text": {
							"type": "plain_text",
							"text": "アイテム3"
						},
						"value": "item3"
					}
				]
			}
        ]
    },
    {
        "type": "actions",
        "elements":[
            {
              "type": "button",
              "text": {
                "type": "plain_text",
                "text": "ボタン1"
              },
              "action_id": "button1"
            },
            {
              "type": "button",
              "text": {
                "type": "plain_text",
                "text": "ボタン2"
              },
              "action_id": "button2"
            }
		]
	}
];
```

app.commandにおいて、/queryが来たら、作成したUIを返すようにしています。
そして、ユーザによってUIの部品を選択すると、都度app.actionが呼び出されます。選択された部品名をレスポンスメッセージにして返しています。

ちなみに、今回のUIの場合は、UIを選択されたとき、以下のような応答がSlackから返ってきています。

選択肢が選択された場合

```
  "actions": [{
    "action_id": "select1",
    "block_id": "hTeDk",
    "selected_option": {
      "text": {
        "type": "plain_text",
        "text": "アイテム2",
        "emoji": true
      },
      "value": "item2"
    },
    "type": "static_select",
    "action_ts": "1557116165.623264"
  }]
```

ボタンがクリックされた場合

```
  "actions": [{
    "action_id": "button2",
    "block_id": "KEM",
    "text": {
      "type": "plain_text",
      "text": "ボタン2",
      "emoji": true
    },
    "type": "button",
    "value": "button2",
    "action_ts": "1557116194.565853"
  }]
```

# 動作確認

AndroidのSlackアプリから操作してみました。

/queryコマンドを入力すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/916cb7c0-d44e-f57c-af1f-dcb3305fe87a.png)

UIが表示されました。
解像度が小さいスマホで表示させたので、解像度が大きい場合は見え方が違うと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/1813be3a-cda6-bc37-4da6-242911fe8139.png)

選択肢を選択すると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/e8aa795e-26a7-7e84-a839-cf6b3eb0b4b7.png)

という感じに、レスポンスメッセージが返ってきました。

# 補足

UIの各部品が選択されるごとに、メッセージが通知されました。
次回は、ダイアログを紹介します。都度通知ではなくすべての入力完了時に通知されるようになります。

以上