松弛螺栓清除视图堆栈

Slack Bolt Clearing view stack

在 view_submission 类型中,我设置 ack 来清除堆栈,如下所示:

await submissionAck({ response_action: 'clear' } as any)

第一个问题 - 为什么我必须将它转换为 any?没有它代码会抛出错误

Argument of type '{ response_action: "clear"; }' is not assignable to parameter of type '(ViewUpdateResponseAction & void) | (ViewPushResponseAction & void) | (ViewClearResponseAction & void) | (ViewErrorsResponseAction & void) | undefined'.Type '{ response_action: "clear"; }' is not assignable to type 'ViewClearResponseAction & void'.
Type '{ response_action: "clear"; }' is not assignable to type 'void'.

第二个问题- 堆栈似乎没有被清除。当我第一次提交模式时没问题,但如果我下次尝试它会抛出:

[ERROR]  bolt-app { Error: The receiver's `ack` function was called multiple times.
    at ack (/home/ec2-user/metrics/node_modules/@slack/bolt/src/ExpressReceiver.ts:147:17)
    at /home/ec2-user/metrics/app/actions.ts:43:17
    at Generator.next (<anonymous>)
    at /home/ec2-user/metrics/app/actions.ts:11:71
    at new Promise (<anonymous>)
    at __awaiter (/home/ec2-user/metrics/app/actions.ts:7:12)
    at app.view (/home/ec2-user/metrics/app/actions.ts:40:70)
    at process_1.processMiddleware (/home/ec2-user/metrics/node_modules/@slack/bolt/src/App.ts:660:19)
    at invokeMiddleware (/home/ec2-user/metrics/node_modules/@slack/bolt/src/middleware/process.ts:36:12)
    at next (/home/ec2-user/metrics/node_modules/@slack/bolt/src/middleware/process.ts:28:21)
    at Array.<anonymous> (/home/ec2-user/metrics/node_modules/@slack/bolt/src/middleware/builtin.ts:201:11)
    at invokeMiddleware (/home/ec2-user/metrics/node_modules/@slack/bolt/src/middleware/process.ts:27:47)
    at next (/home/ec2-user/metrics/node_modules/@slack/bolt/src/middleware/process.ts:28:21)
    at Array.exports.onlyViewActions (/home/ec2-user/metrics/node_modules/@slack/bolt/src/middleware/builtin.ts:110:11)
    at invokeMiddleware (/home/ec2-user/metrics/node_modules/@slack/bolt/src/middleware/process.ts:27:47)
    at Object.processMiddleware (/home/ec2-user/metrics/node_modules/@slack/bolt/src/middleware/process.ts:39:10) code: 'slack_bolt_receiver_ack_multiple_error' }

有什么想法吗?这就是我如何称呼这些视图:(顺便说一下,第三个问题 - 为什么我必须将 body 转换为 BlockAction?否则它会抛出 trigger_id 不存在的错误)

  app.action('modify', async ({ body, ack }) => {
    await ack()
    await authenticate(body.team.id, async (customer: Customer) => {
      await app.client.views.open({
        trigger_id: (body as BlockAction).trigger_id,
        token: 'token',
        view: modificationModal,
      })
      app.view(
        {
          type: 'view_submission',
          callback_id: 'yay',
        },
        async ({ body: submissionBody, ack: submissionAck, view }) => {
          const receivedValues = submissionBody.view.state.values
          await submissionAck({ response_action: 'clear' } as any)
        },
      )
    })
  })

我知道文档中的内容是:

view() requires a callback_id of type string or RegExp.

但这并不能告诉我太多。那个字符串是什么?那是一个功能吗?它应该做什么?

很抱歉这个菜鸟问题,感谢您的帮助!

我将尝试以相反的顺序回答这些问题,因为我认为这可能最有意义。

What is that string? Is that a function? What should it do? (referring to app.view())

创建模态框时,通常使用 callback_id 创建它。您可以在 view payload.

的文档中看到 属性 的描述

