1

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

await submissionAck({ response_action: 'clear' } as 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.

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

对不起,noobish 问题,感谢您的帮助!

4

1 回答 1

3

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

那根弦是什么?那是一个功能吗?它应该怎么做?(参考app.view()

创建 Modal 时,通常使用callback_id. 您可以在视图有效负载的文档中查看该属性的描述。

那句话试图说这是您如何为使用callback_idset to创建的视图收听视图提交"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 */ }],
      },
    })
  })
})

接下来,不要在另一个 listener 中处理视图提交。当您这样做时,每次外部侦听器运行时,您都在(重新)注册要运行的视图提交侦听器。所以第一次运行一次,第二次运行两次,第三次运行三次。这解释了为什么堆栈跟踪会告诉您它ack()被多次调用。相反,只需在该侦听器之外处理视图提交。两个交互之间的“链接”信息是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。在这些接口之内,BlockAction确实InteractiveMessage有一个trigger_id属性,但DialogSubmitAction没有。因此就 TypeScript 而言,它不能确定该属性是否body.trigger_id存在。您可能知道您正在处理的操作是 a 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参数是 type ViewSubmitAction | ViewClosedAction。使用clear响应动作对 a 没有意义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以同样的方式进行通用化。

于 2020-06-03T21:40:03.777 回答