Skip to content

Commit 0e2687f

Browse files
committed
add dynamic application
1 parent b0a6bdb commit 0e2687f

File tree

9 files changed

+109
-23
lines changed

9 files changed

+109
-23
lines changed

canvas_generated/messages/effects_pb2.py

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

canvas_generated/messages/effects_pb2.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ class EffectType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
229229
COMMAND_AVAILABLE_ACTIONS_RESULTS: _ClassVar[EffectType]
230230
COMMAND_VALIDATION_ERRORS: _ClassVar[EffectType]
231231
SHOW_ACTION_BUTTON: _ClassVar[EffectType]
232+
SHOW_APPLICATION: _ClassVar[EffectType]
232233
PATIENT_PORTAL__FORM_RESULT: _ClassVar[EffectType]
233234
PATIENT_PORTAL__APPOINTMENT_IS_CANCELABLE: _ClassVar[EffectType]
234235
PATIENT_PORTAL__APPOINTMENT_IS_RESCHEDULABLE: _ClassVar[EffectType]
@@ -558,6 +559,7 @@ ENTER_IN_ERROR_UNCATEGORIZED_DOCUMENT_REVIEW_COMMAND: EffectType
558559
COMMAND_AVAILABLE_ACTIONS_RESULTS: EffectType
559560
COMMAND_VALIDATION_ERRORS: EffectType
560561
SHOW_ACTION_BUTTON: EffectType
562+
SHOW_APPLICATION: EffectType
561563
PATIENT_PORTAL__FORM_RESULT: EffectType
562564
PATIENT_PORTAL__APPOINTMENT_IS_CANCELABLE: EffectType
563565
PATIENT_PORTAL__APPOINTMENT_IS_RESCHEDULABLE: EffectType

canvas_generated/messages/events_pb2.py

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

canvas_generated/messages/events_pb2.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,7 @@ class EventType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
10171017
PLUGIN_UPDATED: _ClassVar[EventType]
10181018
APPLICATION__ON_OPEN: _ClassVar[EventType]
10191019
APPLICATION__ON_CONTEXT_CHANGE: _ClassVar[EventType]
1020+
APPLICATION__ON_GET: _ClassVar[EventType]
10201021
PATIENT_PORTAL__GET_FORMS: _ClassVar[EventType]
10211022
PATIENT_PORTAL__APPOINTMENT_CANCELED: _ClassVar[EventType]
10221023
PATIENT_PORTAL__APPOINTMENT_RESCHEDULED: _ClassVar[EventType]
@@ -2095,6 +2096,7 @@ PLUGIN_CREATED: EventType
20952096
PLUGIN_UPDATED: EventType
20962097
APPLICATION__ON_OPEN: EventType
20972098
APPLICATION__ON_CONTEXT_CHANGE: EventType
2099+
APPLICATION__ON_GET: EventType
20982100
PATIENT_PORTAL__GET_FORMS: EventType
20992101
PATIENT_PORTAL__APPOINTMENT_CANCELED: EventType
21002102
PATIENT_PORTAL__APPOINTMENT_RESCHEDULED: EventType
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from typing import Any
2+
3+
from pydantic import Field
4+
5+
from canvas_generated.messages.effects_pb2 import EffectType
6+
from canvas_sdk.effects.base import _BaseEffect
7+
8+
9+
class ShowApplicationEffect(_BaseEffect):
10+
"""An Effect that returns an application's properties."""
11+
12+
class Meta:
13+
effect_type = EffectType.SHOW_APPLICATION
14+
15+
name: str = Field(min_length=1)
16+
identifier: str = Field(min_length=1)
17+
open_by_default: bool = Field(default=False)
18+
priority: int = Field(default=0)
19+
20+
@property
21+
def values(self) -> dict[str, Any]:
22+
"""The ShowApplicationEffect's values."""
23+
return {
24+
"name": self.name,
25+
"identifier": self.identifier,
26+
"open_by_default": self.open_by_default,
27+
"priority": self.priority,
28+
}
29+
30+
@property
31+
def effect_payload(self) -> dict[str, Any]:
32+
"""The payload of the effect."""
33+
return {"data": self.values}
34+
35+
36+
__exports__ = ("ShowApplicationEffect",)

canvas_sdk/handlers/application.py

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import warnings
12
from abc import ABC, abstractmethod
23

34
from canvas_sdk.effects import Effect
5+
from canvas_sdk.effects.show_application import ShowApplicationEffect
46
from canvas_sdk.events import EventType
57
from canvas_sdk.handlers import BaseHandler
6-
from canvas_sdk.handlers.action_button import ActionButton
78
from canvas_sdk.handlers.utils import normalize_effects
89

910

