slackapi / bolt-js

A framework to build Slack apps using JavaScript
https://slack.dev/bolt-js
MIT License
2.74k stars 394 forks source link

Bug: Adding block elements through code make actions disable #2138

Closed bilalashraf1710 closed 1 day ago

bilalashraf1710 commented 3 months ago

(Filling out the following with as much detail as you can provide will help us solve your issue sooner.)

@slack/bolt version

^3.17.1

Your App and Receiver Configuration

const receiver = new ExpressReceiver({
  signingSecret: process.env.SLACK_SIGNING_SECRET,
  clientId: process.env.SLACK_CLIENT_ID,
  clientSecret: process.env.SLACK_CLIENT_SECRET,
  stateSecret: process.env.SLACK_STATE_SECRET,
  app: expressApp,
  scopes: SLACK_APP_SCOPES,
  installerOptions: {
    userScopes: USER_SCOPES,
    directInstall: true,
    callbackOptions: { success: installer.success },
  },
  installationStore: isOffline ? new FileInstallationStore() : new DynamoDBInstallationStore(),
  // processBeforeResponse: true, // Required to avoid latency issues with AWS Lambda
})

const app = new App({
  receiver,
  logLevel: LogLevel[process.env.LOG_LEVEL] || LogLevel.WARN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
})

Node.js runtime version

20.12.2

Steps to reproduce:

(Share the commands to run, source code, and project settings)

I am fetching Slack blocks through code and sending them to GPT to refine the messages. The refined blocks are well-formatted and work fine with Block Kit. However, when the blocks contain user_id elements within a rich-text box, buttons on the screen become unresponsive. Interestingly, if I manually edit the rich-text block by adding a space, the buttons start working. Could you please help refine this?

Expected result:

Buttons should work fine without editing the message

Actual result:

Buttons are not working and I can see the warning icon's next to button and submit button also not working.

filmaj commented 3 months ago

Could you please provide some code to reproduce the issue?

bilalashraf1710 commented 3 months ago

@filmaj Please check the code and video 1- I opened a modal on command enter 2- I write a simple text and moved to view-2 ( now the submit button is working ) 3- When I tagged to someone and move to view-2 ( submit button not working )

app.shortcut(/^ask_anything_.*/, async function ({ ack, client, body, logger }) {
      try {
        await ack()
        await client.views.open({
          trigger_id: body.trigger_id,
          view: {
            type: "modal",
            callback_id: "view_1_callback",
            title: { type: "plain_text", text: "View 1" },
            submit: { type: "plain_text", text: "Let's Go" },
            blocks: [
              {
                type: "input",
                block_id: "rich_text_block",
                label: {
                  type: "plain_text",
                  text: "Refined Text",
                },
                element: {
                  type: "rich_text_input",
                  action_id: "rich_text_input_action",
                },
              },
            ],
          },
        })
      } catch (e) {
        logger.warn("Error Occurred - aaa - aaaCommand", e)
      }
    })
app.view("view_1_callback", async function ({ view, ack, client }) {
    const modal = {
      type: "modal",
      callback_id: "view_2_callback",
      external_id: "123",
      title: { type: "plain_text", text: "View 2" },
      submit: { type: "plain_text", text: "Let's Go" },
      blocks: [
        {
          type: "input",
          block_id: "rich_text_block",
          label: {
            type: "plain_text",
            text: "Refined Text",
          },
          element: {
            type: "rich_text_input",
            action_id: "rich_text_input_action",

            initial_value: {
              type: "rich_text",
              elements: view.state.values?.rich_text_block?.rich_text_input_action?.rich_text_value?.elements,
            },
          },
        },
      ],
    }

    await ack({ response_action: "update", view: thinkingModal })
    await client.views.update({ external_id: thinkingModal.external_id, view: modal })
  })
 app.view("view_2_callback", async function ({ view, ack, client }) {

    await ack({
      response_action: "update",
      view: {
        type: "modal",
        callback_id: "view_3_callback",
        title: { type: "plain_text", text: "View 3" },
        submit: { type: "plain_text", text: "Let's Go" },
        blocks: [],
      },
    })
  })

