11
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Bolt for JSでワークフロービルダーのオリジナルステップを実装する

Last updated at Posted at 2020-10-06

はじめに

Bolt for JSでは、Slackのワークフロービルダーで使えるWorkflow Stepsを実装することができます。(以下、Custom Stepと呼びます。)

~~リファレンスがありますが日本語化がまだのため、~~私が実装した経験から解説していきます。
日本語化されました!
https://slack.dev/bolt-js/ja-jp/concepts#steps

事前設定

前提としてSlackアプリを作成するのですが、アプリの作成は様々な記事があがっているのでそちらを参照してください。

Custom Stepを作成するために必要な設定は以下の2点です。

ワークスペースでWorkflow stepsの利用を許可する

ワークスペースの設定 > 権限 > アプリからのワークフロービルダーステップ
「ワークフロービルダーで、このワークスペースにインストールされたアプリのステップを表示する」にチェック。

設定1

アプリのWorkflow Steps

アプリのWorkflow Stepsの「Turn on workflow steps」をONの状態にします。
ON状態にすると、workflow.steps:executeのスコープが必ず追加されるため、アプリのReinstallが促されます。
Reinstallしておきましょう。

設定2

Stepsの「Add Step」から追加するStepを登録します。

設定3.png

  • Step name
    • 追加するCustom Stepの名前
  • Callback ID
    • あとで実装するCallback IDと一致させる

Create up to 10 custom steps for your app to be used within Workflow builder.

Custom Stepは1つのアプリに対して10こまでしか実装できないみたいですね。

実装していく

実装の基本の形は

app.js
const { App, WorkflowStep } = require('@slack/bolt');

const app = new App({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  token: process.env.SLACK_BOT_TOKEN,
});

const wsEdit = ({ ack, step, configure }) => {};
const wsSave = ({ ack, view, update }) => {};
const wsExecute= ({ step, complete, fail, client }) => {};

const ws = new WorkflowStep('custom_step', {
  edit: wsEdit,
  save: wsSave,
  execute: wsExecute,
});
app.step(ws);

です。
'custom_step'の部分が事前設定にあるCallback IDと一致するようにします。

edit(wsEdit), save(wsSave), execute(wsExecute)のそれぞれの役割とサンプルコードを解説します。

edit(wsEdit)

ワークフロービルダーで、Custom Stepを追加したり、編集したりするときに実行されます。
カスタムステップの設定をするモーダルを定義し、開きます。

サンプルコード
app.js
const wsEdit = ({ ack, step, configure }) => {
  await ack();
  
  const blocks = [
    {
      type: 'input',
      block_id: 'title_input',
      element: {
        type: 'plain_text_input',
        action_id: 'title',
      },
      label: {
        type: 'plain_text',
        text: 'タイトル',
      }
    },
    {
      type: 'input',
      block_id: 'message_input',
      element: {
        type: 'plain_text_input',
        action_id: 'message',
        multiline: true,
      },
      label: {
        type: 'plain_text',
        text: 'メッセージ',
      },
    }
  ];

  const { inputs } = step;
  const title = inputs.title;
  const message = inputs.message;

  if (title !== void 0) {
    blocks[0].element.initial_value = title.value;
  }
  if (message !== void 0) {
    blocks[1].element.initial_value = message.value;
  }

  await configure({ blocks });
};

順に説明します。

await ack();

応答です。とりあえず返しておきましょう。

const blocks = [
  // 省略
];

モーダルに表示するBlockを定義します。
Block Kit Builderを使うと便利です。(Modal Previewで!)

const { inputs } = step;
const title = inputs.title;
const message = inputs.message;

if (title !== void 0) {
  blocks[0].element.initial_value = title.value;
}
if (message !== void 0) {
  blocks[1].element.initial_value = message.value;
}

この部分は、編集モードで開いたときの初期値を定義しています。
これがないと、編集で開いたときに前回保存した内容が表示されません。

inputsはこの後にでてくるsave(wfSave)で定義しています。
(この部分はなんかもっとうまいやり方があるかもしれません。)

