Skip to content

Commit

Permalink
Create Command effects and BannerAlert effects
Browse files Browse the repository at this point in the history
Create Command effects and BannerAlert effects
  • Loading branch information
mbiannaccone authored Mar 25, 2024
2 parents 6bccfbd + e844855 commit 89804a1
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from pydantic import BaseModel, ConfigDict, model_validator
from typing_extensions import Self

from plugin_runner.generated.messages.effects_pb2 import Effect


class _BaseCommand(BaseModel):
model_config = ConfigDict(strict=True, validate_assignment=True)

# to look into: should we use external identifiers? or an sdk note class
class Meta:
key = ""

# todo: update int to str as we should use external identifiers
note_id: int | None = None
command_uuid: str | None = None
user_id: int
Expand All @@ -20,37 +25,55 @@ def _verify_has_note_id_or_command_id(self) -> Self:
def values(self) -> dict:
return {}

def originate(self) -> dict:
def originate(self) -> Effect:
"""Originate a new command in the note body."""
# note: this is a placeholder method until we've made some more definitive decisions about how command objects are manipulated
if not self.note_id:
raise AttributeError("Note id is required to originate a command")
return {"note_id": self.note_id, "user_id": self.user_id, "values": self.values}
return {
"type": f"ADD_{self.Meta.key.upper()}_COMMAND",
"payload": {
"user": self.user_id,
"note": self.note_id,
"data": self.values,
},
}

def edit(self) -> dict:
def edit(self) -> Effect:
"""Edit the command."""
# note: this is a placeholder method until we've made some more definitive decisions about how command objects are manipulated
if not self.command_uuid:
raise AttributeError("Command uuid is required to edit a command")
return {"command_uuid": self.command_uuid, "user_id": self.user_id, "values": self.values}
return {
"type": f"EDIT_{self.Meta.key.upper()}_COMMAND",
"payload": {
"user": self.user_id,
"command": self.command_uuid,
"data": self.values,
},
}

def delete(self) -> dict:
def delete(self) -> Effect:
"""Delete the command."""
# note: this is a placeholder method until we've made some more definitive decisions about how command objects are manipulated
if not self.command_uuid:
raise AttributeError("Command uuid is required to delete a command")
return {"command_uuid": self.command_uuid, "user_id": self.user_id, "delete": True}
return {
"type": f"DELETE_{self.Meta.key.upper()}_COMMAND",
"payload": {"command": self.command_uuid, "user": self.user_id},
}

def commit(self) -> dict:
def commit(self) -> Effect:
"""Commit the command."""
# note: this is a placeholder method until we've made some more definitive decisions about how command objects are manipulated
if not self.command_uuid:
raise AttributeError("Command uuid is required to commit a command")
return {"command_uuid": self.command_uuid, "user_id": self.user_id, "commit": True}
return {
"type": f"COMMIT_{self.Meta.key.upper()}_COMMAND",
"payload": {"command": self.command_uuid, "user": self.user_id},
}

def enter_in_error(self) -> dict:
def enter_in_error(self) -> Effect:
"""Mark the command as entered-in-error."""
# note: this is a placeholder method until we've made some more definitive decisions about how command objects are manipulated
if not self.command_uuid:
raise AttributeError("Command uuid is required to enter in error a command")
return {"command_uuid": self.command_uuid, "user_id": self.user_id, "enter_in_error": True}
return {
"type": f"ENTER_IN_ERROR_{self.Meta.key.upper()}_COMMAND",
"payload": {"command": self.command_uuid, "user": self.user_id},
}
5 changes: 4 additions & 1 deletion canvas_sdk/commands/commands/assess.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from enum import Enum

from canvas_sdk.commands.commands.base import _BaseCommand
from canvas_sdk.commands.base import _BaseCommand


class AssessCommand(_BaseCommand):
"""A class for managing an Assess command within a specific note."""

class Meta:
key = "assess"

class Status(Enum):
IMPROVED = "improved"
STABLE = "stable"
Expand Down
5 changes: 4 additions & 1 deletion canvas_sdk/commands/commands/diagnose.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from datetime import datetime

from canvas_sdk.commands.commands.base import _BaseCommand
from canvas_sdk.commands.base import _BaseCommand


class DiagnoseCommand(_BaseCommand):
"""A class for managing a Diagnose command within a specific note."""

class Meta:
key = "diagnose"

icd10_code: str
background: str | None = None
approximate_date_of_onset: datetime | None = None
Expand Down
5 changes: 4 additions & 1 deletion canvas_sdk/commands/commands/goal.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
from datetime import datetime
from enum import Enum

from canvas_sdk.commands.commands.base import _BaseCommand
from canvas_sdk.commands.base import _BaseCommand


class GoalCommand(_BaseCommand):
"""A class for managing a Goal command within a specific note."""

class Meta:
key = "goal"

class Priority(Enum):
HIGH = "high-priority"
MEDIUM = "medium-priority"
Expand Down
5 changes: 4 additions & 1 deletion canvas_sdk/commands/commands/history_present_illness.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from canvas_sdk.commands.commands.base import _BaseCommand
from canvas_sdk.commands.base import _BaseCommand


