-
Notifications
You must be signed in to change notification settings - Fork 245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shortcut modal does not close after submit #610
Comments
Hi @BSouzaDock, sorry you're having this issue. What kind of logs do you see from your app's side? I'm not exactly sure what the error you are seeing implies, or where it is happening. Is this showing up in your modal that you are trying to close? The only thing I can see is that your |
If I take the code below the ack() it works and closes the modal. The error validation part works normally. When I put this code snippet below ack(), after clicking on submit it takes about 3 seconds and this message from the print I sent appears. In the aws logs it does not generate any kind of error despite this image message, which I found strange. |
Oh is this app running on AWS? You may want to look at the Lazy Listeners section of the Bolt for Python docs. You may also want to check the AWS example apps for Bolt we have in the |
I believe the problem is the same. I didn't find any example of lazy with view submition coming from a shortcut . Do you have an example to show? I found from action and workflowstep |
I would suggest you try to combine the |
I had already managed to use lazy with workflowstep like this: def execute_step(step: dict, complete: Complete, fail: Fail)
@step_builder.execute(lazy=[execute_step])
def execute():
pass I tried this way but it didn't work("Syntax error in module 'init': invalid syntax"): def handle_view_events(ack, body, client, view):...
@app.view("aws_access_request")(lazy=[handle_view_events])
def handle():
pass Can you tell me if this view method using decorator accepts lazy? |
The |
@filmaj , Many thanks for the reply. I managed to do it this way: def handle_errors(ack, view):...
def handle_submit(body, client, view):...
app.view("aws_access_request")(ack=handle_errors, lazy=[handle_submit]) The problem is that I have to validate 2 fields in the form. In this way, regardless of whether the fields are filled in correctly or not, the lazy function is executed. The user receives a message as if the form has been successfully executed, while still validating errors: |
@BSouzaDock can you share your full code? How you construct your App, your full handle_errors and handle_submit methods, etc.? |
I saw this problem being mentioned in another thread: Is it not the same case I'm experiencing? This is the full shortcut code: from applications.okta.okta_utils import OktaTools
from applications.slack.features.workflow.aws_access_request.utils import get_workflow_block_fail, \
send_block_fail_message, get_workflow_block_success, send_request_aws_message
from applications.slack.main.slack_main import SlackTools
from util.constants import *
Ot = OktaTools()
St = SlackTools()
def get_shortcuts(app):
formdesc = "Peencha os campos abaixo para solicitar seu acesso. \n\nA solicitação será enviada para aprovação do " \
"gestor e você receberá uma notificação no privado após a resposta."
allawsoptions = [
{
"text": {
"type": "plain_text",
"text": "AWS Acquirer - HML"
},
"value": "AWS Acquirer - HML"
},
{
"text": {
"type": "plain_text",
"text": "AWS Acquirer - PRD"
},
"value": "AWS Acquirer - PRD"
},
{
"text": {
"type": "plain_text",
"text": "AWS C6 - DEV"
},
"value": "AWS C6 - DEV"
},
{
"text": {
"type": "plain_text",
"text": "AWS C6 - HML"
},
"value": "AWS C6 - HML"
},
{
"text": {
"type": "plain_text",
"text": "AWS C6 - PRD"
},
"value": "AWS C6 - PRD"
},
{
"text": {
"type": "plain_text",
"text": "AWS Dablam - Banking"
},
"value": "AWS Dablam - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS Datalake HML - Banking"
},
"value": "AWS Datalake HML - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS Datalake HML - Core"
},
"value": "AWS Datalake HML - Core"
},
{
"text": {
"type": "plain_text",
"text": "AWS Datalake PRD - Banking"
},
"value": "AWS Datalake PRD - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS Dev - Banking"
},
"value": "AWS Dev - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS Dev - Core"
},
"value": "AWS Dev - Core"
},
{
"text": {
"type": "plain_text",
"text": "AWS DevOpsTools - Banking"
},
"value": "AWS DevOpsTools - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS DevopsTools - Core"
},
"value": "AWS DevopsTools - Core"
},
{
"text": {
"type": "plain_text",
"text": "AWS DevopsTools - DEV"
},
"value": "AWS DevopsTools - DEV"
},
{
"text": {
"type": "plain_text",
"text": "AWS DevopsTools - PRD"
},
"value": "AWS DevopsTools - PRD"
},
{
"text": {
"type": "plain_text",
"text": "AWS Dock CloudTribe - DEV"
},
"value": "AWS Dock CloudTribe - DEV"
},
{
"text": {
"type": "plain_text",
"text": "AWS Dock Tech Advocacy - DEV"
},
"value": "AWS Dock Tech Advocacy - DEV"
},
{
"text": {
"type": "plain_text",
"text": "AWS DR - Banking"
},
"value": "AWS DR - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS DR - Core"
},
"value": "AWS DR - Core"
},
{
"text": {
"type": "plain_text",
"text": "AWS HML - Banking"
},
"value": "AWS HML - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS HML - Core"
},
"value": "AWS HML - Core"
},
{
"text": {
"type": "plain_text",
"text": "AWS Internal - Architecture"
},
"value": "AWS Internal - Architecture"
},
{
"text": {
"type": "plain_text",
"text": "AWS Julius - HML"
},
"value": "AWS Julius - HML"
},
{
"text": {
"type": "plain_text",
"text": "AWS Julius - PRD"
},
"value": "AWS Julius - PRD"
},
{
"text": {
"type": "plain_text",
"text": "AWS Merci"
},
"value": "AWS Merci"
},
{
"text": {
"type": "plain_text",
"text": "AWS Merci - HML"
},
"value": "AWS Merci - HML"
},
{
"text": {
"type": "plain_text",
"text": "AWS Network - Banking"
},
"value": "AWS Network - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS Network - Core"
},
"value": "AWS Network - Core"
},
{
"text": {
"type": "plain_text",
"text": "AWS PRD - Banking"
},
"value": "AWS PRD - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS PRD - Core"
},
"value": "AWS PRD - Core"
},
{
"text": {
"type": "plain_text",
"text": "AWS QA - Banking"
},
"value": "AWS QA - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS QA - Core"
},
"value": "AWS QA - Core"
},
{
"text": {
"type": "plain_text",
"text": "AWS Root - Banking"
},
"value": "AWS Root - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS Security - Banking"
},
"value": "AWS Security - Banking"
},
{
"text": {
"type": "plain_text",
"text": "AWS Security - Dev"
},
"value": "AWS Security - Dev"
},
{
"text": {
"type": "plain_text",
"text": "AWS Shared - PRD"
},
"value": "AWS Shared - PRD"
}
]
nothingoption = [{
"text": {
"type": "plain_text",
"text": "Nothing found :sob:"
},
"value": "nothing"
}]
roleoptions = [
{
"text": {
"type": "plain_text",
"text": "Developers",
"emoji": True
},
"value": "Developers"
},
{
"text": {
"type": "plain_text",
"text": "Qa",
"emoji": True
},
"value": "Qa"
},
{
"text": {
"type": "plain_text",
"text": "Cloud",
"emoji": True
},
"value": "Cloud"
},
{
"text": {
"type": "plain_text",
"text": "DBA",
"emoji": True
},
"value": "DBA"
},
{
"text": {
"type": "plain_text",
"text": "Data",
"emoji": True
},
"value": "Data"
},
{
"text": {
"type": "plain_text",
"text": "Architect",
"emoji": True
},
"value": "Architect"
},
{
"text": {
"type": "plain_text",
"text": "Telecom",
"emoji": True
},
"value": "Telecom"
},
{
"text": {
"type": "plain_text",
"text": "SRE",
"emoji": True
},
"value": "SRE"
},
{
"text": {
"type": "plain_text",
"text": "PSE",
"emoji": True
},
"value": "PSE"
},
{
"text": {
"type": "plain_text",
"text": "Csops",
"emoji": True
},
"value": "Csops"
},
{
"text": {
"type": "plain_text",
"text": "StarOps",
"emoji": True
},
"value": "StarOps"
},
{
"text": {
"type": "plain_text",
"text": "Account Manager",
"emoji": True
},
"value": "Account Manager"
},
{
"text": {
"type": "plain_text",
"text": "Techleads",
"emoji": True
},
"value": "Techleads"
},
{
"text": {
"type": "plain_text",
"text": "CloudSecurity",
"emoji": True
},
"value": "CloudSecurity"
}
]
@app.shortcut("aws_access_request")
def handle_shortcuts(ack, body, client):
# Acknowledge the command request
ack()
# Call views_open with the built-in client
client.views_open(
# Pass a valid trigger_id within 3 seconds of receiving it
trigger_id=body["trigger_id"],
# View payload
view={
"type": "modal",
# View identifier
"callback_id": "aws_access_request",
"title": {"type": "plain_text", "text": "AWS Access Request"},
"submit": {"type": "plain_text", "text": "Submit"},
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": formdesc
},
"accessory": {
"type": "image",
"image_url": "https://a0.awsstatic.com/libra-css/images/logos/aws_logo_smile_1200x630.png",
"alt_text": "AWS Access Request"
}
},
{
"type": "input",
"block_id": "input_aws_select",
"element": {
"action_id": "aws_access_select",
"type": "external_select",
"placeholder": {
"type": "plain_text",
"text": "Select or enter the expected value..."
},
"min_query_length": 0
},
"label": {
"type": "plain_text",
"text": "AWS que deseja acessar:",
"emoji": True
}
},
{
"type": "input",
"block_id": "input_aws_role_select",
"element": {
"action_id": "aws_access_role_select",
"type": "static_select",
"placeholder": {
"type": "plain_text",
"text": "Select an item..."
},
"options": roleoptions
},
"label": {
"type": "plain_text",
"text": "Role:",
"emoji": True
}
},
{
"type": "input",
"block_id": "input_aws_access_squad",
"element": {
"type": "plain_text_input",
"action_id": "aws_access_squad"
},
"label": {
"type": "plain_text",
"text": "Squad/Area de atuação:",
"emoji": True
}
},
{
"type": "input",
"block_id": "input_aws_access_reason",
"element": {
"type": "plain_text_input",
"multiline": True,
"action_id": "aws_access_reason"
},
"label": {
"type": "plain_text",
"text": "Motivo do acesso na conta AWS:",
"emoji": True
}
},
{
"type": "input",
"block_id": "input_aws_access_manager",
"element": {
"type": "plain_text_input",
"action_id": "aws_access_manager"
},
"label": {
"type": "plain_text",
"text": "E-mail do seu gestor imediato:",
"emoji": True
}
}
]
}
)
@app.options("aws_access_select")
def handle_some_options(ack, body):
keyword = body.get("value")
if len(keyword) > 0:
options = [o for o in allawsoptions if
str(o["text"]["text"]).upper().find(keyword.upper()) >= 0]
if len(options) == 0:
options = nothingoption
ack(options=options)
elif keyword is None or len(keyword) == 0:
ack(options=allawsoptions)
def handle_errors(ack, view):
# Assume there's an input block with `input_c` as the block_id and `dreamy_input`
awsname = view["state"]["values"]["input_aws_select"]["aws_access_select"]["selected_option"]["value"]
reason = view["state"]["values"]["input_aws_access_reason"]["aws_access_reason"]["value"]
# Validate inputs
errors = {}
mincaracter = 25
if reason is not None and len(reason) <= mincaracter:
errors["input_aws_access_reason"] = f"The value must be longer than {mincaracter} characters"
elif awsname == "nothing":
errors["input_aws_select"] = "Please select valid option"
if len(errors) > 0:
ack(response_action="errors", errors=errors)
return
# Acknowledge the view_submission request and close the modal
ack()
def handle_submit(body, client, view):
awsname = view["state"]["values"]["input_aws_select"]["aws_access_select"]["selected_option"]["value"]
awsrole = view["state"]["values"]["input_aws_role_select"]["aws_access_role_select"]["selected_option"]["value"]
managermail = view["state"]["values"]["input_aws_access_manager"]["aws_access_manager"]["value"]
squad = view["state"]["values"]["input_aws_access_squad"]["aws_access_squad"]["value"]
reason = view["state"]["values"]["input_aws_access_reason"]["aws_access_reason"]["value"]
senderid = body["user"]["id"]
senderobj = client.users_profile_get(user=senderid)
sendermail = senderobj["profile"]["email"]
sendermention = f"<@{senderid}>"
sendername = senderobj["profile"]["display_name"]
inputs = {
"awsName": {
"value": awsname
},
"awsRole": {
"value": awsrole
},
"managerMail": {
"value": managermail
}
}
checkinputname = Ot.check_inputs(inputs, INPUT_AWS_NAME)
checkinputmanager = Ot.check_inputs(inputs, INPUT_MANAGER_MAIL)
# Caso o usuário não tenha informado corretamente o Acesso/Gestor, não envia a solicitação
if not checkinputname or not checkinputmanager:
if not checkinputname:
# errmsg = {
# "message": f"Acesso {awsname} não encontrado! Olhar no Pin fixado do canal o nome de cada AWS."}
blocklayout = FAIL_MSG_AWS_NAME
else:
# errmsg = {"message": f"Gestor {managermail} não encontrado no ambiente!"}
blocklayout = FAIL_MSG_MANAGER_MAIL
# fail(error=errmsg)
blockfail = get_workflow_block_fail(sendermention, managermail, awsname, awsrole, blocklayout)
send_block_fail_message(blockfail, senderid)
else:
try:
manager = client.users_lookupByEmail(email=managermail)
managerid = manager["user"]["id"]
blocksuccess = get_workflow_block_success(sendermention, awsname)
send_request_aws_message(sendername, sendermail, sendermention,
awsname, awsrole, squad, reason, managermail, managerid)
except Exception as e:
if "users_not_found" in str(e):
# error = {"message": f"Gestor {managermail} não encontrado no ambiente!"}
# fail(error=error)
blocklayout = FAIL_MSG_MANAGER_MAIL
blockfail = get_workflow_block_fail(sendermention, managermail, awsname, awsrole, blocklayout)
send_block_fail_message(blockfail, senderid)
else:
# error = {"message": "Just testing step failure! {}".format(e)}
# fail(error=error)
St.webhook_directly(WEBHOOK_LOGS_URI_FAIL, e, FAIL)
else:
client.chat_postMessage(text="Envio com sucesso de solicitação de acesso AWS",
blocks=blocksuccess,
channel=senderid)
app.view("aws_access_request")(ack=handle_errors, lazy=[handle_submit]) |
Oh nice find; yes it seems like it is not possible at this time. Looks like @seratch recommends to duplicate the error validation in the lazy functions. Perhaps we could improve the behaviour to enable this pattern of only running lazy functions if |
Regarding the limitation of lazy listeners mentioned here, as I responded in that thread, having the same validation on the lazy function side is the recommended way. @BSouzaDock By the way, are you running your app on AWS Lambda? If not, you don't need to use lazy listeners if the feature does not fit. You can merge |
Hi,
I developed a shortcut but after submitting by submit button, the modal is not closed.
After the submit, several validations are carried out and a message is sent to the user, but I want the modal to be closed and these processes to be in the background, as it consumes a lot of time and there is no need for the user to wait.
In the documentation it asks to be done this way:
I did it this way:
After ack() "Acknowledge the view_submission request and close the modal" It is not closing the modal and continues running the code below.
The problem is that the code below ack() takes about 10 seconds to run, so this error appears:
As I said, I wanted the form to close immediately after ack() and not wait for all the code to run to close.
The text was updated successfully, but these errors were encountered: