Custom Dashboard Schema
A custom dashboard groups patient reports, custom reports, and inline count or indicator tabs into a named clinical view. Dashboards appear in a configurable section of the Medicus UI (controlled by subnavItem).
A dashboard can reference separately-published reports by identifier, or define inline tabs that embed patient queries directly.
See also the Custom Report Schema for the report types that dashboards reference, and the Patient Query Language reference for writing inline patient queries.
Examples
Dashboard referencing published reports
<?xml version="1.0" encoding="UTF-8"?>
<dashboard>
<name>Diabetes Register</name>
<identifier>my-org/diabetes-register</identifier>
<subnavItem>registers</subnavItem>
<patientReport>my-org/diabetes-patients</patientReport>
<indicatorReport>my-org/diabetes-indicators</indicatorReport>
</dashboard>
Dashboard with an inline count tab
<?xml version="1.0" encoding="UTF-8"?>
<dashboard>
<name>Medication Monitoring</name>
<identifier>my-org/medication-monitoring</identifier>
<subnavItem>medication-monitoring</subnavItem>
<reportCountTab identifier="on-monitoring" label="On Monitoring" type="patient">
<row identifier="warfarin-patients" label="Warfarin">
<patientQuery>
<!-- inline patient query XML -->
</patientQuery>
</row>
</reportCountTab>
</dashboard>
Full dashboard with an inline report tab
Putting it all together: a one-tab dashboard listing every patient with a ring pessary recorded. This example is checked automatically against the current schema (npm run check-schema-examples, wired into prebuild) - if a schema change breaks it, the build fails rather than the example silently going stale.
<?xml version="1.0" encoding="UTF-8"?>
<dashboard>
<name>Ring Pessary Review</name>
<identifier>my-org/ring-pessary-review</identifier>
<subnavItem>local-enhanced-services</subnavItem>
<section>LES</section>
<reportTab identifier="my-org/ring-pessary-patients" name="Ring Pessary Patients">
<patientReport schemaVersion="3">
<name>Ring Pessary Patients</name>
<rows>
<patientQuery>
<name>RingPessary</name>
<description>Patients with a ring pessary</description>
<population><patientQueryReference>ALL</patientQueryReference></population>
<codeLists>
<codeList>
<name>RING_PESSARY_COD</name>
<codeListDefinition>
<rules>
<inclusion><< 274228008 |Insertion of pessary|</inclusion>
</rules>
</codeListDefinition>
</codeList>
</codeLists>
<variables>
<codedEntryVariable name="PESSARY_DAT" code="RING_PESSARY_COD" select="clinically_relevant_date" order="clinically_relevant_date" take="latest"/>
</variables>
<rules>
<rule>
<if>PESSARY_DAT NOTEQ NULL</if>
<then>select</then>
<else>reject</else>
</rule>
</rules>
</patientQuery>
</rows>
<columns>
<demographicInformationColumn headerName="Patient" value="patientName"/>
<demographicInformationColumn value="patientPrimaryIdentifier"/>
<demographicInformationColumn headerName="Age" value="patientAge"/>
</columns>
</patientReport>
</reportTab>
</dashboard>
Schema
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- ===== Dashboard subnavItem enumeration =====
these represent all of the available values users can configure for subnavitem -->
<xs:simpleType name="dashboardSubnavItemType">
<xs:restriction base="xs:string">
<xs:enumeration value="cqc"/>
<xs:enumeration value="local-enhanced-services"/>
<xs:enumeration value="medication-monitoring"/>
<xs:enumeration value="preventative-care"/>
<xs:enumeration value="registers"/>
<xs:enumeration value="screening"/>
<xs:enumeration value="vaccination-recalls"/>
</xs:restriction>
</xs:simpleType>
<!-- ===== Shared enums ===== -->
<xs:simpleType name="countTabTypeType">
<xs:restriction base="xs:string">
<xs:enumeration value="patient"/>
<xs:enumeration value="prescription"/>
<xs:enumeration value="prescription-issue"/>
<xs:enumeration value="appointment"/>
<xs:enumeration value="activity"/>
</xs:restriction>
</xs:simpleType>
<!-- ===== Opaque types ===== -->
<xs:complexType name="patientQueryType" mixed="true">
<xs:sequence>
<xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<!-- ===== Runtime value structures ===== -->
<xs:complexType name="tabRuntimeValueEntryType">
<xs:sequence>
<xs:element name="value" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="tabRuntimeValuesType">
<xs:sequence>
<xs:element name="runtimeValue" type="tabRuntimeValueEntryType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<!-- ===== Tab types ===== -->
<xs:complexType name="reportTabType">
<xs:sequence>
<xs:any processContents="lax" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
<xs:attribute name="identifier" type="xs:string" use="required"/>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="countRowType">
<xs:sequence>
<xs:element name="patientQuery" type="patientQueryType"/>
</xs:sequence>
<xs:attribute name="identifier" type="xs:string" use="required"/>
<xs:attribute name="label" type="xs:string" use="optional"/>
</xs:complexType>
<xs:complexType name="reportCountTabType">
<xs:sequence>
<xs:element name="runtimeValues" type="tabRuntimeValuesType" minOccurs="0"/>
<xs:element name="row" type="countRowType" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="identifier" type="xs:string" use="required"/>
<xs:attribute name="label" type="xs:string" use="required"/>
<xs:attribute name="type" type="countTabTypeType" use="required"/>
</xs:complexType>
<xs:complexType name="indicatorRowType">
<xs:sequence>
<xs:element name="numerator">
<xs:complexType>
<xs:sequence>
<xs:element name="patientQuery" type="patientQueryType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="denominator">
<xs:complexType>
<xs:sequence>
<xs:element name="patientQuery" type="patientQueryType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="identifier" type="xs:string" use="required"/>
<xs:attribute name="label" type="xs:string" use="optional"/>
<xs:attribute name="target" type="xs:decimal" use="optional"/>
<xs:attribute name="matchLabel" type="xs:string" use="optional"/>
</xs:complexType>
<xs:complexType name="reportIndicatorTabType">
<xs:sequence>
<xs:element name="runtimeValues" type="tabRuntimeValuesType" minOccurs="0"/>
<xs:element name="row" type="indicatorRowType" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="identifier" type="xs:string" use="required"/>
<xs:attribute name="label" type="xs:string" use="required"/>
<xs:attribute name="type" type="countTabTypeType" use="optional"/>
</xs:complexType>
<!-- ===== Root element ===== -->
<xs:element name="dashboard">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="identifier" type="xs:string"/>
<xs:choice>
<xs:element name="subnavItem" type="dashboardSubnavItemType"/>
<xs:element name="type" type="dashboardSubnavItemType"/>
</xs:choice>
<xs:element name="section" type="xs:string" minOccurs="0"/>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="patientReport" type="xs:string"/>
<xs:element name="indicatorReport" type="xs:string"/>
<xs:element name="patientCountReport" type="xs:string"/>
<xs:element name="activityCountReport" type="xs:string"/>
<xs:element name="reportTab" type="reportTabType"/>
<xs:element name="reportCountTab" type="reportCountTabType"/>
<xs:element name="reportIndicatorTab" type="reportIndicatorTabType"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Key elements and attributes
| Element / Attribute | Required | Description |
|---|---|---|
name | Yes | Display name of the dashboard. |
identifier | Yes | Unique identifier, e.g. my-org/diabetes-register. |
subnavItem / type | Yes (one of) | Controls which section of the Medicus UI the dashboard appears under. Allowed values: cqc, local-enhanced-services, medication-monitoring, preventative-care, registers, screening, vaccination-recalls. |
section | No | Optional sub-section label within the chosen nav area. |
patientReport | No | Identifier string of a separately-published patient report. |
indicatorReport | No | Identifier string of a separately-published indicator report. |
patientCountReport | No | Identifier string of a separately-published patient count report. |
activityCountReport | No | Identifier string of a separately-published activity count report. |
reportTab | No | Inline tab embedding a report. Requires identifier and name attributes. |
reportCountTab | No | Inline count tab. Requires identifier, label, and type attributes. type is one of patient, prescription, prescription-issue, appointment, activity. |
reportIndicatorTab | No | Inline indicator tab. Each row has a numerator and denominator patient query. Optional target percentage (decimal). |