await configure({ blocks });

最後にconfigureblocksを渡すことで、モーダルが表示されます。

save(wsSave)

Custom Stepで、表示されたモーダルの「保存する」をクリックした時に実行されます。
モーダルからの値を受け取って、利用します。

サンプルコード
app.js
const wsSave = async ({ ack, view, update }) => {
  await ack();

  const { values } = view.state;
  const title = values.title_input.title;
  const message = values.message_input.message;
  const inputs = {
    title: { value: title.value },
    message: { value: message.value },
  };

  const outputs = [
    {
      type: 'text',
      name: 'title',
      label: 'タイトル',
    },
    {
      type: 'text',
      name: 'message',
      label: 'メッセージ',
    },
  ];

  await update({ inputs, outputs });
}

順に説明します。

await ack();

応答です。とりあえず返しておきましょう。

const { values } = view.state;
const title = values.title_input.title;
const message = values.message_input.message;
const inputs = {
  title: { value: title.value },
  message: { value: message.value },
};

view.state.valuesにはモーダルに入力した値がわたってきます。

それをもとにinputsを構成します。
それぞれvalueに値を設定すればよいです。

このinputsはedit(wsEdit)でstep.inputsにわたります。

inputsを詳しく知りたい方はリファレンスを参照ください。
※私にはvariablesを使うシーンがよくわかりませんでした:frowning2:

const outputs = [
  {
    type: 'text',
    name: 'title',
    label: 'タイトル',
  },
  {
    type: 'text',
    name: 'message',
    label: 'メッセージ',
  },
];

outputsには後続のワークフローステップにわたす変数を定義します。
(変数を挿入するをクリックしたときにでてきます。)
変数を挿入する

typeにはtext,channel,userのいずれかが入ります。

実際に渡す値はexecute(wsExecute)で設定します。

await update({ inputs, outputs });

最後にupdateinputsoutputsを渡すことで、モーダルが表示されます。

execute(wsExecute)

ワークフローが実際にCustom Stepに到達した際に実行されます。

サンプルコード
app.js
const wsExecute = async ({ step, complete, fail, client }) => {
  const { inputs } = step;

  const outputs = {
    title: inputs.title.value,
    message: inputs.message.value,
  };

  try {
    await client.chat.postMessage({
      channel: '###',
      blocks: [
        {
          type: 'header',
          text: {
            type: 'plain_text',
            text: inputs.title.value,
            emoji: true,
          }
        },
        {
          type: 'section',
          text: {
            type: 'mrkdwn',
            text: inputs.message.value,
          }
        },
      ]
    });
    await complete({ outputs });
  }
  catch (e) {
    fail({ error: { message: 'fail...' } });
  }
}

順に説明します。

const { inputs } = step;

const outputs = {
  title: inputs.title.value,
  message: inputs.message.value,
};

save(wsSave)で定義したoutputsに対して、次のステップにわたす値を設定します。

try {
  // 省略
  await complete({ outputs });
}
catch (e) {
  fail({ error: { message: 'fail...' } });
}

tryで処理を実行します。
サンプルコードでは、Custom Stepで設定したタイトルとメッセージを固定のチャンネルにポストしています。

最後に

await complete({ outputs });

でoutputsを次のステップにわたします。

エラーがでた場合は

fail({ error: { message: 'fail...' } });

でエラーメッセージを返します。
おそらく、ワークフローのアクティビティにエラーメッセージが表示されるのだと思います。(未確認)

さいごに

これでCustom Stepが実装できました!
ワークフロービルダーでちょっと手の届かないところだけサクッと作れるので、大変重宝しています。

アプリのショートカットはabc順で並ぶので、探すのが大変ですが、ワークフローは一番上に表示されるので、その点でもワークフロービルダーでサクッと作ってしまいたいですよね。

汎用的に使えそうなCustom Stepを複数作ってみて、Slack Lifeを充実させましょう!

最後になりましたが、間違っているところなどありましたら、ばしばしご指摘くださいませ。

11
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?