class HistoryOfPresentIllnessCommand(_BaseCommand):
"""A class for managing a HPI command within a specific note."""

class Meta:
key = "hpi"

narrative: str

@property
Expand Down
5 changes: 4 additions & 1 deletion canvas_sdk/commands/commands/medication_statement.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from canvas_sdk.commands.commands.base import _BaseCommand
from canvas_sdk.commands.base import _BaseCommand


class MedicationStatementCommand(_BaseCommand):
"""A class for managing a MedicationStatement command within a specific note."""

class Meta:
key = "medicationStatement"

fdb_code: str
sig: str | None = None

Expand Down
5 changes: 4 additions & 1 deletion canvas_sdk/commands/commands/plan.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from canvas_sdk.commands.commands.base import _BaseCommand
from canvas_sdk.commands.base import _BaseCommand


class PlanCommand(_BaseCommand):
"""A class for managing a Plan command within a specific note."""

class Meta:
key = "plan"

narrative: str | None = None

@property
Expand Down
5 changes: 4 additions & 1 deletion canvas_sdk/commands/commands/questionnaire.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from canvas_sdk.commands.commands.base import _BaseCommand
from canvas_sdk.commands.base import _BaseCommand


class QuestionnaireCommand(_BaseCommand):
"""A class for managing a Questionnaire command within a specific note."""

class Meta:
key = "questionnaire"

questionnaire_id: int
result: str | None = None

Expand Down
5 changes: 4 additions & 1 deletion canvas_sdk/commands/commands/reason_for_visit.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from pydantic import model_validator
from typing_extensions import Self

from canvas_sdk.commands.commands.base import _BaseCommand
from canvas_sdk.commands.base import _BaseCommand
from canvas_sdk.commands.constants import Coding


class ReasonForVisitCommand(_BaseCommand):
"""A class for managing a ReasonForVisit command within a specific note."""

class Meta:
key = "reasonForVisit"

structured: bool = False
# how do we make sure that coding is a valid rfv coding from their home-app?
coding: Coding | None = None
Expand Down
5 changes: 4 additions & 1 deletion canvas_sdk/commands/commands/stop_medication.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from canvas_sdk.commands.commands.base import _BaseCommand
from canvas_sdk.commands.base import _BaseCommand


class StopMedicationCommand(_BaseCommand):
"""A class for managing a StopMedication command within a specific note."""

class Meta:
key = "stopMedication"

# how do we make sure this is a valid medication_id for the patient?
medication_id: int
rationale: str | None = None
Expand Down
37 changes: 37 additions & 0 deletions canvas_sdk/effects/banner_alert/banner_alert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from typing import Any

from pydantic import Field

from canvas_sdk.effects.banner_alert.constants import (
BannerAlertIntent,
BannerAlertPlacement,
)
from canvas_sdk.effects.base import _BaseEffect


class BannerAlert(_BaseEffect):
"""
An Effect that will result in a banner alert in Canvas.
"""

class Meta:
effect_type = "SHOW_BANNER_ALERT"

patient_key: str
narrative: str = Field(max_length=90)
placements: list[BannerAlertPlacement] = Field(min_length=1)
intents: list[BannerAlertIntent] = Field(min_length=1)

@property
def values(self) -> dict[str, Any]:
"""The BannerAlert's values."""
return {
"narrative": self.narrative,
"placement": [p.value for p in self.placements],
"intent": [i.value for i in self.intents],
}

@property
def effect_payload(self) -> dict[str, Any]:
"""The payload of the effect."""
return {"patient": self.patient_key, "data": self.values}
19 changes: 19 additions & 0 deletions canvas_sdk/effects/banner_alert/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from enum import Enum


class BannerAlertPlacement(Enum):
"""Where the BannerAlert should appear in the Canvas UI."""

CHART = "chart"
TIMELINE = "timeline"
APPOINTMENT_CARD = "appointment_card"
SCHEDULING_CARD = "scheduling_card"
PROFILE = "profile"


class BannerAlertIntent(Enum):
"""The intent that should be conveyed in the BannerAlert."""

INFO = "info"
WARNING = "warning"
ALERT = "alert"
30 changes: 30 additions & 0 deletions canvas_sdk/effects/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from typing import Any

from pydantic import BaseModel, ConfigDict

from plugin_runner.generated.messages.effects_pb2 import Effect


class _BaseEffect(BaseModel):
"""
A Canvas Effect that changes user behavior or autonomously performs activities on behalf of users.
"""

class Meta:
effect_type = ""

model_config = ConfigDict(strict=True, validate_assignment=True)

@property
def values(self) -> dict[str, Any]:
return {}

@property
def effect_payload(self) -> dict[str, Any]:
return {"data": self.values}

def apply(self) -> Effect:
return {
"type": self.Meta.effect_type,
"payload": self.effect_payload,
}

0 comments on commit 89804a1

Please sign in to comment.