[ERROR] bolt-app no more than 100 items allowed [json-pointer:/view/blocks/0/element/options]
Closed this issue · 13 comments
(Describe your issue and goal here)
const result = await client.views.open({
trigger_id: body.trigger_id,
view: {
type: 'modal',
callback_id: 'select_company_modal',
title: {
type: 'plain_text',
text: 'Select Company'
},
blocks: [
{
type: 'input',
block_id: 'company_dropdown',
element: {
type: 'static_select',
action_id: 'company_select',
placeholder: {
type: 'plain_text',
text: 'Select a company'
},
options: customerOptions
},
label: {
type: 'plain_text',
text: 'Company'
}
}
],
submit: {
type: 'plain_text',
text: 'Get Details',
},
}
});
I have the above code snippet to open a modal and the customerOptions
array has around 650 items. Is it not possible to show more than 100 items in the dropdown?
Reproducible in:
The Slack SDK version
"slack/bolt": "^3.17.1",
"slack-block-builder": "^2.8.0",
Node.js runtime version
v16.20.2
OS info
ProductName: macOS
ProductVersion: 14.3.1
BuildVersion: 23D60
Darwin Kernel Version 23.3.0: Wed Dec 20 21:30:59 PST 2023; root:xnu-10002.81.5~7/RELEASE_ARM64_T6030
Steps to reproduce:
(Share the commands to run, source code, and project settings)
Expected result:
Display all the 600+ items in the dropdown
Actual result:
Throwing the following error:
[ERROR] bolt-app failed to match all allowed schemas [json-pointer:/view]
[ERROR] bolt-app no more than 100 items allowed [json-pointer:/view/blocks/0/element/options]
Error: An API error occurred: invalid_arguments
at platformErrorFromResult (/Users/pritishsamal/Documents/EscalationBot/node_modules/@slack/web-api/dist/errors.js:62:33)
at WebClient.apiCall (/Users/pritishsamal/Documents/EscalationBot/node_modules/@slack/web-api/dist/WebClient.js:181:56)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async CustomerDetailsController (/Users/pritishsamal/Documents/EscalationBot/src/slashCommands/customerDetails.js:33:28)
at async Array.<anonymous> (/Users/pritishsamal/Documents/EscalationBot/node_modules/@slack/bolt/dist/middleware/builtin.js:211:9)
at async Array.onlyCommands (/Users/pritishsamal/Documents/EscalationBot/node_modules/@slack/bolt/dist/middleware/builtin.js:45:5) {
code: 'slack_webapi_platform_error',
data: {
ok: false,
error: 'invalid_arguments',
response_metadata: { messages: [Array], scopes: [Array] }
}
}
Requirements
For general questions/issues about Slack API platform or its server-side, could you submit questions at https://my.slack.com/help/requests/new instead. 🙇
Please read the Contributing guidelines and Code of Conduct before creating this issue or pull request. By submitting, you are agreeing to those rules.
Hi @CIPHERTron, thanks for asking the question!
I have the above code snippet to open a modal and the customerOptions array has around 650 items. Is it not possible to show more than 100 items in the dropdown?
Unfortunately, it's not possible to display more than 100 items in a static_select dropdown menu. However, for large data sets like yours, you may consider using the external_select menu: https://slack.dev/bolt-js/concepts#options
I hope you find this information helpful!
Hi @seratch , thank you so much for the quick reply. Let me explore the external_select
menu
Hi again @seratch, now I am using external_select like shown below:
if (customerName === 'list') {
try {
const result = await client.views.open({
trigger_id: body.trigger_id,
view: {
type: 'modal',
callback_id: 'select_company_modal',
title: {
type: 'plain_text',
text: 'Customer 360° Insights',
emoji: true
},
submit: {
type: 'plain_text',
text: 'Get Details',
},
close: {
type: "plain_text",
text: "Cancel Search",
emoji: true
},
blocks: [
{
type: "input",
element: {
type: "external_select",
action_id: "company_select",
placeholder: {
type: "plain_text",
text: "Start typing a customer name...",
emoji: true,
},
},
label: {
type: "plain_text",
text: "Search for a customer",
emoji: true,
},
}
],
}
});
// Acknowledge the command request
await ack();
}
and passing it options like this:
app.options({ action_id: /company_select/ }, async ({ ack }) => {
const customerOptions = customers.map(customer => {
return {
"text": {
"type": 'plain_text',
"text": customer
},
"value": customer
}
})
await ack({
"options": customerOptions
})
});
However, i'm not able to see the options getting listed in the dropdown select. it's always showing "Nothing could be found"
Could you pls help me out here? I'm not exactly sure what I'm doing wrong
Please double-check if you've configured Features > Interactivity & Shortcuts > Select Menus > Options Load URL on the https://api.slack.com/apps/{your app id}
site.
Also, having min_query_length:1 will make the user experience more intuitive. For more details, please refer to this page: https://api.slack.com/reference/block-kit/block-elements#external_select
As of now, I'm using hardcoded options but then also, I'm unable to load the options in slack. I'm getting the same message: Nothing could be found
app.options({ action_id: /company_select/ }, async ({ ack }) => {
console.log("Set Company select options invoked")
try {
// Call an API or perform any asynchronous operation to fetch options
const options = [
{
text: {
type: 'plain_text',
text: 'One'
},
value: '111'
},
{
text: {
type: 'plain_text',
text: 'Two'
},
value: '222'
},
{
text: {
type: 'plain_text',
text: 'Three'
},
value: '333'
}
];
// Acknowledge the options request and return the options
await ack({
options: options
});
} catch (error) {
console.error(error);
}
});
I've confirmed your example (I rewrote it slightly for TypeScript compatibility) works for me without any issues. Please double-check if you've configured the Features > Interactivity & Shortcuts > Select Menus > Options Load URL correctly, plus your app.options
listener passes a valid response data to ack()
method call.
import { App, BlockAction, Option } from "@slack/bolt";
export function registerListeners(app: App) {
app.event("message", async ({ say }) => {
await say({
text: "hi!",
blocks: [
{
type: "actions",
elements: [
{
type: "button",
action_id: "test",
text: { type: "plain_text", text: "Click Me" },
value: "click_me_123",
},
],
},
],
});
});
app.action<BlockAction>("test", async ({ body, client, ack }) => {
await ack();
await client.views.open({
trigger_id: body.trigger_id,
view: {
type: "modal",
callback_id: "select_company_modal",
title: {
type: "plain_text",
text: "Select Company",
},
blocks: [
{
type: "input",
element: {
type: "external_select",
action_id: "company_select",
placeholder: {
type: "plain_text",
text: "Start typing a customer name...",
emoji: true,
},
},
label: {
type: "plain_text",
text: "Search for a customer",
emoji: true,
},
},
],
submit: {
type: "plain_text",
text: "Get Details",
},
},
});
});
app.options<"block_suggestion">(
{ action_id: /company_select/ },
async ({ ack }) => {
const options: Option[] = [
{
text: {
type: "plain_text",
text: "One",
},
value: "111",
},
{
text: {
type: "plain_text",
text: "Two",
},
value: "222",
},
{
text: {
type: "plain_text",
text: "Three",
},
value: "333",
},
];
await ack({ options });
}
);
}
Hey @seratch , apologies for bugging you multiple times. The external_select
method didn't work for me so I reverted back to the static_select
way of showing the list items and instead of using options
, I used option_groups
. I'm doing it as shown below and I'm able to see all the options as expected. I just wanted to know how do we check which option the user has selected? Would really appreciate If you could help me with this. Thanks much!
const customerName = body.text.trim();
const urlEncodesCustomername = encodeURIComponent(customerName)
const customersHash = categorizeCustomersByAlphabet(customers)
const optionGroupsArray = [] // store option groups alphabetically
const optionGroupKeys = Object.keys(customersHash)
optionGroupKeys.forEach((key) => {
const hashkeyValue = customersHash[key]
let options = [];
if(hashkeyValue && hashkeyValue.length > 0) {
options = hashkeyValue.map(customer => {
return {
text: {
type: 'plain_text',
text: customer
},
value: encodeURIComponent(customer)
}
})
}
let group = {
"label": {
"type": "plain_text",
"text": key
},
"options": options
};
optionGroupsArray.push(group)
})
if (customerName === 'list') {
try {
const result = await client.views.open({
trigger_id: body.trigger_id,
view: {
type: 'modal',
callback_id: 'select_company_modal',
title: {
type: 'plain_text',
text: 'Customer 360° Insights'
},
blocks: [
{
type: 'input',
block_id: 'company_dropdown',
element: {
type: 'static_select',
action_id: 'company_select',
placeholder: {
type: 'plain_text',
text: 'Start typing to view suggestions...'
},
option_groups: optionGroupsArray
},
label: {
type: 'plain_text',
text: 'Select a customer from the dropdown'
}
}
],
submit: {
type: 'plain_text',
text: 'Get Details',
},
}
});
console.log(result)
} catch (error) {
console.error(error);
}
}
You can receive the selected item under body.view.state.values.{block_id}.{action_id} data structure in app.view("your_callback_id_here", listener)
listener.
Glad to hear that you've achieved your goal with static select! If everything is clear now, would you mind closing this?
Got it. Thanks!
Yeah sure, I can go ahead and close it.
@seratch I did as you have mentioned above but when I click on the "Get Details" or Submit button, the @app.view("your_callback_id_here")
controller doesn't get triggered in the first place. Am I doing something wrong?
app.view('select_company_modal', async ({ ack, body, view, client }) => {
await ack();
console.log("body", body)
console.log("view", view)
});
Have you properly configured "Request URL" under the "Interactivity & Shortcuts" section on api.slack.com/apps/{your app id}
site?
Oh okay, that might be the problem. The "Request URL" under the "Interactivity & Shortcuts" section was pointing to the prod GCP cluster external url and slash command request url was pointing to my local ngrok. Let me change that and try again
Yes, that was the issue. It's fixed and I'm able to see the selected option. Really appreciate your help and quick response @seratch.
Closing this issue!