@@ -13,6 +14,7 @@ class Application(BaseHandler, ABC):
1314
RESPONDS_TO = [
1415
EventType.Name(EventType.APPLICATION__ON_OPEN),
1516
EventType.Name(EventType.APPLICATION__ON_CONTEXT_CHANGE),
17+
EventType.Name(EventType.APPLICATION__ON_GET),
1618
]
1719

1820
def compute(self) -> list[Effect]:
@@ -42,34 +44,72 @@ def identifier(self) -> str:
4244
return f"{self.__class__.__module__}:{self.__class__.__qualname__}"
4345

4446

45-
class NoteApplication(ActionButton):
46-
"""An Application that can be shown in a note."""
47+
class DynamicApplication(Application, ABC):
48+
"""An embeddable application that can be registered to Canvas."""
4749

48-
NAME: str = ""
49-
IDENTIFIER: str = ""
50+
NAME: str
51+
SCOPE: str
52+
IDENTIFIER: str | None = None
53+
PRIORITY: int = 0
5054

51-
@property
52-
def BUTTON_TITLE(self) -> str: # type: ignore[override]
53-
"""Return NAME as the button title."""
54-
return self.NAME
55+
def compute(self) -> list[Effect]:
56+
"""Handle the application events."""
57+
match self.event.type:
58+
case EventType.APPLICATION__ON_GET:
59+
if self.visible():
60+
return [
61+
ShowApplicationEffect(
62+
name=self.NAME,
63+
identifier=self.identifier,
64+
open_by_default=self.open_by_default(),
65+
priority=self.PRIORITY,
66+
).apply()
67+
]
68+
return []
69+
case _:
70+
return super().compute()
5571

56-
@property
57-
def BUTTON_KEY(self) -> str: # type: ignore[override]
58-
"""Return IDENTIFIER as the button key."""
59-
return self.IDENTIFIER
72+
def open_by_default(self) -> bool:
73+
"""Open the application by default."""
74+
return False
75+
76+
def visible(self) -> bool:
77+
"""Determine whether the application should be visible."""
78+
return self.context.get("scope") == self.SCOPE
6079

6180
@property
62-
def BUTTON_LOCATION(self) -> ActionButton.ButtonLocation: # type: ignore[override]
63-
"""Return the note body as the button location."""
64-
return ActionButton.ButtonLocation.NOTE_BODY
81+
def identifier(self) -> str:
82+
"""The application identifier."""
83+
return self.IDENTIFIER if self.IDENTIFIER else super().identifier
84+
85+
86+
class NoteApplication(DynamicApplication):
87+
"""An Application that can be shown in a note."""
88+
89+
SCOPE = "note"
90+
91+
def on_open(self) -> Effect | list[Effect]:
92+
"""Delegate to handle() for backward compatibility with old plugins."""
93+
# If a subclass overrides handle(), call it for backward compat.
94+
# New plugins should override on_open() directly.
95+
return self.handle()
6596

66-
@abstractmethod
6797
def handle(self) -> list[Effect]:
68-
"""Method to handle button click."""
69-
raise NotImplementedError("Implement to handle button click")
98+
"""Method to handle application click/on_open.
99+
100+
.. deprecated::
101+
Override :meth:`on_open` instead.
102+
"""
103+
warnings.warn(
104+
"NoteApplication.handle() is deprecated. Override on_open() instead.",
105+
DeprecationWarning,
106+
stacklevel=2,
107+
)
108+
return []
70109

71110

72111
__exports__ = (
73112
"Application",
113+
"DynamicApplication",
74114
"NoteApplication",
75115
)

plugin_runner/allowed-module-imports.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,9 @@
670670
"canvas_sdk.effects.send_invite": [
671671
"SendInviteEffect"
672672
],
673+
"canvas_sdk.effects.show_application": [
674+
"ShowApplicationEffect"
675+
],
673676
"canvas_sdk.effects.show_button": [
674677
"ShowButtonEffect"
675678
],
@@ -745,6 +748,7 @@
745748
],
746749
"canvas_sdk.handlers.application": [
747750
"Application",
751+
"DynamicApplication",
748752
"NoteApplication"
749753
],
750754
"canvas_sdk.handlers.base": [

protobufs/canvas_generated/messages/effects.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ enum EffectType {
278278
COMMAND_VALIDATION_ERRORS = 1601;
279279

280280
SHOW_ACTION_BUTTON = 1000;
281+
SHOW_APPLICATION = 1001;
281282

282283

283284

protobufs/canvas_generated/messages/events.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,7 @@ enum EventType {
12361236

12371237
APPLICATION__ON_OPEN = 103000;
12381238
APPLICATION__ON_CONTEXT_CHANGE = 103001;
1239+
APPLICATION__ON_GET = 103002;
12391240

12401241
PATIENT_PORTAL__GET_FORMS = 110000;
12411242
PATIENT_PORTAL__APPOINTMENT_CANCELED = 110001;

0 commit comments

Comments
 (0)