Patient Chart Summary Custom Section Handler
The PatientChartSummaryCustomSectionHandler is the base class for implementing custom sections in the patient chart summary. When Canvas needs to render a custom section, it fires an event that this handler intercepts, and the handler returns a PatientChartSummaryCustomSection effect with the content to display.
Overview #
Custom chart summary sections are registered through PatientChartSummaryConfiguration and served by a PatientChartSummaryCustomSectionHandler subclass. Each handler is responsible for exactly one section, identified by its SECTION_KEY.
To implement a custom section you need two things:
- A
PatientChartSummaryConfigurationhandler that includes the section in the layout. - A
PatientChartSummaryCustomSectionHandlersubclass that returns the section content.
Both handlers must be registered in CANVAS_MANIFEST.json.
Creating a Custom Section Handler #
Subclass PatientChartSummaryCustomSectionHandler and:
- Set
SECTION_KEYto the unique identifier of your section. This must match the key used inPatientChartSummaryConfiguration.CustomSection. - Implement
handle()to return aPatientChartSummaryCustomSectioneffect. - The patient key is available via
self.target. Use it to scope database queries to the current patient. - The logged-in user is available via
self.actor. Use it to tailor the section content to the specific staff member viewing the chart.
from canvas_sdk.effects import Effect
from canvas_sdk.effects.patient_chart_summary_custom_section import PatientChartSummaryCustomSection
from canvas_sdk.handlers.patient_chart_summary_custom_section_handler import PatientChartSummaryCustomSectionHandler
from canvas_sdk.templates import render_to_string
from canvas_sdk.v1.data.patient import Patient
class MySectionHandler(PatientChartSummaryCustomSectionHandler):
"""Handles the PATIENT_CHART_SUMMARY__GET_CUSTOM_SECTION event for 'my_section'.
Fetches the current patient and renders a template with their name.
"""
SECTION_KEY = "my_section"
def handle(self) -> list[Effect]:
patient = Patient.objects.get(id=self.target)
return [
PatientChartSummaryCustomSection(
content=render_to_string("templates/my_section.html", { "patient_name": patient.full_name() }),
icon="📋",
).apply()
]
Required #
SECTION_KEYA unique string identifier for the section. Must match the key passed toPatientChartSummaryConfiguration.CustomSection. Omitting or leaving it empty will raise anImproperlyConfigurederror when the plugin loads.handle()Called when Canvas requests the content for this section. Must return a list containing a singlePatientChartSummaryCustomSectioneffect.
Configuring Chart Summary Sections #
A custom section handler alone is not enough — the section must also be included in the chart summary layout. Use PatientChartSummaryConfiguration to declare which sections appear in the chart summary and in what order. For the full list of available built-in sections, see Patient Summary layout effects.
from canvas_sdk.effects import Effect
from canvas_sdk.effects.patient_chart_summary_configuration import PatientChartSummaryConfiguration
from canvas_sdk.events import EventType
from canvas_sdk.handlers import BaseHandler
class MySummaryConfiguration(BaseHandler):
RESPONDS_TO = [EventType.Name(EventType.PATIENT_CHART_SUMMARY__SECTION_CONFIGURATION)]
def compute(self) -> list[Effect]:
return [
PatientChartSummaryConfiguration(
sections=[
PatientChartSummaryConfiguration.CustomSection(name="my_section"),
PatientChartSummaryConfiguration.Section.MEDICATIONS,
PatientChartSummaryConfiguration.Section.CONDITIONS,
]
).apply()
]
Full Example #
The following example shows a complete plugin with a custom section that displays a list of items fetched from command metadata.
handlers/my_section.py #
import json
from canvas_sdk.effects import Effect
from canvas_sdk.effects.patient_chart_summary_custom_section import PatientChartSummaryCustomSection
from canvas_sdk.effects.patient_chart_summary_configuration import PatientChartSummaryConfiguration
from canvas_sdk.events import EventType
from canvas_sdk.handlers import BaseHandler
from canvas_sdk.handlers.patient_chart_summary_custom_section_handler import PatientChartSummaryCustomSectionHandler
from canvas_sdk.templates import render_to_string
from canvas_sdk.v1.data.command import CommandMetadata
class MySectionHandler(PatientChartSummaryCustomSectionHandler):
"""Handles the PATIENT_CHART_SUMMARY__GET_CUSTOM_SECTION event for 'my_section'.
Fetches all 'my_section' command metadata entries for the current patient
and renders them as a list in the section template.
"""
SECTION_KEY = "my_section"
def handle(self) -> list[Effect]:
entries = (
CommandMetadata.objects.filter(
key="my_section",
command__patient__id=self.target,
)
.order_by("created")
)
items = []
for entry in entries:
try:
items.append(json.loads(entry.value))
except (json.JSONDecodeError, TypeError):
items.append({"title": entry.value})
return [
PatientChartSummaryCustomSection(
content=render_to_string("templates/my_section.html", {"items": items}),
icon="📋",
).apply()
]
class MySummaryConfiguration(BaseHandler):
RESPONDS_TO = [EventType.Name(EventType.PATIENT_CHART_SUMMARY__SECTION_CONFIGURATION)]
def compute(self) -> list[Effect]:
return [
PatientChartSummaryConfiguration(
sections=[
PatientChartSummaryConfiguration.CustomSection(name="my_section"),
PatientChartSummaryConfiguration.Section.MEDICATIONS,
PatientChartSummaryConfiguration.Section.CONDITIONS,
]
).apply()
]
templates/my_section.html #
<ul>
{% for item in items %}
<li>{{ item.title }}</li>
{% empty %}
<li>No items on record.</li>
{% endfor %}
</ul>
CANVAS_MANIFEST.json #
{
"components": {
"handlers": [
{
"class": "my_plugin.handlers.my_section:MySectionHandler",
"description": "Serves content for the My Section custom chart section"
},
{
"class": "my_plugin.handlers.my_section:MySummaryConfiguration",
"description": "Configures the chart summary layout to include My Section"
}
]
}
}