Page History
...
Anchor | ||||
---|---|---|---|---|
|
...
In general, i2b2 is designed to operate using a services-oriented architecture. An i2b2 "hive" is a collection of services called "cells". The primary i2b2 services are: PM / Project Management which manages projects/users in the hive, ONT / Ontology which stores all the terms that are used to select patients, CRC / Clinical Research Chart which is the central repository of patient data within the hive, WORK / Workplace which allows users to store information for later use. The i2b2 web client segments the functionality of its libraries in a similar way. In addition the core of the v1.8 web client has the PLUGIN and LEGACYPLUGIN components which handle the web client's plugins.
Anchor | ||
---|---|---|
|
...
Anchor | |||
---|---|---|---|
|
...
The plugin manager will operate as a singleton cell within the larger application. However, the plugin manager will have the ability to have multiple view instances (and thus plugin iframes). This is to allow multiple plugins to be loaded and operate simultaneously without interference.
The plugin manager communicates back and forth to your plugin's support libraries using the browser's window.postMessage() function call. The support libraries hide the complexity of this communication modality for you.
Anchor | ||
---|---|---|
|
...
Anchor | |||
---|---|---|---|
|
...
All plugins will exist entirely within the /plugins directory. Each plugin will be hosted in a single directory that follows Java-style library paths such as/edu/harvard/catalyst/example with the resulting plugin name being defined as "edu.harvard.catalyst.example". All files and libraries needed by the plugin will be contained solely within its own directory. This also includes a copy of the i2b2-loader.js script file. There will also be a file called plugins.json that exists within the root /plugins directory containing an array of plugin names as shown below.
[
"edu.harvard.catalyst.example",
"edu.harvard.WeberLab.ExportPatientset"
]
If you are using the i2b2-webclient-proxy service to host your web client UI it will automatically generate the plugins.json file based on the directory structure if the file does not exist. The Github repository for this proxy server is at _https://github.com/hms-dbmi/i2b2-webclient-proxy_
...
All plugins that interact with the main i2b2 UI must load the support libraries hosted in the /js-i2b2/cells/PLUGIN/libs directory. The easiest way to do this is to incorporate the i2b2-loader.js file. The loader script also handles initialization of the i2b2 namespace in your plugin's code environment.
Anchor | ||
---|---|---|
|
...
Anchor | |||
---|---|---|---|
|
...
Support Library | Initialization Event | Initialized Event |
SDX (Drag and Drop) | "I2B2_INIT_SDX" | "I2B2_SDX_READY" |
AJAX Communication | "I2B2_INIT_AJAX" | "I2B2_AJAX_READY" |
State Management | "I2B2_INIT_STATE" | "I2B2_STATE_READY" |
Authorized Tunnel | "I2B2_INIT_TUNNEL" | "I2B2_TUNNEL_READY" |
Anchor | ||
---|---|---|
|
...
Anchor | |||
---|---|---|---|
|
...
This functionality lives in the i2b2-state.js file. When this support library is fully loaded it emits the event "I2B2_STATE_READY". The new i2b2 web client uses HTML iframes to fully isolate plugin code from the main UI's environment. This allows plugins to use any libraries they want without having code conflicts with the main UI or other plugins. Unfortunately, browser standards dictate that when an iframe is manipulated within the DOM tree its contents is destroyed and reloaded. This results in destruction of the plugin's internal state. This can occur when a user drags and reorganizes the tabs in the main UI, or if the user expands the plugin to full size, or pops the plugin out into a floating window. To solve this problem, the i2b2 plugin framework can save the i2b2.model namespace to main UI memory. Also, upon loading of the state functionality library, any previous state is retrieved and automatically loaded into the i2b2.model namespace. In order to save the i2b2.model namespace you will need to call the i2b2.state.save() function whenever you update it as shown below:
function saveState() {
i2b2.model.stateString = document.getElementById("stateString").value;
i2b2.state.save();
}
To properly implement state management, you should drive your plugin from the data contained in the i2b2.model namespace. Upon loading your plugin, you should render the screen based on this persistent storage location.
window.addEventListener("I2B2_READY", ()=> {
// i2b2 is loaded and ready (including population of i2b2.model namespace)
if (i2b2.model.stateString === undefined) i2b2.model.stateString = "";
// populate the UI based on a previously saved state
document.getElementById("stateString").value = i2b2.model.stateString;
});
Anchor | ||
---|---|---|
|
...
Anchor | |||
---|---|---|---|
|
...
The Ontology cell found at i2b2.ajax.ONT contains the following AJAX calls:
GetCategories(), GetChildConcepts(), GetChildModifiers(), GetCodeInfo(), GetModifierCodeInfo(), GetModifierInfo(), GetModifierNameInfo(), GetModifiers(), GetNameInfo(), GetSchemes(), GetTermInfo() and _RawSent().
The CRC cell found at i2b2.ajax.CRC contains the following AJAX calls: deleteQueryMaster(), getIbservationfact_byPrimaryKey(), getNameInfo(), getPDO_fromInputList(), getQRY_getResultType(), getQueryInstanceList_fromQueryMasterId(), getQueryMasterList_fromUserId(), getQueryResultInstanceList_fromQueryInstanceId(), getQueryResultInstanceList_fromQueryResultInstanceId(),
getRequestXml_fromQueryMasterId(), renameQueryMaster(), runQueryInstance_fromQueryDefinition() and _RawSent().
The Workplace cell found at i2b2.ajax.WORK contains the following AJAX calls:
addChild(), annotateChild(), deleteChild(), getChildren(), getFoldersByProject(), getFoldersByUserId(), moveChild(), renameChild() and _RawSent().
The Project Management cell found at i2b2.ajax.PM contains the following AJAX calls:
deleteApproval(), deleteCell(), deleteDBLookup(), deleteGlobal(), deleteHive(), deleteParam(), deleteProject(), deleteRole(), deleteUser(), getAllApproval(), getAllCell(), getAllDBLookup(), getAllGlobal(), getAllHive(), getAllParam(), getAllProject(), getAllProjectRequest(), getAllRole(), getAllRoleUser(), getAllUser(), getApproval(), getCell(), getDBLookup(), getGlobal(), getParam(), getProject(), getProjectRequest(), getUser(), getUserAuth(), setApproval(), setCell(), setDBLookup(), setGlobal(), setHive(), setParam(), setPassword(), setProject(), setProjectRequest(), setRole(), setUser(), and _RawSent().
Anchor | ||||
---|---|---|---|---|
|
...
"i2b2.h.getProject",
"i2b2.ONT.view.nav.doRefreshAll"
]
}
}
Within the authorizedTunnel namespace exists an object named variables having its keys be the path used to access the variables within the main i2b2 UI code environment and its values being a string that contains the access permissions to that variable. The access string consists of a combination of the following 3 characters in any order: "R" signifying the read permission, "W" signifying the write permission, and "O" signifying that the targeted variable is an object to be read or written. If the targeted variable is found to be an object but the "O" flag is not used then a security error is thrown in the main UI and the request is ignored.
Within the authorizedTunnel namespace also exists an array named functions containing strings which are the path used to access the functions within the main i2b2 UI code environment.
To *read a variable's value* you will need to use i2b2.authorizedTunnel.variable as shown below. Notice how the accessor method uses square brackets [] to access the variable and not parentheses as in a function. Also, due to the asynchronous nature of window.postMessage() communications a Javascript Promise is returned instead of the actual value of the variable. This Promise can be rejected and an error thrown in the main UI if unauthorized/unconfigured access is attempted.
i2b2.authorizedTunnel.variable["i2b2.PM.model.isAdmin"].then((isReallyAnAdmin) => {
if (isReallyAnAdmin) {
alert("You ARE logged in as an Administrator");
} else {
alert("You are NOT logged in as an Administrator");
}
});
To set a variable's value you will also use i2b2.authorizedTunnel.variable as but you will simply use it on the left side of an assignment statement as shown below. If your plugin has not been configured or is otherwise not allowed write permissions to the variable your plugin will not be notified that the value was not assigned however an error will be thrown in the main UI.
i2b2.authorizedTunnel.variable["i2b2.PM.model.isAdmin"] =true;
To *access a function* you will use i2b2.authorizedTunnel.function. Once again, you will use square brackets \[ \] to access the function as shown below. When accessing the function an anonymous function will be returned which accepts any number of parameters that you can send to the real function within the main UI. When this anonymous function is executed it also returns a Javascript Promise which will resolve with the value returned by the function, or it may be rejected and an error is thrown within the main UI.
let mainUI_function = i2b2.authorizedTunnel.function["i2b2.h.getDomain"];
let mainUI_promise = mainUI_function(my, parameters, here);
mainUI_promise.then((domain) => {
alert("The i2b2 domain is: "+domain);
});
This can be written more succinctly as follows:
i2b2.authorizedTunnel.function["i2b2.h.getDomain"](my,parameters,here).then(
(domain) => {
alert("The i2b2 domain is: "+domain);
}
);
Anchor | ||||
---|---|---|---|---|
|
https://github.com/hms-dbmi/i2b2v2-webclient
Anchor | ||
---|---|---|
|
...
Anchor | |||
---|---|---|---|
|
...