https://github.com/slackapi/bolt-js/assets/57355515/a0d4fc58-670a-4b7e-ae72-ff1210300fff

https://github.com/slackapi/bolt-js/assets/57355515/b4ccad41-0b31-4c5d-b242-9b5ba32cca73

filmaj commented 3 months ago

@bilalashraf1710 what is the value of thinkingModal in the code you shared? I am trying to set up an app to reproduce the issue - without a reproduction, I cannot help.

filmaj commented 3 months ago

Related (or maybe separate issue): the callback to your first view submission seems odd: it is trying to update two modals, the current modal (view_1) as well as a "thinking modal". That is not possible, as there can only be 1 modal shown to the user at a time. That may be why you are seeing the odd "flashing" UI that your video displays.

If I modify your view_1_callback handler to just update the current modal's title, and propagate the rich text input's elements to the new view in an update call, it works fine, even with user mentions:

app.view('view_1_callback', async ({ ack, body, view, client, logger }) => {
  const modal = { // <-- in your code snippet above, this object was not being used
    type: "modal",
    callback_id: "view_2_callback",
    external_id: "123",
    title: { type: "plain_text", text: "View 2" },
    submit: { type: "plain_text", text: "Let's Go" },
    blocks: [
      {
        type: "input",
        block_id: "rich_text_block",
        label: {
          type: "plain_text",
          text: "Refined Text",
        },
        element: {
          type: "rich_text_input",
          action_id: "rich_text_input_action",

          initial_value: {
            type: "rich_text",
            elements: view.state.values?.rich_text_block?.rich_text_input_action?.rich_text_value?.elements,
          },
        },
      },
    ],
  }

  await ack({ response_action: "update", view: modal }) // <--- in this code snippet, the new modal is now being used
  // await client.views.update({ external_id: thinkingModal.external_id, view: modal }) // <--- this should not work, as only a single modal can be viewed at a time. I commented this out in my example.
bilalashraf1710 commented 3 months ago

@filmaj I intentionally added that thinking modal because view-1 rich-text sharing the same context with view-2 rich-text.

In my case, I do some DB calls while showing the Thinking modal to the user.

filmaj commented 3 months ago

The following code worked fine for me (I used a setTimeout to mimic a long-running background operation like your DB operations):

app.command('/post', async ({ ack, say, body, client, logger }) => {
  await ack();
  await client.views.open({
    trigger_id: body.trigger_id,
    view: {
      type: "modal",
      callback_id: "view_1_callback",
      title: { type: "plain_text", text: "View 1" },
      submit: { type: "plain_text", text: "Let's Go" },
      blocks: [
        {
          type: "input",
          block_id: "rich_text_block",
          label: {
            type: "plain_text",
            text: "Refined Text",
          },
          element: {
            type: "rich_text_input",
            action_id: "rich_text_input_action",
          },
        },
      ],
    },
  })
});
app.view('view_1_callback', async ({ ack, body, view, client, logger }) => {
  const thinkingModal = {
    type: "modal",
    callback_id: "thinking",
    external_id: "thinking",
    title: { type: "plain_text", text: "Thinking!!!" },
    blocks: [
      {
        type: "section",
        text: {
          type: "plain_text",
          text: "Processing, please wait",
        }
      }
    ]
  }
  const modal = {
    type: "modal",
    callback_id: "view_2_callback",
    external_id: "123",
    title: { type: "plain_text", text: "View 2" },
    submit: { type: "plain_text", text: "Let's Go" },
    blocks: [
      {
        type: "input",
        block_id: "rich_text_block",
        label: {
          type: "plain_text",
          text: "Refined Text",
        },
        element: {
          type: "rich_text_input",
          action_id: "rich_text_input_action",

          initial_value: {
            type: "rich_text",
            elements: view.state.values?.rich_text_block?.rich_text_input_action?.rich_text_value?.elements,
          },
        },
      },
    ],
  }

  await ack({ response_action: "update", view: thinkingModal })
  await new Promise((res) => setTimeout(res, 5000)); // wait for 5 seconds
  await client.views.update({ external_id: thinkingModal.external_id, view: modal })
});

Here's a gif of the code in action:

GIF Recording 2024-06-21 at 8 16 36 AM

Make sure you use unique external_id, callback_id, as well as unique IDs for every block element's block_id and action_id

bilalashraf1710 commented 3 months ago

@filmaj when you navigate to view-2. Can you please press the Lets Go button and see if it works? The issue is Let's Go button was not working until you edit the message on view-2. if you have any other button that would not work too

filmaj commented 3 months ago

Hmm I see what you mean. Indeed, if there's a user mention in the rich text input and you go to submit it again, there is an error. There is a need to slightly modify the text payload in order for it to submit:

GIF Recording 2024-06-21 at 8 38 38 AM

Interestingly, it seems to me like this is an error from the Slack client itself, as the submit of view 2 errors out on the client side.

Thank you for your patience working with me through this. I think I see the problem, too. If you open the Slack client devtools (it is just like a browser!), when you go to submit the view 2 modal the first time, here is the payload sent to the underlying Slack API views.submit:

state: {"values":{"rich_text_block":{"rich_text_input_action":{"type":"rich_text_input","rich_text_value":{"type":"rich_text","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"hi "},{"type":"user","userId":"U05T59XL1E3"}]}]}}}}}

The error returned by this API is:

{
    "ok": false,
    "error": "invalid_arguments",
    "response_metadata": {
        "messages": [
            "[ERROR] failed to match any allowed schemas [json-pointer:\/state\/values\/rich_text_block\/rich_text_input_action\/rich_text_value]",
            "[ERROR] missing required field: user_id [json-pointer:\/state\/values\/rich_text_block\/rich_text_input_action\/rich_text_value\/elements\/0\/elements\/1]"
        ]
    }
}

Note: the view payload does not include user_id but rather userId for the user mention 👀

If you then change the contents of the rich text input, it works! And the payload to the views.submit API is:

state: {"values":{"rich_text_block":{"rich_text_input_action":{"type":"rich_text_input","rich_text_value":{"type":"rich_text","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"h "},{"type":"user","user_id":"U05T59XL1E3"}]}]}}}}}

Correct user_id parameter, so no error.

Thanks for reporting this. I will raise this internally.

bilalashraf1710 commented 3 months ago

Hmm Interesting. When I print the elements on view-2 then it show user_id in a correct way.

alessio-ragni commented 2 months ago

Hi Slack Team and @filmaj 👋 Do you have an update here? This is something that is preventing us to go live with our product and we would love to have it fixed before applying for the Slack Application Submission. We really appreciate your help here. Thanks, Alex.

filmaj commented 2 months ago

No update here unfortunately. I recommend sending an email to feedback@slack.com and link to this issue and explain how it is a blocker for you - that will help prioritize the work to fix this.

alessio-ragni commented 2 months ago

Thanks, I'll keep you updated 🤞

StephenTangCook commented 1 month ago

Hey @alessio-ragni, I'm also hitting this bug. Did you ever submit a customer report or hear about a fix?

alessio-ragni commented 1 month ago

I also opened a ticket but unfortunately they also replied without an ETA :( and AFAIK there is no workaround. I hope they will fix soon.

On Wed, 21 Aug 2024 at 19:22, Stephen @.***> wrote:

Hey @alessio-ragni https://github.com/alessio-ragni, I'm also hitting this bug. Did you ever submit a customer report or hear about a fix?

— Reply to this email directly, view it on GitHub https://github.com/slackapi/bolt-js/issues/2138#issuecomment-2302598135, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACAN2FQEO45EAILMLPOCX23ZSTEF3AVCNFSM6AAAAABJSHQPPWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMBSGU4TQMJTGU . You are receiving this because you were mentioned.Message ID: @.***>

alessio-ragni commented 2 weeks ago

Hi Slack team 👋 Do you have an update here? Thanks.

filmaj commented 1 day ago

Hello everyone! The fix for this issue is now rolled out to all Slack workspaces and plans. I just tested this and everything works as desired!

Going to close this issue down but feel free to comment or open a new one if you still have issues.