Skip to content
/ agljs Public

AGL.js • A lightweight framework for integrating web apps with Epic's Active Guidelines platform, using modern JavaScript features. Manage action queuing, event handling, subscriptions, and state within Epic Hyperspace.

License

Notifications You must be signed in to change notification settings

faulkj/agljs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AGL.js | Epic Active Guidelines Simplified

AGL.js is a modern framework for integrating web applications with Epic’s Active Guidelines (AGL) platform. Built with TypeScript but fully usable with modern JavaScript, it abstracts the low-level details of AGL communication while remaining lightweight and flexible.

The framework streamlines interaction between web applications and AGL, including:

  • Confirming whether the web app is running inside Epic
  • Facilitating communication with the Epic backend
  • Triggering and queuing actions in Hyperspace
  • Subscribing to and handling AGL events
  • Managing application state and navigation history

Table of Contents

  1. Getting Started
  2. Configuration
  3. Usage
  4. Parameters
  5. Methods
  6. Queuing
  7. Error Handling
  8. Subscriptions
  9. State Management
  10. Navigation History

Disclaimer

AGL.js is not affiliated with or endorsed by Epic Systems Corporation. It is intended solely for use by organizations with active Epic licenses. Please ensure compliance with your Epic agreements before using or distributing this library.

Getting Started

📦 Installation

For modern JavaScript/TypeScript projects, install via npm or yarn:

# npm
npm install agljs

# yarn
yarn add agljs

TypeScript

import AGL from 'agljs'

const agl = new AGL()

(async () => {
  if (await agl.active) {
    console.log(agl.active) //Logs true (boolean)
  }
})()

JavaScript

import AGL from 'agljs/js/agl.js';

(async () => {
  const agl = new AGL();

  if (await agl.active) {
    console.log(agl.details.availableActions); //Logs available AGL actions
  }
})();

💾 Download

  1. Download the latest release from the GitHub repository.
  2. Include agl.min.js in your project:
<script src="path/to/agl.min.js"></script>
<script>
  const agl = new AGL();

  //For browsers that don't support async/await
  Promise.resolve(agl.active).then(function(active) {
    console.log(agl.active); //Logs true or false (boolean)
  });
</script>

🔗 Via CDN

Add AGL.js from a CDN, such as jsDelivr:

<script src="https://cdn.jsdelivr.net/npm/agljs/js/agl.min.js"></script>
<script>
  const agl = new AGL();

  //For browsers that don't support async/await
  Promise.resolve(agl.active).then(function(active) {
    if (active) {
      console.log(agl.details.availableActions); //Logs available AGL actions
    }
  });
</script>

Configuration

The AGL constructor accepts an optional configuration object with the following optional parameters:

Parameter Type Description Default
debug boolean Enables debug logging for troubleshooting false
timeout number Timeout (in milliseconds) before failure for action responses 2000
subscribe object An object containing events to subscribe to during the handshake {}
onError function Callback for handling errors null
onNavigate function Callback for navigation events (e.g., back/forward) null
onReload function Callback for reload events null
onAGLEvent function Callback for custom AGL events null
onSubscribed function Callback for handling subscription results null

Example Configuration

const agl = new AGL({
   debug: true,
   timeout: 5000,
   subscribe: {
      "Epic.Common.RequestToCloseApp": { PauseDuration: 300 },
   },
   onError: (error) => console.error('Error:', error),
   onNavigate: (event) => console.log('Navigation event:', event.direction),
   onReload: (event) => console.log('Reload event:', event.state),
});

Usage

All actions must wait for the AGL handshake to complete and for the framework to confirm it is running inside Epic. This is done by checking if (await agl.active).

Example:

const agl = new AGL();

if (await agl.active) {
   agl.do('Epic.Clinical.Informatics.Web.SaveState', { state: 'example' })
      .then((success) => console.log('State saved:', success))
      .catch((err) => console.error('Error saving state:', err));
}

Example:

const agl = new AGL();
if (!await agl.active) throw new Error('AGL is inactive! We aren't in Epic!');

agl.on('navigate', (event) => {
   console.log('User navigated:', event.direction);
});

Parameters

active (read-only)

Indicates whether the AGL.js framework is active and initialized.

  • If AGL.js is already initialized, returns true or false.
  • If AGL.js is still initializing, returns a promise that resolves to true or false.

Usage: Before performing any actions, ensure AGL.js has completed initialization:

Example:

if (await agl.active) {
   console.log('AGL is initialized and ready.');
}

For subsequent checks (once initialization is complete), you can use agl.active without await:

if (await agl.active) {
   console.log(agl.active ? '✔ AGL is active.' : '❌ AGL is inactive.');
}

details (read-only)

Provides information from Epic about the current AGL context. Properties include:

Property Type Description
availableActions string[] List of actions supported in the current context
currentState string State identifier restored during hibernation
interfaceVersion string Version of the AGL JavaScript interface
readOnly boolean Indicates if the AGL context is read-only
token string Token required for posting messages to Epic

Any additional properties returned by Epic will also be available.

Example:

console.log('Token:', agl.details.token);
console.log('Available actions:', agl.details.availableActions.join(', '));

debug (write-only)

Enables or disables debug logging dynamically

Example:

agl.debug = true; // Enable debug logging

Methods

do(action, args = null, haltOnError = false)

Executes an action within AGL.

Parameter Type Description
action string The name of the action to perform
args object Optional Arguments to pass with the action
haltOnError boolean Optional Stops the queue if this action fails, preventing subsequent actions from running

Example: Basic Action

if (await agl.active) {
   agl.do('SaveState', { state: 'example' });
}

For convenience, actions without a full namespace (i.e., actions without a dot .) are automatically prefixed with Epic.Clinical.Informatics.Web. If you need to override this behavior for specific actions, you can include the full namespace directly:

Example: Full Namespace Action

if (await agl.active) {
   agl.do('Custom.Namespace.Action', { someArg: 'value' });
}

on(eventName, callback)

Registers a callback for specific AGL events.

Parameter Type Description
eventName string The name of the event to listen for
callback function The callback function to execute when the event occurs

Events types:

Event Name Example Response
error { message: 'Error description', details: ['Detail 1', ...] }
navigate { direction: 'Back' }
reload { state: 'State string', fromHibernation: boolean }
aglEvent { name: 'Event name', args: { arg1: ... }
subscribed { EventName: 'Event name', SubscriptionSuccess: boolean }

Example:

agl.on('navigate', (event) => {
   console.log('User navigated:', event.direction);
});

Example: Chaining listeners

agl
   .on('navigate', (event) => console.log('User navigated:', event.direction))
   .on('reload', (event) => console.log('User reloaded:', event.state));

Queuing

Actions are added to a queue and executed sequentially to avoid race conditions. By default, the queue continues processing even if an action fails. However, setting haltOnFail in do to true stops the queue when that action fails or times out, ensuring dependent actions are not executed.

Example:

agl.do('SaveState', { state: 'example' }, true) // Stop queue if SaveState fails
   .catch((error) => console.error('SaveState failed:', error));

agl.do('CloseActivity', null) // Will only execute if SaveState succeeds
   .catch((error) => console.error('CloseActivity failed:', error));

Advanced Usage

Error Handling

The library provides built-in error handling. If an error event listener is not provided, errors will default to logging in the browser's console. If an error event listener is set, the callback will handle all errors and override default behavior.

Overriding Error Handling

You can override internal error handling by providing a custom onError callback in the configuration.

Example: During instantiation

const agl = new AGL({
   onError: (error) => {
      console.error('Custom error handler:', error.message);
   },
});

Example: After instantiation

agl.on('error', (error) => {
   console.error('Custom error handler:', error.message);
});

Subscriptions

You can specify subscriptions during initialization using the subscribe property. Subscriptions allow your application to register for specific events, such as changes in patient demographics or requests to close the app.

Confirming Subscriptions

To confirm that each subscription was successfully processed during the handshake, you can define an onSubscribed callback. This callback receives the subscription results, allowing you to verify whether your subscriptions were accepted by Epic.

Example:

const agl = new AGL({
   subscribe: {
      "Epic.Patient.Demographics.Updated": { IncludeHistory: true },
      "Epic.Common.RequestToCloseApp": { PauseDuration: 200 }
   },
   onSubscribed: (results) => {
      console.log('Subscription handshake completed:', results);
   },
});

Listening for Subscribed Events

After subscriptions are successfully established, your application can handle the events triggered by those subscriptions using the aglEvent handler.

Example:

agl.on('aglEvent', (event) => {
   if (event.name === 'Epic.Patient.Demographics.Updated') {
      console.log('Patient demographics updated:', event.args);
   }
   if (event.name === 'Epic.Common.RequestToCloseApp') {
      agl.do('Epic.Common.CloseApp',  {
         CanClose: true
      });
   }
});

State Management

AGL.js supports saving and restoring app state during transitions or hibernation.

Saving State

To save the current state of your application, use the SaveState action.

Example: Simple string

agl.do('SaveState', { state: 'dashboard' });

Example: Complex state

agl.do('SaveState', {
   state: JSON.stringify({ tab: 'overview', filters: { active: true } })
});

Restoring State

To restore the state during a reload event, listen for the reload event and activate the page accordingly.

Example:

agl.on('reload', (event) => {
   if (event.state) {
      const restoredState = JSON.parse(event.state);
      console.log('Restored state:', restoredState);
      activatePage(restoredState.tab, restoredState.filters);
   }
});

Navigation History

The library supports managing navigation history, tracking user interactions with Back/Forward buttons, and maintaining app-specific navigation states.

Listening to Navigation Events

Use onNavigate to track Back/Forward button clicks.

Example:

agl.on('navigate', ({ direction }) => {
   console.log(`Navigated: ${direction}`);
   // Handle navigation here
});

Saving Navigation History

Save custom navigation states using SaveHistoryState. AGL.js will persist these states for the current session.

Example:

agl.do('Epic.Clinical.Informatics.Web.SaveHistoryState', {
   state: JSON.stringify({ tab: 'dashboard', filters: { active: true } })
});

Disabling Navigation Buttons

Disable Back/Forward buttons in unsupported contexts.

Example:

agl.do('Epic.Clinical.Informatics.Web.SetEnabledHistBtns', {
   Back: false,
   Forward: false
});

🤝 Contributing

Contributions are welcome! Please fork the repository, create a new branch, and submit a pull request.

Kopimi License License

This project operates under the Kopimi ethos. It is free to use, modify, and share. However, if the code itself is used, borrowed, modified, or incorporated into a commercial product or service, proper attribution is required.

About

AGL.js • A lightweight framework for integrating web apps with Epic's Active Guidelines platform, using modern JavaScript features. Manage action queuing, event handling, subscriptions, and state within Epic Hyperspace.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published