Slack 下一代平台 – 高级模态


创建一个空白项目

当你开始一个新项目时,你可以运行slack create命令。在本教程中,您将从头开始构建一个应用程序。所以从列表中选择“空白项目”:

$ slack create
? Select a template to build from:

  Hello World
  A simple workflow that sends a greeting

  Scaffolded project
  A solid foundational project that uses a Slack datastore

> Blank project
  A, well.. blank project

  To see all available samples, visit github.com/slack-samples.

生成项目后,让我们检查slack run命令是否正常运行。此命令将新应用程序的“开发”版本安装到连接的 Slack 工作区中。现在您的应用程序的机器人用户位于工作区中,并且您的应用程序具有用于 API 调用的机器人令牌。

$ cd sharp-chipmunk-480
$ slack run
? Choose a workspace  seratch  T03E94MJU
   App is not installed to this workspace

Updating dev app install for workspace "Acme Corp"

⚠️  Outgoing domains
   No allowed outgoing domains are configured
   If your function makes network requests, you will need to allow the outgoing domains
   Learn more about upcoming changes to outgoing domains: https://api.slack.com/future/changelog
✨  seratch of Acme Corp
Connected, awaiting events

如果您看到Connected, awaiting events日志消息,则应用已成功连接到 Slack。您可以按“Ctrl + C”来终止本地应用程序进程。

定义工作流和触发器

让我们从定义一个简单的演示工作流及其链接触发器开始。一如既往,将源代码保存为workflow_and_trigger.ts

// ----------------
// Workflow Definition
// ----------------
import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";
export const workflow = DefineWorkflow({
  callback_id: "modal-demo-workflow",
  title: "Modal Demo Workflow",
  input_parameters: {
    properties: { interactivity: { type: Schema.slack.types.interactivity } },
    required: ["interactivity"],
  },
});

// Add your custom function to open and handle a modal
import { def as ModalDemo } from "./function.ts";
workflow.addStep(ModalDemo, {
  interactivity: workflow.inputs.interactivity,
});

// ----------------
// Trigger Definition
// ----------------
import { Trigger } from "deno-slack-api/types.ts";
const trigger: Trigger<typeof workflow.definition> = {
  type: "shortcut", // link trigger
  name: "Modal Demo Trigger",
  workflow: `#/workflows/${workflow.definition.callback_id}`,
  inputs: {
    // Modal interactions require `interactivity` input parameter.
    // As of this writing, only link triggers can provide the value.
    interactivity: { value: "{{data.interactivity}}" },
  },
};
export default trigger;

由于您还function.ts没有,编译应该会失败。让我们添加以下源代码function.ts

import { DefineFunction, Schema, SlackFunction } from "deno-slack-sdk/mod.ts";
import { FunctionSourceFile } from "https://deno.land/x/deno_slack_source_file_resolver@0.1.5/mod.ts";

export const def = DefineFunction({
  callback_id: "modal-example",
  title: "Modal interaction example",
  source_file: FunctionSourceFile(import.meta.url),
  input_parameters: {
    properties: { interactivity: { type: Schema.slack.types.interactivity } },
    required: ["interactivity"],
  },
  output_parameters: { properties: {}, required: [] },
});

