Skip to content

Instantly share code, notes, and snippets.

@WilliamBergamin
Created January 24, 2025 22:15
Show Gist options
  • Save WilliamBergamin/f550420ec3da3e380d750679d101fa22 to your computer and use it in GitHub Desktop.
Save WilliamBergamin/f550420ec3da3e380d750679d101fa22 to your computer and use it in GitHub Desktop.
Custom Fields With Dynamic Options
import json
import logging
import os
from typing import List, NotRequired, TypedDict
from slack_bolt import Ack, App, Complete, Fail, Say
from slack_bolt.adapter.socket_mode import SocketModeHandler
from slack_sdk import WebClient
logging.basicConfig(level=logging.INFO)
app = App(client=WebClient(token=os.environ.get("SLACK_BOT_TOKEN")))
class Text(TypedDict):
type: str
text: str
class Items(TypedDict):
type: str
class OptionSelect(TypedDict):
text: Text
value: str
class OptionField(TypedDict):
text: Text
key: str
type: str
is_required: NotRequired[bool]
options: NotRequired[List[OptionSelect]]
items: NotRequired[Items]
issue_tracker_options: List[OptionField] = [
{
"text": {
"type": "plain_text",
"text": "Summary",
},
"type": "string",
"key": "summary",
},
{
"text": {
"type": "plain_text",
"text": "Assignee",
},
"type": "slack#/types/user_id",
"key": "assignee",
},
{
"text": {
"type": "plain_text",
"text": "Description",
},
"type": "slack#/types/rich_text",
"key": "description",
},
{
"text": {
"type": "plain_text",
"text": "Project channel",
},
"type": "slack#/types/channel_id",
"key": "channel_id",
"is_required": True,
},
]
def build_string_field_options(keys: List[str]) -> List[OptionField]:
return [
{
"text": {
"type": "plain_text",
"text": key.title(),
},
"type": "string",
"key": key.lower(),
}
for key in keys
]
@app.function("get-fields", auto_acknowledge=False)
def handle_get_fields(
ack: Ack,
inputs: dict,
complete: Complete,
logger: logging.Logger,
):
try:
logger.info(f"Inputs: {json.dumps(inputs, indent=2)}")
custom_field_options: List[OptionField] = build_string_field_options(
keys=inputs.get("custom_string_field_keys", [])
)
complete(
outputs={"options": issue_tracker_options + custom_field_options}
)
finally:
ack()
logger.info("Acknowledged!")
@app.function("create-issue")
def handle_create_issue(
inputs: dict,
say: Say,
fail: Fail,
complete: Complete,
logger: logging.Logger,
):
issue_tracker_fields = inputs["issue_tracker_fields"]
logger.info(
f"issue_tracker_fields: {json.dumps(issue_tracker_fields, indent=2)}"
)
emoji = issue_tracker_fields.get("done.emoji", ":thumbsup:")
try:
say(
channel=issue_tracker_fields[
"channel_id"
], # sending a DM to this user
text="I made an issue and the issue accessories",
blocks=[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"I made an issue and the issue accessories {emoji}",
},
}
],
)
complete(outputs={})
logger.info("I made an issue and the issue accessories")
except Exception as e:
logger.exception(e)
fail(f"Failed to handle a function request (error: {e})")
if __name__ == "__main__":
SocketModeHandler(app, os.environ.get("SLACK_APP_TOKEN")).start()
{
"display_information": {
"name": "custom-field-dynamic-options"
},
"features": {
"bot_user": {
"display_name": "custom-field-dynamic-options",
"always_online": false
}
},
"oauth_config": {
"scopes": {
"bot": [
"chat:write"
]
}
},
"settings": {
"event_subscriptions": {
"bot_events": [
"function_executed"
]
},
"interactivity": {
"is_enabled": true
},
"org_deploy_enabled": true,
"socket_mode_enabled": true,
"token_rotation_enabled": false,
"hermes_app_type": "remote",
"function_runtime": "remote"
},
"functions": {
"create-issue": {
"title": "Create Issue",
"description": "Create an issue with custom fields",
"input_parameters": {
"custom_field_keys": {
"type": "array",
"title": "Custom Field Names",
"description": "Custom Fields as comma seperated values",
"name": "custom_field_keys",
"items": {
"type": "string"
}
},
"issue_tracker_fields": {
"type": "object",
"title": "Issue Tracker Fields",
"description": "All fields used to create the dynamic option",
"is_required": true,
"name": "issue_tracker_fields",
"dynamic_options": {
"function": "#/functions/get-fields",
"inputs": {
"custom_string_field_keys": {
"value": "{{input_parameters.custom_field_keys}}"
}
},
"selection_type": "key-value"
}
}
},
"output_parameters": {}
},
"get-fields": {
"title": "Get fields",
"description": "Get the external issue tracker fields with builder defined fields",
"input_parameters": {
"custom_string_field_keys": {
"type": "array",
"title": "Custom Fields",
"description": "Custom keys to be added as string fields",
"name": "custom_string_field_keys",
"items": {
"type": "string"
}
}
},
"output_parameters": {
"options": {
"type": "slack#/types/options_field",
"title": "Options",
"description": "Custom and issue trakcer fields",
"name": "options"
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment