Introduction
Limfinity scripting enables the user to expand out-of-the-box Limfinity framework functionality. Below are a couple examples that can be done with scripting.
Getting Started
Any UI element in Limfinity can be configured with a script which will run before or after the UI element is clicked. The Ruby language is used to create scripts in Limfinity. Examples of this include:
- Creating objects after a button is clicked
- Running a search after a dialog is closed
- Setting default values
- Showing custom error messages
You can view all configured scripts in Limfinity by going to "Settings and Preferences" --> More Settings --> All Scripts
What is a User-Defined Field (UDF)?
User-Defined Fields (UDFs) make up the subjects in Limfinity. Each UDF corresponds to a subject property. There are many types of UDFs, each with its own corresponding value types. For example, a “Number” type UDF only supports the entering of numerical values, whereas a “Date” type UDF only supports date format values. UDFs are often set using scripts.
Values
Values in Limfinity are defined as the generic objects which are to be manipulated. Values can be user-defined fields, standard fields, names, and IDs.
What is a Subject?
A subject is a Limfinity object with defined fields and values. A subject can have any number of fields, including collections of other subjects. Subjects are the core objects in Limfinity which are manipulated and handled to store data. Subjects can be of any type which has been defined in the Limfinity system, and there is no limit to the number of subjects which can be created. Subjects store data in standard and user-defined fields, and progress through respective workflows.
Using subjects in scripting
“Subj” is a Limfinity term which refers to the currently opened subject. For example, when working with
a sample subject record, “subj” in a script in that record’s window will refer to that subject. Any get_value()
calls will refer to the data within that subject.
Accessing Entered Values in a Form
# Populate the subject with values from a form, unless the value in the form is blank
params.each_pair{|udf, value|
if value.present?
subj.set_value(udf, value)
else
subj.remove_prop(udf)
end
}
It is sometimes necessary to get the value of a field object in a script for variable assignment or storage. When manipulating a subject in a script, the get_value()
method is used. However if a script is being run without a subject object, for example when entering information into a form via a Quick Link, then the params[]
call is used. The params[]
call obtains the value which is entered into the form, respective to each field.
Parameters
# Using the params[:required] script will ensure that each UDF with a "true" parameter must have a value
# before the form can be submitted.
params[:required] = {
'Chem Analyses' => true,
'Chemistry Package' => true
}
Parameters are accessed in a similar way as fields with already set values. The standard syntax for obtaining a parameter’s information is params[‘FIELD NAME’]. This call is very useful when creating a subject. The params[] call may be used within a set_value() method call, where the parameter may be the value to set.
Exception Handling
# The raise method is used for exception handling, and is also good for debugging
# Here we raise the value of the "Sample Type" UDF of the opened subject to see its value in a new window
raise subj.get_value('Sample Type')
# Here we raise an error message if the value of the "PH Level" UDF is higher than 7
if subj.get_value('PH Level') >= 7
raise "PH level is too high"
end
Limfinity supports the Ruby “Raise” method, which is used for handling exceptions. When an exception (error) needs to be handled, the raise method is an excellent tool. When an exception is handled using the raise method, the script in Limfinity will cease running, and as a result no actions will have been performed.
The raise method can be used for exception handling, and for logic and value checking. In this example, an error message is thrown if the value of the subject’s “PH Level” is higher than 7.
Debugging
The inspect
method can be called on a subject to provide output of a specified value inside a raise
statement. This is equivalent to calling to_json
on a Limfinity object.
The raise
method can be used to break out of a script and display a message.
To troubleshoot an error thrown by Limfinity:
- Copy the error message out of the error dialog
- Go to
Settings and Preferences
, chooseSystem Preferences
and click onVM Console Log
- Scroll to the bottom of the console log (the latest errors will show up on the bottom)
- If the error message is not at the bottom of the console log, click
Ctrl+F
to paste the copied error message into the search box - Once you have located the error message in the console log, take note of the line number and the script name where the error was originated. The stack trace accompanying the error will be shown below the error in the console log.
- Apply the fix to the script referenced in the console log and perform the action again.
Manipulating Subjects
Get Value
# In this example, a variable ‘age’ is set to the value of the subject’s “Age” user-defined field.
age = subj.get_value('Age')
# This subject is a "Testing Run". A testing run can have a sample, which can have its own information
# This call will obtain the value of the dilution of the sample within the testing run
#It is possible to “chain” get_value() method calls for downstream objects. In this example, the value of a
#testing run’s sample’s dilution is obtained. There is no limit to the number of get_value() chains that may
#be called.
dilution = subj.get_value('Sample').get_value('Dilution')
# The object 'Samples' is a collection of sample subjects, therefore it is stored in an array.
# A get_value() method call can be used to obtain teh collection of sample subjects.
samples = subj.get_value('Samples')
#For example, the destroy method will destroy the first sample (index) in the samples array,
# As designated by the [0]. Note that array indeces start at 0.
samples.[0].destroy
#Loops can also be used to perform actions on all elements in the array.
samples.each do |example|
example.destroy
end
Returns a value of a property. The get_value() method is used for obtaining a value of a subject’s or several subjects’ user-defined fields. This method gets the value of the defined parameter, and stores it in any variable to which it is assigned.
Defining Subject - “Subj”
“Subj” is a Limfinity term which refers to the currently opened subject. For example, when working with a sample subject record, “subj” in a script in that record’s window will refer to that subject. Any get_value() calls will refer to the data within that subject.
Parameters
Parameter | Description |
---|---|
property | The value of the property to retrieve |
It is possible to “chain” get_value() method calls for downstream objects. There is no limit to the number of get_value() chains that may be called.
Arrays are collections of data, therefore the get_value() method call can be used to obtain the value of the collection.
Note that in order to perform any action on an element in the array, a loop must be used for a single index that must be defined
Set Value
# Example: Setting a single value
# Set_value takes two parameters. The first parameter is the value (Request Method), and the second is the intended value (Metagenomics).
# Here we set the request method for the subject to Metagenomics.
subj.set_value('Request Method', 'Metagenomics')
# Chaining get_value() to set_value()
# In this example, a subject has a reference subject called “First Analysis”. The “First Analysis” subject has a subject called “First Sample”.
# With this chained call, the “First Sample” subject is having its “Sample Name” UDF assigned the value of “Example”, even though that subject is not currently opened on the screen.
# set_value() can be chained together after a get_value()
# Here we get the field "First Sample" from the field of a referenced subject "First Analysis" of the opened subject,
# and set the value of that first sample's UDF "Sample Name" to "Example".
subj.get_value('First Analysis').get_value('First Sample').set_value("Sample Name", "Example")
# Looping set_value()
# Loops are very useful when it is necessary to set the value of a field for several subjects
# Here we get the array of analyses of this subject, loop through each one, and set the UDF value "Checked" to "Yes"
subj.get_value('Analyses').each do |analysis|
analysis.set_value('Checked?', 'Yes')
end
The set_value()
method is used for setting the value of a subject’s or several subjects’ user-defined fields. The method accepts two parameters, the first of which is the field to be set, and the second of which is the intended value.
Parameters
Parameter | Description |
---|---|
property | The intended property to be set |
value | The intended value for the property |
Removing Values
# This example has the user select a Test Panel that will have all associated Lab Tests removed
panel = params['Select Panel to Clear Tests From']
panel.remove_prop('Lab Tests')
The remove_prop()
method is used to clear the contents of user defined fields within a subject. The remove_prop()
method is executed on the subject that calls the method. Note that the UDF is not permanently removed from the subject; remove_prop()
method clears the value currently stored in the UDF for calling subject.
Parameters
Parameter | Description |
---|---|
property | The value of the property to clear |
Naming Subjects
# Example: Overriding the Name of a Subject
# To set the name of a subject, an assignment operation can be used. Note that subject names must always be unique.
# Here we overwrite the name of the subject by appending the current date and time to it.
# Using the current date and time is a good way to ensure that the name of the subject remains unique.
subj.name = (subj.name + Time.now.to_s)
# Example: get_next_name_number
# Using the get_next_name_number is another way to ensure that a subject’s name remains unique. This method can be used when creating a subject or reassigning its name.
# Here we use the get_next_name_number method to ensure the subject's name is unique
"Sample " + '-' + ("%05d"% subject_type.get_next_name_number)
Subjects can be named in a variety of ways in Limfinity. For example, names can be generated via the subject type’s extension, or they can be set manually during a subject edit, or they may be modified using a simple assignment operation.
params[:display_field] = {
'Submission' => 'Submission Name'
}
Using params[:display_field] in Before Script
User can choose any ‘Text Field’ UDF as a display option for linked subject(s) instead of the system generated ‘Name’ field.
Creating Subjects
# Here we create a subject, and within a loop set a few of its UDF values
# Note that the UDF values are being set to the values which have been entered into the form by using the params[] objects
subject = create_subject('Job') do |jb|
jb.set_value('Client', params['Client'])
jb.set_value('# of Samples', params['# of Samples'])
end
# Here we call the create_subject method and create a subject of type "QC Sample"
# Using the open_subject() method call, the created subject will be opened.
subject = create_subject('QC Sample') do |qc|
qc.name = params['Name']
qc.set_value('Lot #', params['Lot #'])
end
open_subject(subject)
To create subjects via scripts in Limfinity, the create_subject()
method is called. The create_subject()
method is often called using a loop, so as to create multiple subjects, or to assign values to the subject which is being created.
It is often the intent to create a subject and immediately begin working on it, however the create_subject()
method call only creates the subject. In order to open the subject to immediately view it and work with it after it has been created, the open_subject()
method call is used.
Parameters
Parameter | Description |
---|---|
subject_type | The subject type of which the subject is to be created. |
Deleting Subjects
# Here we delete each sample associated with the subject
subj.get_value(samples).each do |sample|
sample.destroy
end
def before_delete_action
false
end
To delete subjects in Limfinity, the destroy() method is used. Calling the destroy() method will delete the subject from the database. The associated information and user-defined field data will be deleted as well.
Prevent Deleted Subjects
Add a method to Subject Type Subject Extension to prevent a user deleting any related subject/s by any means.
Copying Properties from Another Subject
# Here we create a new family, and copy the properties of it from an existing family (subject)
familyname = params['Family']
patient = create_subject('Patient') do |p|
p.set_value('Family', familyname)
p.set_value('UDP Inquiry', subj)
p.copy_properties_from(subj)
end
To copy properties from one subject to another, the copy_properties_from() method is used. This method is useful for duplicating subjects, and creating new subjects with existing data.
aside class="notice"> Copying properties works simply by taking a subject (user-defined field) and duplicating that data into another subject.
Setting Permissions
ug = UserGroup.find_by_name('Users')
sub = params['Project']
subj.set_value('Project', sub)
# Acl::NOACCESS, Acl::READONLY, ACL::READWRITE
Acl.set_permissions(sub, ug, Acl::READWRITE)
The set_permission
method is used to set a permission flag on an object for a user group. The following parameter definitions for the parameters are explained below:
- NOACCESS – Specifies a user group which has a designated access level of “no access”
- READONLY – Specifies a user group which has a designated access level of “view only”
- READWRITE – Specifies a user group which has a designated access level of “full access”
The syntax for the Acl.set_permission
method is as follows:
Acl.set_permission(subject, user_group, NOACCESS/READONLY/READWRITE)
The following After Script is used to give READWRITE
permission to subject type- subject ‘Project’ for
user group ‘Users’. The subject type ‘Project’ is set as ‘READONLY’ for user group ‘Users’
Removing Permissions
ug = UserGroup.find_by_name('Users')
sub = params['Project']
subj.set_value('Project', sub)
# Acl::NOACCESS, Acl::READONLY, ACL::READWRITE
Acl.remove_permission(sub, ug)
The remove_permission
method is used to remove a permission flag on an object for a user group. The syntax for the Acl.remove_permission
method is as follows:
Acl.remove_permission(subject, user_group)
Workflows and States
Workflows and states are the core of the Limfinity platform. Workflows dictate what types of objects can be manipulated, when they can be manipulated, and how. Workflows are the main engine in Limfinity and explain the individual processes which each object goes through.
Starting Workflows
# The start_workflow() method is used to start the workflow for a newly created subject
# param1 - Name of the workflow as defined in the system
# param2 - Subject for which the workflow should be started
patient = create_subject('Patient') do |p|
p.set_value('Family', params['Family'])
end
start_workflow('Patient Workflow', patient)
When a subject is created, it needs to be placed into a workflow. The start_workflow()
method is called to perform this. The start_workflow()
method takes two parameters: the first parameter is the name of the workflow, and the second parameter is the subject for which the workflow should be started.
There are two parameters required for the start_workflow()
method:
Property | Description |
---|---|
Workflow | Name of the workflow as defined in the system |
Subject | Subject for which the workflow should be started |
Advancing Workflows
# Iterate over a set of subjects and create a new subject with the same properties
# Place the subject into a 'Batched' state in the `Result` workflow
spikes.each do |spike|
new_result = create_subject('Result') do |rz|
rz.copy_properties_from(spike)
rz.set_value('Result Type', 'SAMPLE SPIKE')
end
advance_workflow('Result', 'Batched', new_result)
end
When a workflow has been started, or when it is in progress, it may be necessary to set a subject or list of subjects to a specific state. This can be done in any after script or run script, and so it can be performed in tools, workflow transitions, and even quick links.
There are three parameters for the advance_workflow()
method:
Property | Description |
---|---|
Workflow | The name of the Workflow in Limfinity |
Workflow State | The name of the state to which the subject should be advanced, within the workflow |
Subject | The subject object/loop index which is to be advanced. |
Acquiring All Subject States
# Here we check to see if the subject has been in more than 5 states
# If the subject has been in more than 5 states, an error is raised
states_array = subj.states
if states_array.count > 5
raise "This subject has been in too many states"
end
If it is ever necessary to acquire a list of the states that a subject has been in during its lifetime, the states method may be used. A simple subj.states
call may be used on the current subject, and an array of the subject’s states will be returned.
This method is useful for quality control, but may also be used for checking if a subject has been in a specific state by using additional scripting.
Determining the Current State of a Subject
# Here we use the current_states method to check if the subject is in a specific state
if subject.current_states = "Pending Approval"
raise "This subject is currently in the 'Pending Approval' state"
end
# Here we advance the subject through a workflow, if its array of states includes 'HOLD'
note = params['Employee Notes']
subj.set_value('Employee Notes', note) if note.present?
samples = subj.get_value('Samples')
samples.each do |sample|
advance_workflow('Sample', 'Received', sample)
end
advance_workflow('Sample Prep', 'MICRO', subj) if subj.current_states.map(&:name).include?('HOLD')
It is often necessary to determine the current state of a subject. In order to successfully obtain the current state of an object, the current_states
method is used. This method may be used in a check or in conjunction with an array index.
Messages
There are two different types of messages, which can be displayed via scripts in Limfinity: messages and alerts. Messages are displayed in confirmation dialogs, which the user must interact with, and alerts are displayed in a dropdown message for a short amount of time.
Showing Messages
# Example: Showing Messages
#Here we use the show_message() method to provide the user with a simple output message
show_message("All samples have been selected for analyses. Please click 'OK' to proceed.")
# Example: Showing Alerts
# Here we provide the user with a simple alert message, which they do not need to acknowledge
show_alert("You are now in the next workflow state")
Messages with confirmation dialogs are shown using the show_message() in After Script tab. The user will be required to click a confirmation “OK” button to acknowledge that they have seen the message. show_message() dialogs are shown after all other code has been executed.
Text Messages from Input Forms
params[:tab_name] = 'Samples'
params[:subject_type] = 'Sample'
params[:query] = search_query do |qb|
qb.and(
qb.state('Results Entry')
)
end
params[:hint_msg] = '<p style="color:red">List of Samples.</p>'
params[:tb_items] = [
{xtype: 'box', html: ''<span style =\'color:darkgreen\'>Result Entry State</span>'}
]
# Here we use a tool message to inform the user. THis message will be displayed in the tool itself
params[:tool _message] = "Prior to performing this action, ensure that all other actions are complete"
Text messages can be added to input forms by using the :tool_message
parameter.
User Defined Fields (UDFs)
User-Defined Fields (UDFs) make up the subjects in Limfinity. There are many types of UDFs, each with its own corresponding value types. For example, a “Number” type UDF only supports the entering of numerical values, whereas a “Date” type UDF only supports date format values. UDFs are often set using scripts.
Changing the way UDFs are displayed in grids
if (value == null) {
return '<span style="color:blue;font-weight:bold;"> No </span>'
} else return '<span style="color:red;font-weight:bold;"> '+val+' </span'
Making UDFs Required
#Using the params[:required] script will ensure that each UDF with a 'true' parameter must have a value before the form can be submitted
params[:required] = {
'Chem Analyses' => true,
'Chemistry Package' => true
}
It is often necessary to make sure a UDF has a corresponding value when a form is being completed. Furthermore, it may be necessary to ensure that a value has been entered prior to the form submission completion. Using the params[:required]
in Before Script can accomplish this.
Disabling UDFs in Forms
# Here we disable the 'Submitter Name' UDF, as it should be a read-only UDF
params[:disabled] = {
'Submitter Name'=>true
}
UDFs can be disabled in forms by using the params[:disabled]
parameter in Before Script. This parameter is used when specific UDFs in a form should be disabled, in order to enforce read-only access to the user.
Skipping/Hiding UDFs in Forms
# Here we skip the 'Submitter Name' UDF if it already has an entry
if subj.get_value('Submitter Name').present?
params[:skip_UDF] = {
'Submitter Name' => true
}
end
It is possible to skip or hide a UDF when editing a subject form, by using the params[:skip_UDF]
parameter. This is a very useful tool when logic is involved when editing a subject.
Creating Custom Views and Forms
Custom views and forms may be created in Limfinity, in lieu of the default form formatting. By default, Limfinity will build a default form containing all the UDFs that were passed in as parameters to the tool. The parameter UDFs can be modified in before and after scripts (making fields required or disabled, adding input validation, etc). However, it is possible to completely override the default form look and feel by replacing it with your own custom view.
Creating a simple form
# Before script: Open a form when on or more sample records are selected in the grid. Display a dialog with storage fields
raise "Please select at least one sample" unless subjects.length > 0
params[:dialog_options] = {maximizable: true, resizable: true, layout: ‘fit’}
params[:required] = {
'Freezer'=>true,
'Rack'=>true,
'Shelf'=>true,
'Date Stored'=>true
# After script: Update each selected sample with storage information from the form and update their status. Display alert to the user when operation is completed.
subjects.each do |s|
s.set_value('Freezer', params['Freezer'])
s.set_value('Rack', params['Rack'])
s.set_value('Shelf', params['Shelf'])
s.set_value('Box', params['Box'])
s.set_value('Slot', params['Slot'])
s.set_value('Date Stored', params['Date Stored'])
advance_workflow('Sample', 'Stored', s)
end
show_alert("#{subjects.length} Samples successfully stored to #{params['Freezer'].name}" )
- Create a quick link or a workflow tool
- Enter UDF names into the
Script Parameters
field (these UDFs must already exist in Limfinity) - Create a before script (if you would like to apply attributes to the UDFs), or perform validation.
- Create an after script with the funcionality that needs to happen after the user clicks on the tool (this can be creation of new subjects, updating data, or displaying alerts)
In this example, we are using params[:dialog_options] = {maximizable: true, resizable: true, layout: ‘fit’}
to create a resizable dialog.
Creating a custom form
extend ScriptRunner::UI
params[:custom_fields] = encode_fields([item1, item2...])
params[:submit_disabled_as_empty] = true
In order to create custom forms and UIs, a few scripts must be used. The layout form the form can either be defined in the before script, or in a helper script (if the layout is very complicated). view. A before script and after script are necessary for the tool. Once these three scripts are written and in place, the custom form may be used.
To create a custom form:
- Create a quick link or a workflow tool
- Right-click on the workflow tool and click on Before Script
- You must extend the
ScriptRunner:UI
class - Create an array of items that you want to display as fields on the form, and encode them by using the
encode_fields
method - You must set the value of
params[:custom_fields]
property to the value returned by theencode_fields
- If you wish to submit disabled fields as empty values, you can use the property
params[:submit_disabled_as_empty]
Custom form with a fieldset
# This example creates a form with multiple fieldsets and rows containing UDFs
extend ScriptRunner::UI
params[:custom_fields] = encode_fields([
field_set(title:'2012-0846', items:[
field_row([
udf('Patient Name', subj)
]),
field_row([
udf('MRN_Number',subj)
]),
field_row([
udf('Consenting Protocol', subj, labelWidth:150)
]),
field_row([
udf'PSC Date', subj),
udf('PSC Type', subj, flex:3)
]),
field_row([
udf('Principal Investigator', subj, labelWidth:150)
]),
field_row([
udf('Title', subj.get_value('Consenting Protocol'))
]),
field_row([
udf('Requesting Investigator', subj)
]),
field_row([
(udf'Surgery Date', subj),
udf('Surgeon', subj),
udf('Building ID', subj),
udf('Room ID', subj)
]),
field_row([
udf('Preliminary Diagnosis', subj)
])
]),
field_set(title:'Tissue Specific Information', items:[
field_row([
udf('Sample Type', subj)
]),
field_row([
udf'Organ/Sites', subj)
]),
field_row([
udf'Processing Details', subj)
])
]),
field_set(title:'Special Instructions', items:[
field_row([
udf('Special Instructions', subj)
]),
field_set(title:'Pickup Information', items:[
field_row([
udf('Pick Up Date/Time', subj)
]),
field_row([
udf('Contact for Pickup', subj)
])
])
])
This example demonstrates how to create a form with multiple fieldsets and multiple rows. Each row is created
by calling field_row
and passing it one or more udfs.
Custom form with hide/show logic
# Create a custom form with a radio button and a field set. Here we want to show the field set only when
# the value of the 'Find Requsitions' radio button is 'Submitted'
extend ScriptRunner::UI
params[:custom_fields] = encode_fields([
udf('Find Requisitions', nil, labelWidth:160, required:false),
field_set(title:'Find By Properities', border:'1 0 0 0', items:[
udf('External Source ID', nil, info:'This field can be used for the Sample Barcode Entry',
allowCreate:false, labelWidth:160, anchor:'100%'),
udf('Requisition', nil, labelWidth:160, allowCreate:false),
udf('Patient', nil, labelWidth:160, allowCreate:false),
udf('Requesting Physician', nil, labelWidth:160, allowCreate:false),
udf('Collection Date', nil, labelWidth:160, anchor:'50%'),
],
react: {
shown_when: 'value == "Submitted"',
only: 'Find Requisitions'
})
])
You can attach listeners to any field by using the react
property. In this example, we will hide/show a fieldset based on a value
of a radio button. In order to hide or show a component you must use the shown_when
property, and pass it an expression which evaluates to true or false.
The only
property can specify a component that the field will listen to. If only
is missing, the field will listen to changes on all
fields on the form.
Populating form fields with values from other fields
# In this example we first pick a Billing Facility, and then auto-populate the Billing Facility Address field with the
# value of the facility's address stored in the database.
field_container([
udf('Billing Facility', subj, labelWidth:160, required: true, allowCreate:false, filter: "#{facility_filter}"),
udf('Billing Facility Address', subj, labelWidth:160, anchor:'100%', height:40, required: true, validateAddress:true, react:{
change:'form.setValuesAsync({id: value, udfs: {"Address":"Billing Facility Address"}})',
only: 'Billing Facility'
})
],
react: {
shown_when: "value == 'Facility'",
only: 'Bill To'
}
)
This example demonstrates how you can populate fields with values from another field. You can use the change
listener to
call either setValue
or setValuesAsync
(if you want to suspend listeners while the form is being populated).
Filtering dropdowns in forms
# In this example we only want to show tests that are already on the requisition, and are applicable to all specimen types or our specimen types
udf('Tests', nil, value:tests, required:true, allowCreate:false,
filter: "<-Requisition::\"Tests\" = #{req.id} AND (\"Specimen Types\" = #{specimen.id} OR \"Specimen Types\" = null)",
react: {
change: "
this.setFilter(\'<-Requisition::\"Tests\" = #{req.id} AND (\"Specimen Type\" = \'+value+' OR \"Specimen Types\" = null)');
this.setValue(#{tests_by_specimen.to_json}[value]);",
only: 'Specimen Type'
}),
# Here we only want to see tests that are not archived and are orderable (i.e clients can order them)
udf('Non-Orderable Tests', nil, value:non_orderable_tests, filter: 'terminated = false AND "Non-Orderable" = true', allowCreate:false),
This example demonstrates how you can filter the values of dropdowns by a criteria or an expression. There are multiple ways to set filters.
- The simplest way to filter something is to set the
filter
property on a UDF, like so:filter:"terminated is false",
. - You can plug in your variables into the ruby template by following this example:
filter:"Facility = #{facility ? facility.id : 0} and terminated is false"
- You can also pass in a filter expression like so:
filter: "#{facility_filter}")
- Filter by state:
filter: "#state = Active""
UI class methods
udf('Requesting Physician', subj, addCustomFields: physician_layout(subj, 2), labelWidth:160, required:true,
filter:"Facility = #{facility ? facility.id : 0} and terminated is false",
react: {
shown_when: 'value',
change: "this.setFilter('terminated is false and Facility='+(value || 0));",
only:'Facility'
}),
udf
Creates a UDF (user defined field).
Parameter | Description |
---|---|
:name | UDF name |
:subj | Subject containing the UDF |
:options | The options object |
field_row([
udf('Decimal Places', subj),
udf('Unit', subj, labelWidth:60)
]),
field_row
Creates a field row by taking an array of fields and laying them out in one row
Parameter | Description |
---|---|
:items | Array of items to place into a form row |
:options | The options object |
field_container(fields, defaults: {anchor:'100%', labelWidth:160}, react:{
init: 'this.setDisabled(!value)',
only: 'Patient'
})
field_container
Lays out passed in items in a field container. Useful if you want to apply the same styling to all items within a container
Parameter | Description |
---|---|
:items | Array of items to place into a form row |
:options | The options object |
# Example fieldset
field_set(title:'General Information', border:'1 0 0 0', defaults:{anchor:'100%'}, items:[])
field_set
Creates a ExtJs 4.2.2 fieldset with the given options
Parameter | Description |
---|---|
:options | The options object |
choice_by_query
Creates a Choice type UDF but with the drop-down list filled by query
Parameter | Description |
---|---|
:name | The UDF name |
:subj | Subject containing the UDF |
:query | The query object that will produce a set of results to populate the picklist |
:options | The options object to pass to the picklist |
custom_radio_group
Creates a radio group from given options
Parameter | Description |
---|---|
:args | A configuration object, consisting of args[0] = name for the radio group and args[1] = the options object. |
The options object can contain an items
property with each item having a name
and checked
properties.
udfs_for_subject_type
Returns a list of UDFs that exist for a given subject type in Limfinity
Parameter | Description |
---|---|
:st | The subject type |
:subj | Subject containing the UDF |
:customizations | Object containing any additional properties for the UDFs such as "readOnly", or "anchor |
subj = UI.add_subject('Analyte', params, {name: name})
add_subject
Creates a subject populated with the values from the params
Parameter | Description |
---|---|
:st | The subject type |
:params | The params (usually from the custom form/view) |
:options | The options object |
UI.save_subject(subj, params, name != subj.name ? {name: name} : {})
save_subject
Saves a subject populated with the values from the params. This method performs access controlled read and write operations, and writes to the audit trail.
Parameter | Description |
---|---|
:subject | The subject to save |
:params | The params (usually from the custom form/view) |
:options | The options object. If the options object contains "name" or "gen:name" properties, they will be used to create a new subject name |
opts = count ? {count: count} : {}
ScriptRunner::UI::search_tab_link(subj_type_name, query, "style=\"color:white; text-decoration:none;\" onmouseover=\"this.style.color='black'\" onmouseout=\"this.style.color='white'\"", tab_name, opts)
search_tab_link
Generates a link opening a search tab or showing '0' if nothing found
Parameter | Description |
---|---|
:subject_type_name | The subject type to search |
:query | The query to run the search |
:tab_opts | Object containing tab parameters |
:link_attrs | Link attributes |
:tab_anem | Name for the new tab |
#Example for Group Edit Component - display grid
# Displays a grid with 4 rows, each containing an editable collection kit record
params[:tool_message] = "Create up to 5 Collection Kits<br><br>"
extend ScriptRunner::UI
column_configs = {
'Quantity' => {minValue: 1}
}
params[:custom_fields] = encode_fields([
group_editor('Add_Collection_Kits', [
{0=>subj.get_value('Facility'), 3=>0},
{0=>subj.get_value('Facility'), 3=>0},
{0=>subj.get_value('Facility'), 3=>0},
{0=>subj.get_value('Facility'), 3=>0}
], name: 'custom[data]', flex: 1)
])
params[:custom_fields_place] = 'top'
# script here to process the data from the Group Edit table
# This script reads all the data out of each row and creates one collection kit per row
# The editable fields are defined in the "Add Collection Kits" workflow tool
extend ScriptRunner::UI
names = []
count = 0
data = parse_group_edit_data(params['data'])
data.each do |row|
quantity = row.fetch(row.keys.find{|p|p[:display_name] == 'Quantity'})
specimen_type = row.fetch(row.keys.find{|p|p[:display_name] == 'Specimen Type'})
facility = row.fetch(row.keys.find{|p|p[:display_name] == 'Facility'})
components = row.fetch(row.keys.find{|p|p[:display_name] == 'Kit Components'})
if quantity > 0
for i in 1..quantity
kit = create_subject('Collection Kit') do |kit|
kit.set_value('Facility', facility)
kit.set_value('Specimen Type', specimen_type)
kit.set_value('Kit Components', components)
kit.advance_workflow('Collection Kit', 'Requested')
count += 1
end
end
end
end
show_alert("Created #{count} Collection Kits") if count != 0
group_editor
Embeds an editable grid within a dialog
Parameter | Description |
---|---|
:tool | The instance of the subject group edit tool defined in the workflow builder |
:content | An array containing the configuration for each row that will be displayed in the embedded grid. |
:options | An array of options: payloads, column configs or anything else that needs to be passed ot the component |
select_template_field
?????????????
Parameter | Description |
---|---|
:subject_type | The name of the subject type |
:options | An array of options |
select_printer_field
?????????????
Parameter | Description |
---|---|
:options | An array of options |
Sending Emails
# In this example, an array of recipients is first create,d and then an email is setn to the recipients using an email template by the name of "Example Template", regarding the opened subject
# Create an array of recipients
recipients = []
# Add all members of the "User Group 1" group to the recipients array
recipients << find_user_group('User Group 1)
# Add all members of the "User Group 2" group to the recipients array
recipients << find_user_group('User Group 2)
# Send an email using the email template "Example Template" regarding the current subject
send_email( recipients , find_email_template('Example Template'), subj)
Limfinity supports the automatic sending of emails through scripts, if the installation is set up with proper emailing credentials. The send_email()
method is used to send emails to users with registered email addresses to their user accounts.
In this example, an array of recipients is first created. Recipients can be specific users, or entire user groups. User groups are added to the recipients array in this case.
After the recipients have been assigned, the send_email()
method is called. The method takes the first parameter of the recipients, the second of the defined email template, and the last parameter of the opened subject.
*Note that an email template is always required to send an email. Email templates must be created in the system in order to successfully send an email.
Sending an email with a file attachment
# recipient email address
email_addr = 'test@ruro.com'
# This is the email template in the system
template = "Email Test"
# This is the 'File' UDF set in the 'Script Parameter'
if params['ATTACHED FILE'].present?
file = params['ATTACHED FILE']
subj.set_value('ATTACHED FILE', file)
end
# the attached file
rfile = subj.get_value('ATTACHED FILE')
send_email(email_addr, template, subj) do |e|
e.add_attachment(rfile, rfile.to_s, rfile.to_json['mime_type'])
end
show_message('Email sent')
Files can be attached to the email using ‘File’ UDF. When creating the email workflow tool, the field ‘Script Parameter’, which is the ‘File’ UDF, needs to be selected. The After Script will contain the reference of the script parameters.
Errors
The Lifinity API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- The request is incorrect. |
API
List of Objects Supported by Limfinity API
AuditRec
A record of any change within the system.
Parameter | Description |
---|---|
:id | Unique ID of an audit record. |
:obj_name | Name of the changed object. |
:user | The name of the user that made the change. |
:obj_type | The type of the object changed. |
:created_at | The date the audit record was created. |
:message | The action performed that created the audit. |
:comments | Any user-generated comment added when the audited action was performed. |
Auth_token
An authorization token used in place of a user’s password for API calls. Using the auth_token will omit the “API Session Created” and “API Session Removed” entries in the audit log.
Users
Uniquely identifies a user in the system:
Parameter | Description |
---|---|
:id | Unique ID of a user. |
:username | User’s Login name. |
:fullname | User’s full name. |
User’s email. | |
:created_at | Date when the user was created in the system. |
:roles | Roles assigned to the user. |
:disabled | Defines whether the user is currently disabled. |
:locked = | Defines whether the user is currently locked. |
:active | Defines whether the user is currently active. |
:groups | List of User Groups this user belongs to. |
Group
Uniquely identifies a user group in the system:
Parameter | Description |
---|---|
:id | Unique ID of a user group. |
:name | User group’s name. |
:description | Description of the group. |
:created_at | Date when the group was created in the system. |
:created_by | User name who created this group. |
:updated_at | Date when the group was last updated. |
:users-count | Number of users in the group. |
:baseline | Placeholder text. |
Role
A role that defines the access permissions in the system:
Parameter | Description |
---|---|
:id | Unique ID of a role. |
:name | Role’s name. |
:rights | A list of rights assigned to the role. |
:baseline | Placeholder text. |
:created_at | Date when the role was created in the system. |
:system_role | Defines whether the role is internal (built-into the software) or user-defined. |
UserField
A user-defined field in the system:
Parameter | Description |
---|---|
:id | Unique ID of a user-defined field. |
:name | Internal name of the user-defined field. |
:display_name | Display (human readable) name of user-defined field. |
:type | User-defined field type (“Date”, “Text Field”, “Text Area”, “Checkbox”, etc.) :searchable = Defines whether the user-defined field is searchable. |
:values | User-defined field values. |
:created_at | Date when the user-defined field was created in the system. |
:updated_at | Date when the user-defined field was last updated. |
:created_by | User name who created this user-defined field. |
:used_by | Which objects use the user-defined field. |
:permission | Permissions applicable to the user calling a method which returns this object. |
SubjectType
A user-defined subject type in the system:
Parameter | Description |
---|---|
:id | Unique ID of a subject type. |
:name | Internal name of the subject type. |
:descr | Description of the subject type. |
:color | Color of the icon representing the subject type. |
:searchable_quick | Defines whether the subject type may be found in a quick search. :searchable_advanced = Defines whether the subject type may be found in an advanced search. :searchable_batch = Defines whether the subject type may be found in a batch search. |
:fields | List of user-defined properties. |
:searchable | The subject type is searchable within the system. |
:syslock | Indicates if the object is “locked” in the configuration, and can’t be changed regardless of the site. :baseline = Indicates if the object is part of the baseline configuration. |
:created_at | Date when the subject type was created in the system. |
:updated_at | Date when the subject type was last updated. |
:created_by | User name who created this subject type. |
:enabled | Enabled or disabled flag for this subject type. |
:permission | The permissions available to this subject type. |
:configuration | The subject type is part of the system configuration. |
:fields_count | Number of user-defined fields in this Subject Type. |
SubjectTypeGroup
A user-defined group of subject types in the system:
Parameter | Description |
---|---|
:id | Unique ID of a subject type group. |
:subject_types | The subject types associated with this group. |
created_at | Date when the subject type group was created. |
baseline | Indicates if the object is part of the baseline configuration. |
updated_at | Date when the subject type group was last updated. |
created_by: | User name who created this subject type group. |
Subject
Any user object in the system. Subjects are instances of a particular Subject Type:
Parameter | Description |
---|---|
:id | Unique ID of a subject. |
:name | Subject name. |
:barcode_tag | The unique barcode number assigned to the subject. :rid_tag = The unique RFID number assigned to the subject. :subject_type = Subject type name (Example: Bacteria or Sample). |
:created_at | Date when the subject was created in the system. |
:updated_at | Date when the subject was last updated. |
:terminated | Flag if subject is terminated and no longer part of process/workflow. :user = Username of a subject owner. |
:permission | The permissions available to this subject. |
:flow_states | Workflow states which the object has been in. |
:created_by | The user that created the subject. |
:updated_by | The user that last updated the subject. |
:udfs | The number and names of all user-defined fields associated with this subject. |
List of API Functions
Returned Objects
LIMFINITY objects returned by API function.
Required Parameters
Necessary parameter or parameters for the method to run correctly. Without the required parameters an error message from the server should be expected. These will be written in the format required for the script along with placeholder text within the ‘ ’ marks.
Optional Query parameters
Optional parameters to control the results. These will be written in the format required for the script along with placeholder text within the ‘ ’ marks.
Optional Control parameters
Optional parameters to control the number and order of records in the output, and to implement paging of the results. These will be written in the format required for the script along with placeholder text within the ‘ ’ marks.
audit
#Example #1 - This API will print the total number of Audit Records and list all related information.
#add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
#, :date_flag=>'all/today/yesterday/week/month': Allows user to search for a specific date #, :date_range=>'date from,date to': Allows user to search a specific date range
#, :subj_ids=>'value,value': comma-separated Subject IDs to get audit records
#add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
#, :start=>'value': specifies what record to start listing from
#, :limit=>'value': limit number of records to retrieve
#, :sort=>'text': sort the records by a specific value
#, :dir=>'ASC/DESC': sort the records in ascending or descending order
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'audit'#Copy and paste optional query and/or control parameters here
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
data.each do |key,value|
if key == "AuditRecs"
value.each do |types|
puts "--------------"
types.each do |k,v|
puts (k.to_s + ": " + v.to_s)
end
end
end
end
Retrieves a list of audit records of every change made within the system.
Property | Parameter | Description |
---|---|---|
Returned Objects: | AuditRecs | |
Required Parameters: | None | |
Optional Query Parameters | :date_flag=>’all/today/yesterday/week/month’ | Displays audit records made today, yesterday, this week, or this month. |
:date_range=>’date_from,date_to’ | Displays audit records made within a specific date range(format: mm/dd/yyyy). | |
:subj_ids=>’value,value’ | Displays audits records of a specific range of subjects. | |
Optional Control Parameters | :start=>’value’ | The item specific ID to start the list with. |
:limit=>'value' | The total number of items to retrieve. | |
:sort=>'text' | Sort the displayed results by a specific field such as subject_type, subject_name, etc. | |
:dir=>'ASC/DESC' | Sort the displayed results in ascending or descending order. |
users
#Example #2 - This API will print the total number of Users and list all related information.
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'users'
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
data.each do |key,value|
if key == "Users"
value.each do |types|
puts "--------------"
types.each do |k,v|
puts (k.to_s + ": " + v.to_s)
end
end
end
end
Retrieves a list of users within the system.
Property | Description |
---|---|
Returned Objects | Users |
Required Parameters | None |
Optional Query Parameters | None |
Optional Control Parameters | None |
users_groups
#Example #3 - This API will print the total number of User Groups and list all related information.
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'user_groups'
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
data.each do |key,value|
if key == "Groups"
value.each do |types|
puts "--------------"
types.each do |k,v|
puts (k.to_s + ": " + v.to_s)
end
end
end
end
Retrieves a list of user groups within the system.
Property | Description |
---|---|
Returned Objects | Groups |
Required Parameters | None |
Optional Query Parameters | None |
Optional Control Parameters | None |
roles
#Example #4 - This API will print the total number of Roles and list all related information.
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'roles'
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
data.each do |key,value|
if key == "Roles"
value.each do |types|
puts "--------------"
types.each do |k,v|
puts (k.to_s + ": " + v.to_s) end
end
end
end
Retrieves a list of roles within the system.
Property | Description |
---|---|
Returned Objects | Roles |
Required Parameters | None |
Optional Query Parameters | None |
Optional Control Parameters | None |
userfields
#Example #5 - This API will print the total number of User Fields and list all related information. #add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
#, :query=>'text': optional search string to filter the results.
#add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
#, :start=>'value': specifies what record to start listing from
#, :limit=>'value': limit number of records to retrieve
#, :sort=>'value': sort the records by a specific value
#, :dir=>'ASC/DESC': sort the records in ascending or descending order
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'userfields'#Copy and paste optional query and/or co ntrol parameters here
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
data.each do |key,value|
if key == "UserFields"
value.each do |types|
puts "--------------"
types.each do |k,v|
puts (k.to_s + ": " + v.to_s) end
end
end
end
Retrieves a list of user-defined fields within the system.
Property | Parameter | Description |
---|---|---|
Returned Objects | UserFields | |
Required Parameters | None | |
Optional Query Parameters | :query=>’text’ | Displays a list of user-defined fields containing a specific text string. |
Optional Control Parameters | :start=>’value’ | The item specific ID to start the list with. |
:limit=>'value' | The total number of results to retrieve. | |
:sort=>'text' | Sort the displayed results by a specific field such as subject_type, subject_name, etc. | |
:dir=>'ASC/DESC' | Sort the displayed results in ascending or descending order. |
subject_types
#Example #6 - This API will print the total number of Subject Types and any relevant information
#add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
#, :query=>'text': optional search string to filter the results.
#add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
#, :start=>'value': specifies what record to start listing from
#, :limit=>'value': limit number of records to retrieve
#, :sort=>'value': sort the records by a specific value
#, :dir=>'ASC/DESC': sort the records in ascending or descending order
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'subject_types'#Copy and paste optional query and/or control parameters here
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
data.each do |key,value|
if key == "SubjectTypes"
value.each do |types|
puts "--------------"
types.each do |k,v|
puts (k.to_s + ": " + v.to_s) end
end
end
end
#puts data
Retrieves a list of subject types within the system.
Property | Parameter | Description |
---|---|---|
Returned Objects | SubjectTypes | |
Required Parameters | None | |
Optional Query Parameters | :query=>’text’ | Displays a list of subject types containing a specific text string. |
Optional Control Parameters | :start=>’value’ | The item specific ID to start the list with. |
:limit=>'value' | The total number of results to retrieve. | |
:sort=>'text' | Sort the displayed results by a specific field such as subject_type, subject_name, etc. | |
:dir=>'ASC/DESC' | Sort the displayed results in ascending or descending order. |
subject_groups
#Example #7 - This API will print the total number of Subject Type Groups and any relevant informatio n
#add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
#, :query=>'text': optional search string to filter the results.
#add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
#, :start=>'value': specifies what record to start listing from
#, :limit=>'value': limit number of records to retrieve
#, :sort=>'value': sort the records by a specific value
#, :dir=>'ASC/DESC': sort the records in ascending or descending order
require 'rubygems'
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'subject_groups'#Copy and paste optional query and/o r control parameters here
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
data.each do |key,value|
if key == "SubjectTypeGroups"
value.each do |types|
puts "--------------"
types.each do |k,v|
puts (k.to_s + ": " + v.to_s) end
end
end
end
#puts data
Retrieves a list of subject type groups within the system.
Property | Parameter | Description |
---|---|---|
Returned Objects | SubjectTypes | |
Required Parameters | None | |
Optional Query Parameters | :query=>’text’ | Displays a list of subject type groups containing a specific text string. |
Optional Control Parameters | :start=>’value’ | The item specific ID to start the list with. |
:limit=>'value' | The total number of results to retrieve. | |
:sort=>'text' | Sort the displayed results by a specific field such as subject_type, subject_name, etc. | |
:dir=>'ASC/DESC' | Sort the displayed results in ascending or descending order. |
subjects
#Example #8 - This API will print the total number of Subjects and any relevant information
#add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
#, :subject_ids=>'value': limit subjects to a list of IDs
#, :subject_names=>'text': limit subjects to a list of names
#, :user_fields=>'text': comma-delimited list of User Defined fields to retrieve for subjects #, :query=>'text': optional search string to filter the results.
#add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
#, :start=>'value': specifies what record to start listing from
#, :limit=>'value': limit number of records to retrieve
#, :sort=>'value': sort the records by a specific value
#, :dir=>'ASC/DESC': sort the records in ascending or descending order
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'subjects', :subject_type=>'Patient'#Copy and paste optional query and/or control parameters here
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
puts data
data.each do |key,value|
if key == "Subjects"
value.each do |types|
puts "--------------" types.each do |k,v|
puts (k.to_s + ": " + v.to_s)
end
end
end
end
#puts data
Retrieves a list of subjects within the system.
Property | Parameter | Description |
---|---|---|
Returned Objects | Subjects | |
Required Parameters | :subject_type=>’value/text’ | Limits the search to all subjects of a specific type(can use subject type name or specific ID). |
Optional Query Parameters | :subject_ids=>’value,value’ | Limits subjects to a list of item specific IDs. |
:subject_names=>’text,text’ | Limits subjects to a list of item specific names. | |
:query=>’text’ | Displays a list of subjects containing a specific text string. | |
Optional Control Parameters | :start=>’value’ | The item specific ID to start the list with. |
:limit=>'value' | The total number of results to retrieve. | |
:sort=>'text' | Sort the displayed results by a specific field such as subject_type, subject_name, etc. | |
:dir=>'ASC/DESC' | Sort the displayed results in ascending or descending order. |
delete_subject
#Example #9 - This API will delete a Subject as specified by ID or a combination of subject_type/subj ect_name
#add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
#, :subject_type=>'value': subject type ID
#, :subject_name=>'text': subject name
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'delete_subject', :id=>'13'#replace <:id=>'value '> with <:subject_type=>'value', :subject_name=>'text'> for optional query parameters
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
puts "-------------------"
puts data.to_json
puts "-------------------"
Deletes a subject as specified by ID.
Property | Parameter | Description |
---|---|---|
Returned Objects | None | |
Required Parameters | :id=>’value’ | The specific ID of the subject to be deleted, OR |
:subject_type=>’value/text’ | Limits the search to all subjects of a specific type(can use subject type name or specific ID). | |
:subject_name=>’text’ | Limits the search to all subjects matching the specified name | |
Optional Query Parameters | None | |
Optional Control Parameters | None |
gen_token
#Example #10 - This API will generate and print an "auth_token" to be used instead of a user's pass word. Using the auth_token will omit the API Session Created
# and API Session Removed entries in the audit log
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks = Net::HTTP::Post::Multipart.new url.path,
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'gen_token'
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
str = res.body
puts str #Output the generated authentication token
Creates an “auth_token” to be used instead of a user’s password. Using the auth_token will omit the “API Session Created” and “API Session Removed” entries in the audit log.
Property | Description |
---|---|
Returned Objects | Auth_token |
Required Parameters | None |
Optional Query Parameters | None |
Optional Control Parameters | None |
subject_details
#Example #11 - This API will Print all details of a Subject as specified by ID, Barcode, and RFID
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks 8.
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'subject_details', :subject_id=>'9',
:barcode_tag=>'L04000009', :rfid_tag=>'355AB1CBC000004000000009'
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
data.each do |key,value|
puts (key.to_s + ": " + value.to_s)
end
Deletes a subject as specified by ID.
Property | Parameter | Description |
---|---|---|
Returned Objects | A list of values corresponding to a specific subject | |
Required Parameters | :id=>’value’ | The specific ID of the subject to be displayed. |
:barcode_tag=>’value’ | The specific barcode tag of the subject to be displayed. | |
:rfid_tag =>value | The specific RFID tag of the subject to be displayed. | |
Optional Query Parameters | None | |
Optional Control Parameters | None |
run_script
#Example 12 - This API will execute a run_script / helper script by specifying the name of the script in the system and the data which should be passted to it.
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://demo.limfinity.com/api') 8.
req = Net::HTTP::Post::Multipart.new url.path, :username=> "admin",
:password=> "admin",
:name=> "demo_helper_script",
:data=> { "Name": "Sample 1", "BARCODE": "123456", "Specimen Name": "Specimen 1", "Created": "10/28/2014", "Created By": "User 1", "Current Amount": 10.2 }
res = Net::HTTP.star(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
puts data.to_json
Allows the running of a helper script by name and the passing of arbitrary JSON-formatted parameters to that script.
Property | Parameter | Description |
---|---|---|
Returned Objects | Helper script-returned serialized JSON | |
Optional Query Parameters | None | |
Optional Control Parameters | None | |
Required Parameters | :name=>’helper_script_name’ | The name of the helper script to be run. |
:data=>’’ | Arbitrary data to be passed to the script represented as a JSON object(s) of a string wit JSON-encoded object(s). This data will be accessible in the script as data. |
The script will also have access to all HTTP request parameters specified in the request using params[:parameter_name]
syntax
This function differs from all other API functions by how it should be called. Instead of passing run_script
as a value for the “method” parameter, is requires a special URL in the following form: http://{LIMS_ADDR}:{LIMS_PORT}/api/run_script
search_subjects
#Example #13 - This API will search for a Subject by variables such as Subject Type, Search Mode, Use r Fields, and texts strings.
#add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
#, :start=>'value': specifies what record to start listing from
#, :limit=>'value': limit number of records to retrieve
#, :sort=>'value': sort the records by a specific value
#, :dir=>'ASC/DESC': sort the records in ascending or descending order
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks)
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin',
:method=>'search_subjects', :subject_type=>'Client', :search_mode=>'REGULAR',
:user_fields=>'Address, Phone Number',
:fields=>'Subject Name', :conditions=>'contains', :values=>'ruro'#Copy and paste optional control par ameters here
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
data.each do |key,value|
if key == "Subjects"
value[0].each do
puts (k.to_s|k,v| +":"+v.to_s)
end
end
end
Retrieves a subject or list of specified subjects.
Property | Parameter | Description |
---|---|---|
Returned Objects | Subjects | |
Required Parameters | :search_mode=>’REGULAR/DEEP’ | Specifies the type of search to be performed. |
:subject_type=>’value/text’ | Limits the search to all subjects of a specific type(can use subject type name or specific ID, Example: ‘Client’). | |
:user_fields=>’text,text’ | Comma delimited list of User-defined fields to retrieve for the searched subject(s)(Example: ‘Address, Phone Number’). | |
:fields=>’text’ | fields to search within the subject(Example: ‘Subject Name’) | |
:conditions=>’text’ | The conditions that will be applied to the search subject. :values=>’value/text’ = Specific strings within the subject to be searched for. | |
Optional Query Parameters | None | |
Optional Control Parameters | :start=>’value’ | The item specific ID to start the list with. |
:limit=>'value' | The total number of results to retrieve. | |
:sort=>'text' | Sort the displayed results by a specific identifier such as subject_type, subject_name, etc. | |
:dir=>'ASC/DESC' | Sort the displayed results in ascending or descending order. |
import_subjects via CSV
#Example #14 - This API will import Subjects based on a CSV filerequire 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks) 8.
File.open("./clients.csv") do |the_csv|
req = Net::HTTP::Post::Multipart.new url.path,
:file=> UploadIO.new(the_csv, "text", "clients.csv"), :username=>'admin', :password=>'admin',
:method=>'import_subjects', :subject_type=>'Client'
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
puts "Total Success" if data['success']
puts data['message'] #success or error message will be printed here
end
Imports a subject or subjects along with specified fields from a CSV file.
Property | Parameter | Description |
---|---|---|
Returned Objects | Subjects | |
Required Parameters | :file=>’.CSV file’ | File to import(Must be CSV format). |
:subject_type=>’value/text” | The specific type of the subject or subjects to be imported. | |
Optional Query Parameters | None | |
Optional Control Parameters | None |
import_subjects via JSON
Imports a subject or subjects along with specified fields specified by subjects in JSON format
Property | Parameter | Description |
---|---|---|
Returned Objects | None | |
Required Parameters | :json=>’’ | String of LIMFINITY subjects in JSON format. |
:subject_type=>’value/text” | The specific type of the subject or subjects to be imported. | |
Optional Query Parameters | None | |
Optional Control Parameters | None |
upload_file_udf
#Example #15 - This API will upload a file to a Subject as specified by ID
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks)
fname = 'C:\Users\Louis\Desktop\New Limfinity API Guide Examples\clients.csv'
File.open("#{fname}") do |f|
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'upload_file_udf',
:file=> UploadIO.new(f, "text", fname), :id=>'2', :udf_name=>'File'
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
str = res.body
puts str
end
Uploads a file containing user-defined fields to the system.
Property | Parameter | Description |
---|---|---|
Returned Objects | None | |
Required Parameters | :udf_name=>’ text’ | Name of the file to be uploaded. |
:file=>’text’ | The content of the file to be uploaded. | |
Optional Query Parameters | None | |
Optional Control Parameters | None |
get_pedigree_data
#Example #16 - This API will print the pedigree data of a Subject as specifed by ID
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://demo.limfinity.com/api')#Copy and paste actual URL within the '' marks)
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :password=>'admin', :method=>'get_pedigree_data',
:subject_type=>'Patient', :subject_id=>'12345'
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
data.each_pair do |key, value|
if key.is_a?(Numeric) #has assigned patient
patient = value[:Individual]
father = value[:Father]
if father
father_id = father.is_a?(Subject) ? father.id : father
father_data = data[father_id]
puts father_data #output father data
end
mother = value[:Mother]
if mother
mother_id = mother.is_a?(Subject) ? mother.id : mother
mother_data = data[mother_id]
puts mother_data #output mother data
end
else #No assigned patient
puts "No assigned patient"
end
end
Retrieves the pedigree data of one family within the system.
Property | Parameter | Description |
---|---|---|
Returned Objects | Key/value pair pf pedigree node subject and its information. | |
Required Parameters | :family_subject=>’value/text’ | Family subject type(can use subject type name or specific ID). |
:pedigree_prop=>’text’ | Pedigree type user-defined field or its name(not required if there is only one user-defined field for this type | |
Optional Query Parameters | None | |
Optional Control Parameters | None |
Returned Hash Values
he key is an individual ID of a pedigree node. The key is the numeric subject ID for the pedigree nodes with the assigned subject, or a string otherwise. The value is a hash with the following content(each pair is optional).
Property | Description |
---|---|
:Individual | Assigned subject. |
:Mother | Subject if the mother node has an assigned subject; String ID otherwise. |
:Father | Subject if the father node has an assigned subject; String ID otherwise. |
:Gender | ‘Male’ or ‘Female’. |
:Sampled, :MZTwin, :DZTwin, :Proband, :Deceased, :Consultand, :Carrier, :Affected | Same as in the standard PED format. |
:terminated_pregnancy | “true” if the pregnancy was terminated. |
:adopted_in | “true” if the individual was adopted in |
:adopted_out | “true” if the individual was adopted out. |
Using auth Token
#Example #17 - The purpose of this API is to test if an auth token generated by "Example 10 Gen Token.rb" works as intended if used instead of a password.
require 'rubygems'
require 'json'
require 'net/http'
require 'net/http/post/multipart'
url = URI.parse('http://demo.limfinity.com/api')#Copy and paste actual URL within the '' marks
req = Net::HTTP::Post::Multipart.new url.path,
:username=>'admin', :auth_token=>'9bdc7e45-e541-4867-9077-6ff181876118', :method=>'users'#copy and paste generated auth token in <:auth_token=>''>
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
data = JSON.load(res.body)
total = data['Total']
puts total
puts data
data.each do |key,value|
if key == "Users"
value.each do |types|
puts "--------------"
types.each do |k,v|
puts (k.to_s + ": " + v.to_s)
end
end
end
end
This example is not linked to a corresponding method. The purpose of this example is to demonstrate how to use an auth token returned by “Example 10 Gen Token.rb”.
suffix = subj.get_value('Program Identifier')
url= 'https://clinicaltrialsapi.cancer.*9'
Calling External APIs with Limfinity
User can use call_external_service in After Script with optional :get, :post(default), and :put to specify the HTTP methods
Guides
Modelling your data with Limfinity
This guide walks you through the process of replicating your data model with Limfinity. In this guide you'll learn how to:
- Create a new subject type
- Create a subject
- Create new user-defined-fields
- Configuring grid options for a subject
In the sections below, we'll create a "Patient" subject that will be linked to a "Sample.
Step 1: Create a new Subject Type
A Subject Type
defines the type of data you can store. Think of it as a form, or a table.
Each subject type is annotated with user-defined fields
(UDFs) that capture the metadata for that object. Each instance of a subject type is called a subject.
- Log in and click on Settings and Preferences
- Click on Subject Types
- Click the plus button to create a new Subject Type New Subject Type
- Name your Subject Type "Patient" and specify the
Plural Name
- Patients - Click OK to save
Step 2: Adding User-Defined-Fields to your Subject Type
Now we have a new "Patient" subject type, but it has no fields. Let's add a couple:
- Click on the "Patient" subject type
- Click on the
Add User Defined Field
button and chooseDate
as the field type - Enter "DOB" for the User Field Name and check
Advanced Search
- Let's add a couple other fields: Phone Number (Text Field), Consent Signed (Checkbox), Gender (Choice - Male, Female, Both), Comments (Text Area)
- Click OK to Save
Let's also create another subject type and name it "Sample" with the field Amount (Numeric). What we want to do now is to link the sample to the patient it has been collected from.
- Open the "Sample" subject type
- Click on
Add User Defined Field
button and chooseLimfinity
->Subject
as the field type - Enter "Patient" as the User Field Name and select
Patient
as the `Subject Type - Click OK to Save
Step 3: Creating a subject
Our 'Patient' subject type has fields defined, but we do not yet have any actual patients.
Let's make a patient:
- Click on
Explorer
- Click on Patients
- Click the plus button to add a new subject
- Enter values for DOB, Gender, Consent Signed, Phone number, Comments and click OK to save the new subject
Configuring the subject type grid
Our newly added fields are not yet showing up on patient result grids. Let's configure the grid and add our new fields:
- Click on
Settings and Preferences
- Click on
Subject Types
- Select Patient and click
View Options
- Add fields DOB, Gender, Phone Number, Consent Signed and Comments
- Remove the UID field
- Move the fields DOB, Gender, Phone Number and Consent Singed to the top and click OK
Creating workflows
This guide walks you through the process of creating a workflow. In this guide you will learn how to:
- Create a new new workflow
- Create workflow states
- Add tools to a workflow
- Take a subject through a workflow
In the sections below, we'll create an "Issue" workflow. Let's start by creating an "Issue" subject type with fields:
- Description (Text Area)
- Status (Choice)
- Assignee (User)
- Resolved Date (Date)
Step 1: Create a new Workflow
Each workflow can only be attached to one single subject type, but subject types can belong to multiple workflows. A workflow describes how subjects go through processes and what actions are available for each state
- Click on
Settings and Preferences
- Click on the plus button and select the desired subject type ("Issue)
- Enter a name for the workflow. The convention is to name it the same as the subject type, so let's put in "Issue" as the worklfow name
- Click on the workflow to open it in the workflow editor window
Step 2: Add states
We have a brand new "Issue" workflow, but it has no states. Each record in the workflow will go through a sequence of states that model the workflow. For our "Issue" workflow, we know that it can either be "Open" or "Resolved". 1. Click on the plus button to add a new state 2. Let's call the new state "Open". This new state will appear on the canvas. By default, this state will be the entry state for all new subjects in the "Issue" workflow, but you can always change the first state by specifying a new "Entry State" in workflow editor 3. Create another state called "Resolved"
Step 3: Adding a workflow transition
Now that we have both "Open" and "Resolved" states, let's link it together. To do this, you will need to create a tool (it can be any type of tool)
1. Click on the plus button in the Tools
tab
2. Give your tool a name, and a title. Name
is the internal identifier, while Title
is the user-facing value
3. Specify the Input Subject Type
= Issue
4. Specify the Workflow Transition
= Resolved
5. Drag the tool into the "Open" state
5. You should now see an arrow stretch the "Open" state to the "Resolved" state
Let's add another tool to create a new Issue:
- Create a
Create New Subject
tool and name it "New Issue" - Fill out the
Name
,Title
,Output Subject Type
, andWorkflow
- Click
OK
to create a new Issue record
Step 4: Adding tool groups
Starting with Limfinity 7.1 you can now reuse individual tools or multiple tools in many workflows by placing them into tool groups. Tool groups can be used in many places such as Quick Links
(buttons that appear in the left nav bar) or workflows.
To create a toolgroup:
- Click on the plus button in the
Tool Groups
tab - Fill out the
Name
= Issues and theTitle
= Issues fields - You can specify whether to display the tool group as a quick link, or as a set of buttons on the workflow state. Let's place this toolgroup in the Quick Links bar.
- Add the "Resolve" and the "New Issue" tools to this tool group
- Refresh to see a folder with the workflow tools
Step 5: Taking a subject record through a workflow
Let's take an Issue from being open to resolution:
- Click on
Explorer
. and selectIssues
- Click
New Issue
- A "New Issue" dialog will open
- Fill out the data to create a new Issue
- Upon saving, the page for the new record will open and you should see a "Resolve" button on the right of the page