松弛螺栓清除视图堆栈
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
。在这些接口中,BlockAction
和 InteractiveMessage
确实有一个 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
通用。
在 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
。在这些接口中,BlockAction
和 InteractiveMessage
确实有一个 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
通用。