こんにちは、Slack の公式 SDK 開発と日本の Developer Relations を担当している瀬良 (@seratch) と申します
この記事は Slack の次世代プラットフォーム機能を少しずつ試しながら、ゆっくりと理解していくシリーズの記事です。
「次世代プラットフォーム機能って何?」という方は、以下の記事で詳しく解説しましたので、まずはそちらをお読みください。
この記事では、標準ファンクションとして提供されているフォーム(OpenForm)の使い方をご紹介します。
プロジェクトを作成
いつものようにブランクプロジェクトを作成してゼロからコードを足していきましょう。slack create
コマンドを実行して、選択肢から「Blank Project」を選択してください。作成したプロジェクトの構成は以下の通りです。
$ tree
.
├── LICENSE
├── README.md
├── assets
│ └── default_new_app_icon.png
├── deno.jsonc
├── import_map.json
├── manifest.ts
└── slack.json
ワークフローを追加
今回は標準ファンクションだけを使いますので workflow.ts
というファイルだけを作成します。
// ----------------
// ワークフロー定義
// ----------------
import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";
export const workflow = DefineWorkflow({
callback_id: "form-demo-workflow",
title: "OpenForm Demo Workflow",
input_parameters: {
properties: {
interactivity: { type: Schema.slack.types.interactivity },
user_id: { type: Schema.slack.types.user_id },
channel_id: { type: Schema.slack.types.channel_id },
},
required: ["interactivity", "user_id", "channel_id"],
},
});
// ここにフォームを使ったステップを追加
const formStep = workflow.addStep(Schema.slack.functions.OpenForm, {
title: "Send a greeting",
interactivity: workflow.inputs.interactivity,
submit_label: "Send greeting",
fields: {
elements: [
{
name: "recipient",
title: "Recipient",
// users_select ブロックに変換される
type: Schema.slack.types.user_id,
default: workflow.inputs.user_id,
},
{
name: "channel",
title: "Channel to send message to",
// channels_select ブロックに変換される
type: Schema.slack.types.channel_id,
default: workflow.inputs.channel_id,
},
{
name: "message",
title: "Message to recipient",
// plain_text_input ブロックに変換される
type: Schema.types.string,
// multiline: true に変換される
long: true,
},
],
required: ["recipient", "channel", "message"],
},
});
// 正しく outputs を受け取った確認
workflow.addStep(Schema.slack.functions.SendEphemeralMessage, {
user_id: formStep.outputs.fields.recipient, // name がキー名になる
channel_id: formStep.outputs.fields.channel, // name がキー名になる
message: "OpenForm's `outputs.fields`: ```" +
formStep.outputs.fields +
"```",
});
// ----------------
// トリガー定義
// ----------------
import { Trigger } from "deno-slack-api/types.ts";
const trigger: Trigger<typeof workflow.definition> = {
type: "shortcut",
name: "Form Demo Trigger",
workflow: `#/workflows/${workflow.definition.callback_id}`,
inputs: {
// interactivity は OpenForm を利用するためには必須
// この記事投稿時点で interactivity を提供できるのはリンクトリガーのみ
interactivity: { value: "{{data.interactivity}}" },
// OpenForm を利用する上では必要ないが、受け取った内容の出力をするために利用
user_id: { value: "{{data.user_id}}" },
channel_id: { value: "{{data.channel_id}}" },
},
};
export default trigger;
そして manifest.ts
に今作成したワークフローを登録します。
import { Manifest } from "deno-slack-sdk/mod.ts";
import { workflow as DemoWorkflow } from "./workflow.ts";
export default Manifest({
name: "frosty-mink-263",
description: "Demo workflow",
icon: "assets/default_new_app_icon.png",
workflows: [DemoWorkflow],
outgoingDomains: [],
botScopes: ["commands", "chat:write", "chat:write.public"],
});
slack run
でアプリを起動してみて、エラーが発生していないことを確認してください。
リンクトリガーを作成してワークフローを試す
slack triggers create --trigger-def ./workflow.ts
を実行して、リンクトリガーを作成して、それをチャンネル内のメッセージかブックマークとして共有してください。
実行すると以下のようにあなただけに見えるメッセージとしてフォームで受け取った情報を返してくれます。
基本的な利用法のまとめ
OpenForm の基本的な利用法のポイントは、
- リンクトリガーを使って
interactivity
をワークフローに渡す - ワークフローに
Schema.slack.functions.OpenForm
ファンクションを追加 - OpenForm の設定項目は、こちらやこちらのページを参照のこと
-
OpenForm
をworkflow#addStep()
した戻り値を変数として保持、その変数のoutputs.fields
に送信された情報は含まれる
という点になります。
ここまで、とりあえず使い方は理解できたと思いますが、もう少し具体例をご紹介していきます。
組み込みの入力バリデーションを追加
先ほどのフォームでは、すべての項目を必須項目として設定していました。"message"
を必須項目から外してみましょう。そのためには required
として設定されている三つの要素から "message"
を削除するだけです。
required: ["recipient", "channel"],
これで "message"
に何も入力しなくても送信できるようになります。入力せずに送信した場合、空文字になるわけではなく outputs.fields
にそのキー自体が存在しなくなりますので、ご注意ください。
次に「"message"
は必須ではないが、入力するなら 5 文字以上 20 文字以下」という条件をつけてみましょう。以下のように設定することで 1-4 文字、21 文字以上の入力がされた状態ではフォームを送信できなくなります。
{
name: "message",
title: "Message to recipient",
// plain_text_input ブロックに変換される
type: Schema.types.string,
// multiline: true に変換される
long: true,
minLength: 5,
maxLength: 20,
},
(まだあまり詳しい説明が書かれていませんが・・・ )こちらのページに利用可能な属性の一覧がありますので、ご参照ください。
組み込みのセレクトメニューの使い方
Block Kit でいうところの static_select
のような機能は設定方法が若干異なりますので、具体例とともご紹介しておきます。
以下のような要素を追加するとセレクトメニューが生成されます。
{
name: "favorite", // 必須
title: "Favorite", // 必須
type: Schema.types.string, // 必須
choices: [
{ value: "dog", title: "Dog" },
{ value: "cat", title: "Cat" },
], // 必須
enum: ["dog", "cat"], // 必須
default: "cat", // 必須でない
},
実際の見た目はこのようになります。
注意点としては、(この記事投稿時点ではまだ機能として利用されていませんが) enum
は必須項目となっており、省略した場合、フリーテキストの plain_text_input ブロックにフォールバックされてしまいますので、必ず指定するようにしてください。
また、その他のセレクトメニューとしては、上のコード例でもすでに出てきていますが、user_id
や channel_id
といった type を指定すると自動的にユーザー一覧からの選択、チャンネル一覧からの選択に変換されるようになっています。
また、複数選択には Schema.types.array
とその要素の type を指定します。
{
name: "people",
title: "People",
type: Schema.types.array,
items: {
type: Schema.slack.types.user_id,
},
default: [workflow.inputs.user_id, "USLACKBOT"],
},
以下のような UI に変換されます。
ここまでで試した fields.elements
をすべて含む完全なコードは以下の通りです。これを貼り付けて試してみてください。
// ここにフォームを使ったステップを追加
const formStep = workflow.addStep(Schema.slack.functions.OpenForm, {
title: "Send a greeting",
interactivity: workflow.inputs.interactivity,
submit_label: "Send greeting",
fields: {
elements: [
{
name: "recipient",
title: "Recipient",
// users_select ブロックに変換される
type: Schema.slack.types.user_id,
default: workflow.inputs.user_id,
},
{
name: "channel",
title: "Channel to send message to",
// channels_select ブロックに変換される
type: Schema.slack.types.channel_id,
default: workflow.inputs.channel_id,
},
{
name: "message",
title: "Message to recipient",
// plain_text_input ブロックに変換される
type: Schema.types.string,
// multiline: true に変換される
long: true,
minLength: 5,
maxLength: 20,
},
{
name: "favorite",
title: "Favorite",
// static_select ブロックに変換される
type: Schema.types.string,
choices: [
{ value: "dog", title: "Dog" },
{ value: "cat", title: "Cat" },
],
enum: ["dog", "cat"], // 省略しないでください
default: "cat",
},
{
name: "people",
title: "People",
// multi_users_select ブロックに変換される
type: Schema.types.array,
items: {
// ここの型を変えると他のブロックに変化する
type: Schema.slack.types.user_id,
},
default: [workflow.inputs.user_id, "USLACKBOT"],
},
],
required: ["recipient", "channel"],
},
});
// 正しく outputs を受け取った確認
workflow.addStep(Schema.slack.functions.SendEphemeralMessage, {
user_id: formStep.outputs.fields.recipient, // name がキー名になる
channel_id: formStep.outputs.fields.channel, // name がキー名になる
message: "OpenForm's `outputs.fields`: ```" +
formStep.outputs.fields +
"```",
});
繰り返しとなりますが、指定可能な値についてはこちらのドキュメントをご参照ください。
終わりに
いかがだったでしょうか?制約はあるものの、この標準のフォームで、多くの用途はカバーできるのではないかと思います。特に既存の Block Kit では標準でサポートしてなかった最小値・最大値のバリデーションなどはよくあるユースケースだと思います。
より詳細な情報は、以下のページをご参照ください。
別の記事では、制約のない高度なモーダル利用についても解説する予定ですので、そちらの情報をお探しの方は少々お待ちください。
(追記)記事を公開しました。
それでは!