Getting We had some trouble connecting. Try again? after updating a view. Using aws lambda.
Below code will open a comment modal.
// Handle selection of a pending task in the static select
app.action(
{ type: "block_actions", action_id: /^pending_task_action_(\d+)$/ },
async ({ ack, body, client }) => {
await ack();
const selectedOption = body.actions[0].selected_option.value;
const selectedApplicationId = body.actions[0].block_id;
const userEmail = body.user.name + "@mdsol.com";
// Open a modal with a text input for reason
await client.views.open({
trigger_id: body.trigger_id,
view: {
type: "modal",
callback_id: "reason_modal",
private_metadata: JSON.stringify({
selectedOption,
selectedApplicationId,
userEmail
}),
title: {
type: "plain_text",
text: ":wave: Please comment ",
},
blocks: [
{
type: "input",
block_id: "reason_input",
element: {
type: "plain_text_input",
action_id: "reason",
multiline: true,
},
label: {
type: "plain_text",
text: "Please provide comment for your action:",
},
},
],
submit: {
type: "plain_text",
text: "Submit",
},
},
});
}
);
And After comment we will update the existing view with
// Handle submission of the reason modal
app.view('reason_modal', async ({ ack, body, view, client }) => {
await ack()
const viewId = view.id;
// Open a quick loading modal
await client.views.update({
view_id: viewId,
"response_action": "update",
view: {
type: "modal",
title: {
type: "plain_text",
text: ":man-biking:Processing..",
},
blocks: [
{
type: "section",
text: {
type: "plain_text",
text: ":hourglass_flowing_sand: Please wait while we process your request...",
},
},
],
},
});
**
But I am getting an error as We had some trouble connecting. Try again? after submitting the comment.
**
Hi @tusharwagh-mdsol, thanks for asking the question!
When you want to update the submitted modal in app.view listeners, you can use await ack({ response_action: "update", view: view}) instead of views.update API call. Please refer to https://slack.dev/bolt-js/concepts#view-submissions for more details.
Hi @seratch Thanks for the quick response. So basically i am using aws lambda for hosting my bolt application using JS.
In above code when we submit the comments i want to display processing modal and after that the modal should get updated with another message as this task is completed but here task completion will take some time to complete because we have some api calls as well and also after task completion I have to refresh the homeview as well to remove the completed task.
Can you please suggest best way to do this ?
below is the full code for the same.
// Handle submission of the reason modal
app.view('reason_modal', async ({ ack, body, view, client }) => {
await ack({ response_action: "update", view: view})
const viewId = view.id;
// Open a quick loading modal
await client.views.update({
view_id: viewId,
"response_action": "update",
view: {
type: "modal",
title: {
type: "plain_text",
text: ":man-biking:Processing..",
},
blocks: [
{
type: "section",
text: {
type: "plain_text",
text: ":hourglass_flowing_sand: Please wait while we process your request...",
},
},
],
},
});
const { selectedOption, selectedApplicationId, userEmail } = JSON.parse(view.private_metadata);
const reason = view.state.values.reason_input.reason.value;
const approveruserId = body.user.id;
const pendingTasksUrl = `${process.env.slack_local_api}/pending-tasks?user_email=${userEmail}`;
try {
const response = await axios.get(pendingTasksUrl, {
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.X_API_KEY,
},
});
const tasks = response.data.tasks;
const task = tasks.find(task => task.application_req_ref_id == selectedApplicationId);
if (!task) {
throw new Error("Task not found");
}
const payload = {
_id: task._id,
recordedAction: capitalizeFirstCharacter(selectedOption),
tasktoken: task.tasktoken,
application_req_ref_id: selectedApplicationId,
requestingApplication: task.requestingApplication,
actioned_at: new Date().toISOString().slice(0, 10),
taskName: task.taskName,
description: task.description,
userEmail: userEmail,
reason: reason,
approveruserId: approveruserId,
approvalScheme: task.approvalScheme
};
const approvalUrl = `${process.env.slack_local_api}/slack-approval`;
// Ensure the post request is awaited
await axios.post(approvalUrl, payload, {
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.X_API_KEY,
},
});
// Determine the final title and message based on the selected option
let titleTxt = "";
let blockMsg = "";
switch (selectedOption) {
case "Approve":
titleTxt = "Approved";
blockMsg = "Requested action is completed :white_check_mark:";
break;
case "Reject":
titleTxt = "Rejected";
blockMsg = "Requested action is rejected :x:";
break;
case "Ignore":
titleTxt = "Ignored";
blockMsg = "Requested action is ignored :no_entry_sign:";
break;
default:
titleTxt = "Unknown Action";
blockMsg = "An unknown action was selected.";
}
// Update the modal with the final content
await client.views.update({
view_id: viewId,
"response_action": "update",
view: {
type: "modal",
callback_id: "modal-1",
title: {
type: "plain_text",
text: titleTxt,
},
blocks: [
{
type: "section",
block_id: "section-1",
text: {
type: "mrkdwn",
text: blockMsg,
},
},
],
},
});
try{
// Optionally refresh the pending tasks view
const refreshResponse = await axios.get(pendingTasksUrl, {
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.X_API_KEY,
},
});
const refreshedTasks = refreshResponse.data.tasks;
// Always include the Pending and Completed Tasks buttons
const baseViewBlocks = [
{
type: "section",
text: {
type: "mrkdwn",
text: ":wave: *Welcome to the Approval Application!*\n Please choose between the options to check tasks..",
},
},
{
type: "actions",
elements: [
{
type: "button",
text: {
type: "plain_text",
text: "Pending Tasks",
emoji: true,
},
action_id: "pending_button",
style: "danger",
},
{
type: "button",
text: {
type: "plain_text",
text: "Completed Tasks",
emoji: true,
},
action_id: "completed_button",
style: "primary",
},
],
},
];
if (refreshedTasks.length === 0) {
baseViewBlocks.push(
{
type: "section",
text: {
type: "mrkdwn",
text: "*You have no pending tasks at the moment.*",
},
},
{
type: "section",
text: {
type: "mrkdwn",
text: "*Please check back later or contact support if you believe this is an error.*",
},
}
);
await client.views.publish({
user_id: body.user.id,
"response_action": "clear",
view: {
type: "home",
blocks: baseViewBlocks,
},
});
return;
}
const uniqueCategories = [...new Set(refreshedTasks.map(task => task.requestingApplication))];
const defaultCategory = uniqueCategories.includes(task.requestingApplication) ? task.requestingApplication : uniqueCategories[0];
const tasksForDefaultCategory = getTasksForCategory(defaultCategory, refreshedTasks);
const categoryButtons = uniqueCategories.map(category => {
const tasksForCategory = getTasksForCategory(category, refreshedTasks);
const pendingTasksCount = tasksForCategory.length;
return {
type: "button",
text: {
type: "plain_text",
text: `${category} (${pendingTasksCount})`,
},
action_id: `pending_category_${category.replace(/\s/g, "_")}_button`,
style: selectedCategory === category ? "primary" : "danger",
};
});
const tasksBlocks = tasksForDefaultCategory.map((task, index) => [
{
type: "section",
block_id: `${task.application_req_ref_id}`,
text: {
type: "mrkdwn",
text: `:clipboard: *Task ${index + 1}:* <${task.req_app_redirect_url}| ${task.application_req_ref_id}> ${task.taskName}`,
},
accessory: {
type: "static_select",
action_id: `pending_task_action_${index + 1}`,
placeholder: {
type: "plain_text",
text: "Select an action",
},
options: getOptionsForTaskActions(task.actions),
},
},
{
type: "divider",
},
]).flat();
const view = {
type: "home",
blocks: [
...baseViewBlocks,
{
type: "section",
text: {
type: "mrkdwn",
text: "*Please choose between below tasks category*",
},
},
{
type: "actions",
elements: categoryButtons,
},
{
type: "divider",
},
{
type: "section",
text: {
type: "mrkdwn",
text: `Selected Category Tasks (${defaultCategory}):`,
},
},
...tasksBlocks,
],
};
await client.views.publish({
user_id: body.user.id,
"response_action": "clear",
view,
});
}catch (error) {
// Always include the Pending and Completed Tasks buttons
const baseViewBlocks = [
{
type: "section",
text: {
type: "mrkdwn",
text: ":wave: *Welcome to the Approval Application!*\n Please choose between the options to check tasks..",
},
},
{
type: "actions",
elements: [
{
type: "button",
text: {
type: "plain_text",
text: "Pending Tasks",
emoji: true,
},
action_id: "pending_button",
style: "danger",
},
{
type: "button",
text: {
type: "plain_text",
text: "Completed Tasks",
emoji: true,
},
action_id: "completed_button",
style: "primary",
},
],
},
];
baseViewBlocks.push(
{
type: "section",
text: {
type: "mrkdwn",
text: "*You have no pending tasks at the moment.*",
},
},
{
type: "section",
text: {
type: "mrkdwn",
text: "*Please check back later or contact support if you believe this is an error.*",
},
}
);
await client.views.publish({
user_id: body.user.id,
"response_action": "clear",
view: {
type: "home",
blocks: baseViewBlocks,
},
});
return;
}
} catch (error) {
let errorMessage = "Something went wrong while processing your request.";
if (error.response && error.response.status === 404) {
errorMessage = "You have caught up with all tasks! :white_check_mark:";
}
await client.views.update({
view_id: viewId,
"response_action": "update",
view: {
type: "modal",
title: {
type: "plain_text",
text: "Congratulations!",
},
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: errorMessage,
},
},
],
},
});
}
});
bolt-python's lazy listeners could be the best solution for your use case: https://slack.dev/bolt-python/concepts#lazy-listeners However, unfortunately the same functionality does not exist in bolt-js due to its design restrictions. Also, we don't have plans to enhance bolt-js for the need.
If we want to write your app using bolt-js + AWS Lambda, the only suggestion I can give is to have a queue for delegating the time-consuming task to a different Lambda function. You can store the event payload and view_id etc. into the queue message. With that, the async task worker function can update the end-user once the task completes.
I hope this helps. Is everyting clear now? If yes, would you mind closing this?
👋 It looks like this issue has been open for 30 days with no activity. We'll mark this as stale for now, and wait 10 days for an update or for further comment before closing this issue out. If you think this issue needs to be prioritized, please comment to get the thread going again! Maintainers also review issues marked as stale on a regular basis and comment or adjust status if the issue needs to be reprioritized.
As this issue has been inactive for more than one month, we will be closing it. Thank you to all the participants! If you would like to raise a related issue, please create a new issue which includes your specific details and references this issue number.