export default SlackFunction(
  def,
  // ---------------------------
  // The first handler function that opens a modal.
  // This function can be called when the workflow executes the function step.
  // ---------------------------
  async ({ inputs, client }) => {
    // Open a new modal with the end-user who interacted with the link trigger
    const response = await client.views.open({
      interactivity_pointer: inputs.interactivity.interactivity_pointer,
      view: {
        "type": "modal",
        // Note that this ID can be used for dispatching view submissions and view closed events.
        "callback_id": "first-page",
        // This option is required to be notified when this modal is closed by the user
        "notify_on_close": true,
        "title": { "type": "plain_text", "text": "My App" },
        "submit": { "type": "plain_text", "text": "Next" },
        "close": { "type": "plain_text", "text": "Close" },
        "blocks": [
          {
            "type": "input",
            "block_id": "first_text",
            "element": { "type": "plain_text_input", "action_id": "action" },
            "label": { "type": "plain_text", "text": "First" },
          },
        ],
      },
    });
    if (response.error) {
      const error =
        `Failed to open a modal in the demo workflow. Contact the app maintainers with the following information - (error: ${response.error})`;
      return { error };
    }
    return {
      // To continue with this interaction, return false for the completion
      completed: false,
    };
  },
)
  // ---------------------------
  // The handler that can be called when the above modal data is submitted.
  // It saves the inputs from the first page as private_metadata,
  // and then displays the second-page modal view.
  // ---------------------------
  .addViewSubmissionHandler(["first-page"], ({ view }) => {
    // Extract the input values from the view data
    const firstText = view.state.values.first_text.action.value;
    // Input validations
    if (firstText.length < 5) {
      return {
        response_action: "errors",
        // The key must be a valid block_id in the blocks on a modal
        errors: { first_text: "Must be 5 characters or longer" },
      };
    }
    // Successful. Update the modal with the second page presentation
    return {
      response_action: "update",
      view: {
        "type": "modal",
        "callback_id": "second-page",
        // This option is required to be notified when this modal is closed by the user
        "notify_on_close": true,
        "title": { "type": "plain_text", "text": "My App" },
        "submit": { "type": "plain_text", "text": "Next" },
        "close": { "type": "plain_text", "text": "Close" },
        // Hidden string data, which is not visible to end-users
        // You can use this property to transfer the state of interaction
        // to the following event handlers.
        // (Up to 3,000 characters allowed)
        "private_metadata": JSON.stringify({ firstText }),
        "blocks": [
          // Display the inputs from "first-page" modal view
          {
            "type": "section",
            "text": { "type": "mrkdwn", "text": `First: ${firstText}` },
          },
          // New input block to receive text
          {
            "type": "input",
            "block_id": "second_text",
            "element": { "type": "plain_text_input", "action_id": "action" },
            "label": { "type": "plain_text", "text": "Second" },
          },
        ],
      },
    };
  })
  // ---------------------------
  // The handler that can be called when the second modal data is submitted.
  // It displays the completion page view with the inputs from
  // the first and second pages.
  // ---------------------------
  .addViewSubmissionHandler(["second-page"], ({ view }) => {
    // Extract the first-page inputs from private_metadata
    const { firstText } = JSON.parse(view.private_metadata!);
    // Extract the second-page inputs from the view data
    const secondText = view.state.values.second_text.action.value;
    // Displays the third page, which tells the completion of the interaction
    return {
      response_action: "update",
      view: {
        "type": "modal",
        "callback_id": "completion",
        // This option is required to be notified when this modal is closed by the user
        "notify_on_close": true,
        "title": { "type": "plain_text", "text": "My App" },
        // This modal no longer accepts further inputs.
        // So, the "Submit" button is intentionally removed from the view.
        "close": { "type": "plain_text", "text": "Close" },
        // Display the two inputs
        "blocks": [
          {
            "type": "section",
            "text": { "type": "mrkdwn", "text": `First: ${firstText}` },
          },
          {
            "type": "section",
            "text": { "type": "mrkdwn", "text": `Second: ${secondText}` },
          },
        ],
      },
    };
  })
  // ---------------------------
  // The handler that can be called when the second modal data is closed.
  // If your app runs some resource-intensive operations on the backend side,
  // you can cancel the ongoing process and/or tell the end-user
  // what to do next in DM and so on.
  // ---------------------------
  .addViewClosedHandler(
    ["first-page", "second-page", "completion"],
    ({ view }) => {
      console.log(`view_closed handler called: ${JSON.stringify(view)}`);
      return { completed: true };
    },
  );

稍后我会解释细节,但关键点是:

  • 第一个处理程序为最终用户打开一个模式
  • addViewSubmissionHandler()使用处理程序注册 + 模态的调度模态数据提交事件callback_id
  • addViewClosedHandler()使用的处理程序注册 + 模态的调度模态关闭事件

本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;

2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;

3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;

4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;

5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/295263.html

(0)
上一篇 2023年2月10日
下一篇 2023年2月10日

相关推荐

发表回复

登录后才能评论