Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4c43f1b
Add Dialogs handler
heyitsaamir Nov 24, 2025
5a48dee
Fix
heyitsaamir Nov 24, 2025
e85535f
Fix
heyitsaamir Nov 24, 2025
4ca5e71
Fix naming
heyitsaamir Nov 24, 2025
ae1e409
Update packages/cards/src/microsoft/teams/cards/utilities/open_dialog.py
heyitsaamir Nov 24, 2025
df7a500
Fix build
heyitsaamir Nov 25, 2025
9b5eefd
Merge remote-tracking branch 'origin' into aamirj/dialogs
heyitsaamir Nov 29, 2025
40e50a0
Merge remote-tracking branch 'origin' into aamirj/dialogs
heyitsaamir Dec 4, 2025
2e22017
Merge remote-tracking branch 'origin' into aamirj/dialogs
heyitsaamir Dec 4, 2025
6d06e9f
Merge remote-tracking branch 'origin' into aamirj/dialogs
heyitsaamir Dec 5, 2025
200c263
Merge remote-tracking branch 'origin' into aamirj/dialogs
heyitsaamir Dec 5, 2025
1f21f23
Fix imports
heyitsaamir Dec 5, 2025
b15818d
Merge remote-tracking branch 'origin' into aamirj/dialogs
heyitsaamir Dec 11, 2025
4f2db64
on_card_action -> on_card_execute
heyitsaamir Dec 11, 2025
bc29f28
fix merge conflicts
Mar 23, 2026
90baecb
Merge branch 'main' into aamirj/dialogs
lilyydu Mar 23, 2026
b432592
remove print and mock logger from dialog tests
Mar 24, 2026
7f23ce2
remove outdated activity targeted test and mock logger from action ro…
Mar 24, 2026
ea4ee6a
Merge branch 'main' into aamirj/dialogs
heyitsaamir Mar 25, 2026
74656b9
Merge branch 'main' into aamirj/dialogs
lilyydu Mar 30, 2026
cf614ea
address PR comments
Mar 30, 2026
8cd823d
merge w main
Apr 1, 2026
8604183
rename EnahncedSubmitActionData to SubmitData
Apr 1, 2026
29d6e17
fix sample
Apr 1, 2026
951b3bb
rename to .open_dialog_data
Apr 1, 2026
0909ca4
update dialogs sample w rename
Apr 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 111 additions & 71 deletions examples/cards/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@

from microsoft_teams.api import AdaptiveCardInvokeActivity, MessageActivity, MessageActivityInput
from microsoft_teams.api.models.adaptive_card import (
AdaptiveCardActionErrorResponse,
AdaptiveCardActionMessageResponse,
)
from microsoft_teams.api.models.error import HttpError, InnerHttpError
from microsoft_teams.api.models.invoke_response import AdaptiveCardInvokeResponse
from microsoft_teams.apps import ActivityContext, App
from microsoft_teams.cards import (
Expand All @@ -20,6 +18,7 @@
ExecuteAction,
NumberInput,
OpenUrlAction,
SubmitData,
TextBlock,
ToggleInput,
)
Expand All @@ -29,15 +28,33 @@


def create_basic_adaptive_card() -> AdaptiveCard:
"""Create a basic adaptive card for testing."""
"""Create a basic adaptive card for testing - uses ExecuteAction with specific action routing."""
card = AdaptiveCard(
schema="http://adaptivecards.io/schemas/adaptive-card.json",
body=[
TextBlock(text="Hello world", wrap=True, weight="Bolder"),
TextBlock(text="Specific Action Routing", wrap=True, weight="Bolder"),
ToggleInput(label="Notify me").with_id("notify"),
ActionSet(
actions=[
ExecuteAction(title="Submit").with_data({"action": "submit_basic"}).with_associated_inputs("auto")
ExecuteAction(title="Submit").with_data(SubmitData("submit_basic")).with_associated_inputs("auto")
]
),
],
)
return card