这句话是想说这就是您监听视图提交的方式,该视图是在 callback_id 设置为 "some_callback_id" 的情况下创建的:

app.view('some_callback_id', async () => {
  /* listener logic goes here */
})

注意:如果您希望相同的函数处理多个视图的视图提交,您也可以使用正则表达式 - callback_id 的视图都遵循相同的模式。但是正则表达式是一个非常高级的情况,我认为我们现在不应该担心它。

要创建模态框,您可以使用 views.open 方法,这就是您首先要设置 callback_id 的地方。我要提出改进建议。所有 Web API 方法都可以在侦听器中作为 client 参数上的方法使用。那么您无需担心添加 token。这是一个使用它的例子:

// Add the `client` argument
app.action('modify', async ({ body, ack, client }) => {
  await ack()
  await authenticate(body.team.id, async (customer: Customer) => {
    // Remove `app.`
    await client.views.open({
      // Let's come back to this cast later
      trigger_id: (body as BlockAction).trigger_id,
      // Not sure what's in modificationModal, but to illustrate, I used a literal
      view: {
        // *** Setting the callback_id ***
        callback_id: 'modify_submission',
        title: {
          type: 'plain_text',
          text: 'Modify something'
        },
        blocks: [{ /* add your blocks here */ }],
      },
    })
  })
})

接下来,不要在另一个侦听器中处理视图提交。当您这样做时,每次外部侦听器 运行 时,您都在(重新)将视图提交侦听器注册到 运行。所以第一次会运行一次,第二次会运行两次,第三次会运行三次。这解释了为什么堆栈跟踪告诉您 ack() 被多次调用。相反,只需在该侦听器之外处理视图提交。两次交互之间的 "linking" 信息是 callback_id。以前面的例子为基础:

// Further down in the same file, at the same level as the previous code
// *** Using the callback_id we set previously ***
app.view('modify_submission', async ({ body, ack, view }) => {
  const receivedValues = body.view.state.values
  // Let's come back to this cast later
  await ack({ response_action: 'clear' } as any)
})

好的,这应该一切正常,但现在让我们谈谈演员表。当您使用 app.action() 处理操作时,body 参数被键入为 BlockAction | InteractiveMessage | DialogSubmitAction。在这些接口中,BlockActionInteractiveMessage 确实有一个 trigger_id 属性,但 DialogSubmitAction 没有。所以就 TypeScript 而言,无法确定 属性 body.trigger_id 是否存在。您可能知道您正在处理的操作是 BlockAction(假设它是),但 TypeScript 不是!然而,Bolt 的构建是为了允许用户通过使用通用参数为 TypeScript 提供更多信息。这是第一个示例的一部分,已修改为使用通用参数。

import { BlockAction } from '@slack/bolt';

app.action<BlockAction>('modify', async ({ body, ack, client }) => {
   // `body` is now typed as a BlockAction, and therefore body.trigger_id is a string
});

app.view() 和通用参数的情况非常相似。这次,body 参数的类型是 ViewSubmitAction | ViewClosedAction。使用 clear 响应操作对于 ViewClosedAction 没有意义,因此我们需要再次约束类型。没错,泛型参数不仅仅是 body 的类型,它实际上可以改变(约束)任何监听器参数!在这种情况下,泛型参数更改 ack().

的类型
import { ViewSubmitAction } from '@slack/bolt';

app.view<ViewSubmitAction>('modify_submission', async ({ body, ack, view }) => {
  // No errors now
  await ack({ response_action: 'clear' });
});

最后说明:您使用约束对象编写视图提交处理程序的方式({ type: 'view_submission', callback_id: 'yay' } 看起来您已经为 TypeScript 提供了足够的信息来约束侦听器参数的类型。这实际上适用于app.action({ type: 'block_actions', ... }, ...) 因为我们将 ActionConstraints 定义为通用的。这是 Bolt 可以改进的地方,只需以相同的方式使 ViewConstraints 通用。