Overview
These are the guidelines, principles, compatibility, and security aspects for Seegnal's Web hosting on EHR client machines. This document combines product design, technical capabilities, and security limitations.
Seegnal's UI is an HTML5 web-based application based on Angular.js (currently migrating to React – TBD). The motivation of Seegnal's workflow is to have the UI open as a dialog or always on top, so users experience an urgent obligation to attend prescription alerts.
For best experience, the UI needs the ability to close itself or to alert the hosting environment to close it. If self-close is not an option, additional flow assumptions apply (see below).
At the end of Seegnal's UI session the EHR should detect the closure of the UI, or communicate with the UI before closure (depending on the hosting environment).
Compatibility
Site is compatible with the following browsers:
- Chrome (Chromium)
- IE 11 (supported up to Seegnal version 10.4)
- Edge
Resolution
The minimum resolution for Seegnal's UI is 1024×720 px. Optimal is 1490×720 px. Other resolutions need to be reviewed.
There is currently no support for mobile or tablet (tablet use may also disable hover-over, tooltips, etc.).
Future migration to React will provide a responsive view.
EHR — Application Based (exe)
Some EHRs are PC application-based (local executable), running on various operating systems and built with different platforms — old and new. This creates a unique hosting method that often requires a tailor-made solution for integration.
The EHR application usually opens Seegnal's UI using a Web-View (shell) component or an external app (e.g. CEF — Chromium Embedded Framework). Some web-views provide a degree of communication between the EHR client and the Seegnal-hosted site, which optimizes the flow but has edge cases depending on technology and communication protocols. This communication might require a cross-origin definition.
Most web-views provide a shell window of the default installed browser (usually Internet Explorer). The shell can introduce issues with JavaScript execution, AJAX calls, multimedia playback and more. The EHR must conduct tests with Seegnal's site to verify these issues are resolved.
Open Seegnal — opening Seegnal's site is done by the link sent in the ProcessTherapy API response. This is normally used as-is. Optionally the host may add query string segments if agreed with Seegnal (e.g. for security or functionality reasons).
Default 'X' button — Most shells come with default close (×), minimize, and maximize controls. The EHR should make sure all options are invisible or disabled, except for close (×).
Close Seegnal
There are a few scenarios for closure, depending on the host platform capabilities and security aspects:
- Seegnal can close itself.Once the shell is closed, an UpdateEMR call should be invoked. Closing with '×' triggers an UpdateEMR call — naturally 'save changes' is not applied.
- Seegnal can close itself and can call the hosting window.When Seegnal's 'close and save' is pressed, the EHR can be updated with the UpdateEMR response before closing. If no update is sent, the EHR behaves as if '×' was pressed. Closing with '×' triggers UpdateEMR; 'save changes' is not applied.
- Seegnal cannot close itself but can call the hosting window.'Save and close' acts as the previous option (with or without UpdateEMR response). Closing relies entirely on the hosting window. '×' triggers UpdateEMR.
- Seegnal cannot close itself and cannot call the hosting window.Only the '×' button is available. Seegnal does not display 'close and save'. Closing with '×' triggers UpdateEMR; response status considers:
- If medication changes were made, the server assumes a 'save' was made and replies with a pending state and recommendations. The EHR should ask the user to approve. If approved, modify orders accordingly and invoke a new ProcessTherapy. If not approved, ignore recommendations and invoke ProcessTherapy. The response updates Seegnal's status indicator icon.
- If no changes were made and all alerts were bypassed, the UpdateEMR response contains a 'bypass' state indicator. The EHR should update Seegnal's status indicator and proceed with prescription.
EHR — Browser Based
Web-based EHRs differ by the hosting browser used for Seegnal flow integration. Hosting Seegnal's site has some logical/technical limitations:
- Opening the site using an 'always on top' approach is not possible* on a different window/tab.
- Communication between the EHR site and Seegnal is not possible*. The EHR cannot detect Seegnal closure.
- Seegnal closure will not necessarily lead back to the opening window or tab.
- The site is not allowed* to close itself due to security agenda; browsers prompt the user via popup alerts.
* Depends on browser type, version, and organization security policies.
There are a few solutions to overcome these limitations, depending on the browser type and version:
Site Blocker
A cover layer displayed on the EHR site (e.g. "Seegnal is opened in a new window, please attend...") with a "Return from Seegnal" (Close) button that removes the blocker.
The advantage is synchronization between the EMR and Seegnal sites: once pressed, UpdateEMR or ProcessTherapy is invoked to update indicators and continue the signing-medications flow. This completes the cycle and allows the EMR to update elements for clarity.
A blocker cover can be easily implemented with basic HTML and CSS.
Modal Window (IE 11 only)
For the best experience on IE 11, use a showModalDialog dialog.
window.showModalDialog(
'{seegnal url}',
null,
'dialogWidth:1324px;dialogHeight:824px;scroll:auto;help:yes;status:yes;'
);- Resolution may differ from declared and need adjustment during integration.
- Due to cross-domain security, the Seegnal window and EHR window cannot communicate using return values or shared objects. This may be solved if Seegnal's site is hosted under an EHR certificate — must be tested under client permissions and security policies.
- The EHR can still add arguments to Seegnal's query string when invoking the link.
Since closing modal view or communicating from/to it is blocked, this acts as the Seegnal cannot close itself and cannot call hosting window scenario above.
iFrame
The working solution for modern browsers is to host Seegnal's site in an iframe wrapped with a dialog look-and-feel via CSS. The EHR invokes the dialog using JavaScript to toggle CSS visibility and set the iframe src from the ProcessTherapy response.
A cross-domain definition must be configured on Seegnal's site to allow the EHR hosting URI by altering X-Frame-Options headers. iFrame integration allows both sites to communicate via postMessage.
Message payload data.action and data.args are provided on integration and include actions such as close, update-emr, error, etc. Seegnal can expand action types as needed.
EHR hosting code template
<script>
// Listen to messages from the child window
window.addEventListener("message", function (e) {
console.log('*** Parent Window: ' + e.data.action + ' ***');
console.log('*** Parent Window: ' + e.data.args + ' ***');
setTimeout(function () {
e.source.postMessage({ actionExecuted: true }, e.origin); // Action acknowledge
}, 100);
});
</script>Open / close from the EHR
function openSeegnal() {
$("#seegnal-frame").attr('src', "{ seegnal url }");
window.scroll({ top: 0, left: 0, behavior: 'smooth' });
$(".popup-overlay, .popup-content").addClass("active");
}
$(".close, .popup").on("click", function () {
$(".popup-overlay, .popup-content").removeClass("active");
});Full implementation example
Complete reference page combining the iframe popup, message listener and styling (enlarge to review properly):
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.0/jquery-ui.js"></script>
</head>
<body>
<h2>Seegnal Hosting Example</h2>
<h5 class="indicator-text">Press Seegnal's Indicator to Simulate Popup window</h5>
<img class="indicator" src="data:image/jpeg;base64,…" onclick="openSeegnal()" />
<!--<button class="open">Open</button>-->
<div id="lipsum">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit…</p>
<!-- additional page content -->
</div>
<div class="popup-overlay">
<!--Creates the popup content-->
<div class="popup-content">
<iframe id="seegnal-frame">Loading...</iframe>
<!--popup's close button-->
<button class="close">Close</button>
</div>
</div>
</body>
<script>
function openSeegnal() {
$("#seegnal-frame").attr('src', "{ seegnal url }");
window.scroll({ top: 0, left: 0, behavior: 'smooth' });
$(".popup-overlay, .popup-content").addClass("active");
}
$(".close, .popup").on("click", function () {
$(".popup-overlay, .popup-content").removeClass("active");
});
// Listen to message from child window
window.addEventListener("message", function (e) {
console.log('*** Parent Window: ' + e.data.action + ' ***');
console.log('*** Parent Window: ' + e.data.args + ' ***');
setTimeout(function () {
e.source.postMessage({ actionExecuted: true }, e.origin); // Action Acknowledge
}, 100);
});
</script>
<style>
html {
font-family: "Helvetica Neue", sans-serif;
width: 100%;
color: #666666;
text-align: center;
}
.indicator-text { color: red; }
.indicator { width: 200px; height: 55px; }
iframe {
width: -webkit-fill-available;
height: -webkit-fill-available;
}
.popup-overlay {
/*Hides pop-up when there is no "active" class*/
visibility: hidden;
position: absolute;
background: #ffffff;
border: 3px solid #666666;
width: 50%;
height: 50%;
left: 25%;
top: 25%;
overflow: hidden;
}
.popup-overlay.active {
/*displays pop-up when "active" class is present*/
visibility: visible;
text-align: center;
width: 100%;
/* !!!! height must be adjustable by clients page height !!!!*/
height: 200%;
left: 0;
top: 0;
background: #7a7a7a7a;
}
.popup-content {
/*Hides pop-up content when there is no "active" class */
visibility: hidden;
background-color: white;
/* width: 50%;*/
width: 1024px;
height: 720px;
margin: 0 auto;
margin-block-start: 3em;
border: 3px solid lavender;
border-radius: 5px;
}
.popup-content.active {
/*Shows pop-up content when "active" class is present */
visibility: visible;
}
button {
display: inline-block;
vertical-align: middle;
border-radius: 30px;
margin: 0.5rem;
font-size: 1rem;
color: #666666;
background: #ffffff;
border: 1px solid #666666;
}
button:hover {
border: 1px solid #666666;
background: #666666;
color: #ffffff;
}
</style>
</html>Plugin
TBD