def create_generic_execute_card() -> AdaptiveCard:
"""Create a card with ExecuteAction that uses global handler (no specific action routing)."""
card = AdaptiveCard(
schema="http://adaptivecards.io/schemas/adaptive-card.json",
body=[
TextBlock(text="Global Handler (No Action)", wrap=True, weight="Bolder"),
TextBlock(text="This card doesn't have a specific action handler", wrap=True),
ToggleInput(label="Enable feature").with_id("enabled"),
ActionSet(
actions=[
ExecuteAction(title="Submit").with_data({"some_field": "some_value"}).with_associated_inputs("auto")
]
),
],
Expand Down Expand Up @@ -110,7 +127,7 @@ def create_profile_card() -> AdaptiveCard:
ActionSet(
actions=[
ExecuteAction(title="Save")
.with_data({"action": "save_profile", "entity_id": "12345"})
.with_data(SubmitData("save_profile", {"entity_id": "12345"}))
.with_associated_inputs("auto"),
OpenUrlAction(url="https://adaptivecards.microsoft.com").with_title("Learn More"),
]
Expand Down Expand Up @@ -156,7 +173,7 @@ def create_feedback_card() -> AdaptiveCard:
ActionSet(
actions=[
ExecuteAction(title="Submit Feedback")
.with_data({"action": "submit_feedback"})
.with_data(SubmitData("submit_feedback"))
.with_associated_inputs("auto")
]
),
Expand All @@ -167,12 +184,20 @@ def create_feedback_card() -> AdaptiveCard:

@app.on_message_pattern("card")
async def handle_card_message(ctx: ActivityContext[MessageActivity]):
"""Handle card request messages."""
print(f"[CARD] Card requested by: {ctx.activity.from_}")
"""Handle card request messages - specific action routing."""
print(f"[CARD] Card with specific action routing requested by: {ctx.activity.from_}")
card = create_basic_adaptive_card()
await ctx.send(card)


@app.on_message_pattern("generic")
async def handle_generic_card_message(ctx: ActivityContext[MessageActivity]):
"""Handle generic card request messages - global handler."""
print(f"[GENERIC] Card with global handler requested by: {ctx.activity.from_}")
card = create_generic_execute_card()
await ctx.send(card)


@app.on_message_pattern("json")
async def handle_validate_card_message(ctx: ActivityContext[MessageActivity]):
"""Handle model validation card request messages."""
Expand Down Expand Up @@ -207,7 +232,7 @@ async def handle_form(ctx: ActivityContext[MessageActivity]):
ActionSet(
actions=[
ExecuteAction(title="Create Task")
.with_data({"action": "create_task"})
.with_data(SubmitData("create_task"))
.with_associated_inputs("auto")
.with_style("positive")
]
Expand Down Expand Up @@ -242,69 +267,84 @@ async def handle_feedback_card(ctx: ActivityContext[MessageActivity]):
await ctx.send(card)


@app.on_card_action
async def handle_form_action(ctx: ActivityContext[AdaptiveCardInvokeActivity]) -> AdaptiveCardInvokeResponse:
"""Handle card action submissions from form example."""
@app.on_card_action_execute
Comment thread
lilyydu marked this conversation as resolved.
Comment thread
lilyydu marked this conversation as resolved.
async def handle_all_execute_actions(ctx: ActivityContext[AdaptiveCardInvokeActivity]) -> AdaptiveCardInvokeResponse:
"""Handle all Action.Execute events without specific action routing (global handler)."""
data = ctx.activity.value.action.data
if not data.get("action"):
print(ctx.activity)
return AdaptiveCardActionErrorResponse(
status_code=400,
type="application/vnd.microsoft.error",
value=HttpError(
code="BadRequest",
message="No action specified",
inner_http_error=InnerHttpError(
status_code=400,
body={"error": "No action specified"},
),
),
)

print("Received action data:", data)

if data["action"] == "submit_basic":
notify_value = data.get("notify", "false")
await ctx.send(f"Basic card submitted! Notify setting: {notify_value}")
elif data["action"] == "submit_feedback":
feedback_text = data.get("feedback", "No feedback provided")
await ctx.send(f"Feedback received: {feedback_text}")
elif data["action"] == "create_task":
title = data.get("title", "Untitled")
priority = data.get("priority", "medium")
due_date = data.get("due_date", "No date")
await ctx.send(f"Task created!\nTitle: {title}\nPriority: {priority}\nDue: {due_date}")
elif data["action"] == "save_profile":
entity_id = data.get("entity_id")
name = data.get("name", "Unknown")
email = data.get("email", "No email")
subscribe = data.get("subscribe", "false")
age = data.get("age")
location = data.get("location", "Not specified")

response_text = f"Profile saved!\nName: {name}\nEmail: {email}\nSubscribed: {subscribe}"
if entity_id:
response_text += f"\nEntity ID: {entity_id}"
if age:
response_text += f"\nAge: {age}"
if location != "Not specified":
response_text += f"\nLocation: {location}"

await ctx.send(response_text)
else:
return AdaptiveCardActionErrorResponse(
status_code=400,
type="application/vnd.microsoft.error",
value=HttpError(
code="BadRequest",
message="Unknown action",
inner_http_error=InnerHttpError(
status_code=400,
body={"error": "Unknown action"},
),
),
)
print(f"[GLOBAL HANDLER] Received Action.Execute data: {data}")
await ctx.send(f"Global handler processed Action.Execute. Data: {data}")
return AdaptiveCardActionMessageResponse(
status_code=200,
type="application/vnd.microsoft.activity.message",
value="Global handler processed action",
)


@app.on_card_action_execute("submit_basic")
async def handle_submit_basic(ctx: ActivityContext[AdaptiveCardInvokeActivity]) -> AdaptiveCardInvokeResponse:
"""Handle basic card submission - specific action routing."""
data = ctx.activity.value.action.data
notify_value = data.get("notify", "false")
print(f"[SPECIFIC HANDLER] Received submit_basic action. Notify: {notify_value}")
Comment thread
lilyydu marked this conversation as resolved.
await ctx.send(f"Specific handler: submit_basic. Notify setting: {notify_value}")
return AdaptiveCardActionMessageResponse(
status_code=200,
type="application/vnd.microsoft.activity.message",
value="Action processed successfully",
)


@app.on_card_action_execute("submit_feedback")
async def handle_submit_feedback(ctx: ActivityContext[AdaptiveCardInvokeActivity]) -> AdaptiveCardInvokeResponse:
"""Handle feedback submission."""
data = ctx.activity.value.action.data
print("Received submit_feedback action data:", data)
feedback_text = data.get("feedback", "No feedback provided")
await ctx.send(f"Feedback received: {feedback_text}")
return AdaptiveCardActionMessageResponse(
status_code=200,
type="application/vnd.microsoft.activity.message",
value="Action processed successfully",
)


@app.on_card_action_execute("create_task")
async def handle_create_task(ctx: ActivityContext[AdaptiveCardInvokeActivity]) -> AdaptiveCardInvokeResponse:
"""Handle task creation."""
data = ctx.activity.value.action.data
print("Received create_task action data:", data)
title = data.get("title", "Untitled")
priority = data.get("priority", "medium")
due_date = data.get("due_date", "No date")
await ctx.send(f"Task created!\nTitle: {title}\nPriority: {priority}\nDue: {due_date}")
return AdaptiveCardActionMessageResponse(
status_code=200,
type="application/vnd.microsoft.activity.message",
value="Action processed successfully",
)


@app.on_card_action_execute("save_profile")
async def handle_save_profile(ctx: ActivityContext[AdaptiveCardInvokeActivity]) -> AdaptiveCardInvokeResponse:
"""Handle profile save."""
data = ctx.activity.value.action.data
print("Received save_profile action data:", data)
entity_id = data.get("entity_id")
name = data.get("name", "Unknown")
email = data.get("email", "No email")
subscribe = data.get("subscribe", "false")
age = data.get("age")
location = data.get("location", "Not specified")

response_text = f"Profile saved!\nName: {name}\nEmail: {email}\nSubscribed: {subscribe}"
if entity_id:
response_text += f"\nEntity ID: {entity_id}"
if age:
response_text += f"\nAge: {age}"
if location != "Not specified":
response_text += f"\nLocation: {location}"

await ctx.send(response_text)
return AdaptiveCardActionMessageResponse(
status_code=200,
type="application/vnd.microsoft.activity.message",
Expand Down
Loading
Loading