Create an Input Form with Form Builder

The BaseSpace Form Builder is a form engine responsible for generating forms for BaseSpace Apps. Developers can go to the dev portal and design their forms using a simple JSON format. The JSON is converted into html form elements in the BaseSpace UI.

This documentation describes the Json format for the forms and should be used as a resource for new controls as they get added.

Any app can use the Reports Builder tool, whether is it a Web, Desktop, or Native app.

How to Use Forms Builder

The Forms Builder tool is available by navigating to your app's page in the Develper Portal and clicking on the Forms Builder tab.

Active Form

You will be taken to the Revisions tab the first time that you visit the Forms Builder tab for an app.

The Active Form tab is also available, the active form is the form that the user will see in BaseSpace when they launch the app. Once you activate a form for your app, you can view that form directly on BaseSpace! For now, it will just be a placeholder form until you activate a form for the app.

Revisions

After clicking on Forms Builder, you will be taken to the Revisions tab. From the Revisions tab, you can manage the Active Form for your app.

There are two forms available by default, the Default Form and the Example Form.

  1. The Default Form is suggested for apps that only require a Project for input, in general only Web apps that wish to create their own input form will use this form.

  2. The Example Form is a very basic example of a form that can be created using the Forms Builder. This form's purpose is to show developers a simple form to make it easier to create complex ones.

In addition to these forms, you will also see a few buttons on the Revisions tab.

Here's a quick description of each button's function:

  • Open: If you select a form in the Revisions tab and click Open, the Forms Builder tool will be opened with the selected Form.
  • Activate: This button will activate the selected form. When a form is in the Inactive state, it can only be viewed in the Forms Builder tab. However, when a form is in the Active state, it will be the form that any user will see when they launch the app from BaseSpace (if they have permission to view the app, of course.) Once a form is Active, it cannot be modified in the Forms Builder tool.
  • Duplicate: Duplicates the selected form. To modify an existing form, we suggest using the Duplicate feature on a pre-existing form, making modifications, then activating the new form to keep a history of form changes.
  • Delete: Deletes the selected form.
  • Load More: The last 10 Custom Forms, not including the Default Form, will be displayed in the Revisions tab. If you wish to view more forms, simply click on this button and the next 10 will also load.

How to Obtain Data Selected in the Form

The final important feature of the Forms Builder tool is how it passes along the data selected in the input form to the app.

The method to obtain the data is slightly different depending on the type of app that is being created and how the data is being accessed, so we have broken this portion into three sections: Via Javascript in the Form, For Web and Desktop Apps, and For Native Apps.

Via Javascript in the Form

In some cases, an app may require custom validation with dependencies on other form elements in its form. In this scenario, common javascript can be executed in the Callbacks.js script and in any ScriptValidationRule in the form to access these input form values.

For example, for the following SampleChooser field:

    {
        "$type": "SampleChooser",  
        "size": 300, 
        "allowedPermissions": "read", 
        "label": "Input Sample",
        "required": true,
        "requiredMessage": "Please choose a sample",
        "id": "sample-1",
        "rules": "sample-reader"
    }

When a user is using this form, they will select a Sample as input, for this example let us say the Id of that Sample is 123. The user will then complete the form and click Continue to run the app. At this moment, an AppSession is created and the Properties field of this AppSession is populated with the following:

"Properties": {
    "Items": [
        "Type": "sample",
        "Href": "v1pre3/appsessions/{AppSession_Id}/properties/Input.sample-1",
        "Name": "Input.sample-1",
        "Description": "",
        "Content": {
            "Id": "123"
        },
    ],
}

We can access the Id of the Sample selected by using the following dataProvider.GetProperty("Input.sample-1").Id which, in this case, will return 123. If the SampleChooser had also included "multiselect":"true", this would return an array of Sample Ids that were selected by the user instead of a single value.

In some cases, the Content field of the Properties response object will not contain an Id field. The value is then stored directly within the Content field.

For example, for a TextBox with the Id custom-1, the following Properties would be generated on the AppSession if the user select 123 as the input value:

"Properties": {
    "Items": [
        "Type": "textbox",
        "Href": "v1pre3/appsessions/{AppSession_Id}/properties/Input.custom-1",
        "Name": "Input.custom-1",
        "Description": "",
        "Content": "123"
    ],
}

Now, the value that the user selected or inserted will be returned with the following:

dataProvider.GetProperty("Input.custom-1")

In this way, complex forms can be driven using user input.

How to Use the dataProvider.GetProperty() Method

dataProvider.GetProperty() takes a Property name as input. When the form is submitted, formbuilder will automatically append input. or output. to the id of your form field and save that as the Property name in the Property Items on the AppSession that is created. In general, Properties will have input. appended but if an Output Project or AppResult is selected by the user then it is appended by output. instead. For example, if the Id of the SampleChooser field in a form was sample-1, the following can be used to get the Sample that was selected by the user:

dataprovider.GetProperty("Input.sample-1")

If the Property Type for the Property is a BaseSpace resource (e.g. it is a run, project, appresult, or sample, or an array of those), the value returned will be the full BaseSpace resource or an array of full BaseSpace resources. In addition, if the id of the field in the form is app-session-id, the entire AppSession will be returned via this method.

Since the entire resource is returned, you may want to find specific information about the selected resource. For example, if we use dataProvider.GetProperty("Input.sample-1"), the Property on the AppSession (if the Sample's Id was 888888) will be the following:

{
    "Type": "sample[]",
    "Href": "v1pre3/appsessions/2695119/properties/Input.Samples",
    "Name": "Input.Samples",
    "Description": "",
    "Items": [
      {
        "Id": "888888",
        "Href": "v1pre3/samples/888888",
        "UserOwnedBy": {
          "Id": "3003",
          "Href": "v1pre3/users/3003",
          "Name": "Illumina Inc",
          "GravatarUrl": "https://secure.gravatar.com/avatar/702e4f8795f80bd0929a8b818bb19f65.jpg?s=20&d=https%3a%2f%2fbasespace.illumina.com%2fpublic%2fimages%2fDefaultCustomerGravatar.png&r=PG"
        },
        "Name": "HBr1",
        "SampleId": "HBr1",
        "Status": "Complete",
        "StatusSummary": "",
        "DateCreated": "2013-10-16T17:19:56.0000000",
        "TotalSize": 0,
        "Genome": {
          "Id": "4",
          "DisplayName": "Homo Sapiens - UCSC (hg19)",
          "SpeciesName": "Homo sapiens",
          "Source": "UCSC",
          "Build": "hg19",
          "Href": "v1pre3/genomes/4",
          "HrefFileSets": "v1pre3/genomes/4/filesets",
          "HrefAnnotations": "v1pre3/genomes/4/annotations"
        },
        "Read1": 51,
        "Read2": 51
      }
    ],
    "HrefItems": "v1pre3/appsessions/2695119/properties/Input.Samples/items",
    "ItemsDisplayedCount": 1,
    "ItemsTotalCount": 1
}

Now, any information from this response can be accessed by the form. If we want to return Read1 for the above Sample, we can use simple dot operators in the following way:

dataProvider.GetProperty("Input.sample-id").Read1

This will return 51 since that is the value for Read1 in the above response.

All of the information included in each full BaseSpace resource is described in the Rest API Reference.

If the Property Type is not any of the above and the id of the field is not app-session-id, the above method would instead return the value that the is in the form (either set by the user or by the form by default.)

For example, if the Type was a Textbox with id textbox-1 and the user input was hello, then dataProvider.GetProperty("Input.textbox-1") will return the value hello as a String.

More information about using the dataProvider to create complex forms and rulesets is described in the Open Ended Script Validation Documentation.

For Web and Desktop Apps

After the user selects the data for the input form and clicks Launch, the user is redirected to the app's redirect_uri with an appsessionuri. This appsessionuri contains the Id of the AppSession that was created once the input form was submitted.

All of the data that the user selected on the input form is saved as Properties of the AppSession that was created. Any Properties labelled input.* are input values and any labelled output.* are output values (e.g. an output Project.)

The app can parse the Properties of the AppSession to find all of the data that the user selected on the input form.

For Native Apps

After the user selects the data for the input form and clicks Launch, an AppSession is created. For Native apps, a file called appsession.json is created and stored in the data/input directory in your Docker image.

All of the data that the user selected on the input form is saved as Properties of the AppSession. Any Properties labelled input.* are input values and any labelled output.* are output values (e.g. an output Project.)

The app can parse the Properties of the AppSession to find all of the data that the user selected on the input form.

Forms Builder Components

There are two components of a form for BaseSpace applications, they are accessed by clicking on the Current Template dropdown menu and selecting the following:

  1. The form - JSON editor that allows developers to create complex, robust UI forms for users. Forms have two major components, "fields":[] and "rulesets":[]. Here's a short description of each:

    • Fields: Each field corresponds to an HTML UI form element that is generated on the input form (e.g. textboxes, dropdown menus, choosers, etc.)
    • Rulesets: Each rule validates some property of the field that it is applied to (e.g. only allowing hg19 Samples to be chosen as input.) In addition, some rules may be applied to the entire form for validation.
  2. The callbacks.js script - For Native apps only: This contains the command line argument that will be passed to your Docker image when a user launches your app from BaseSpace, billing information, and other launch-specific information.

The Form

There is only one form element and it contains all the fields and rules necessary for user input to start an app. The order in which you place the fields is the order in which they display on the form.

{
    fields: [],
    rulesets: []
}

This defines a form with no fields and no rules.

Fields

A form requires at least two fields to be useful; a user-input field and a submit button. The default form contains a ProjectChooser, a SampleChooser, and a TextBox:

{
    "$type": "Form",
    "fields": [
        {
            "$type": "TextBox",
            "size": 400,
            "minLength": 0,
            "maxLength": 150,
            "value": "Example [LocalDateTime]",
            "label": "Analysis Name",
            "required": true,
            "requiredMessage": "Please enter name for your app session.",
            "id": "app-session-name"
        },
        {
            "$type": "SampleChooser",
            "size": 300,
            "valueType": "Input",
            "allowedPermissions": "read",
            "label": "Sample",
            "required": false,
            "id": "samples",
            "rules": "sample-reader"
        },      
        {
            "$type": "ProjectChooser",
            "size": 300,
            "valueType": "Output",
            "allowedPermissions": "owner",
            "label": "Save Results To",
            "required": true,
            "requiredMessage": "Please choose a project",
            "id": "project",
            "rules": "is-project-owner"
        },
        {
            "$type": "SectionBreak"
        }
    ],
    "rulesets":[
        {
            "$type": "PermissionValidationRule",
            "permissions": "Read",
            "severity": "Error",
            "message": "You do not have read access to the selected sample",
            "id": "sample-reader"
        },
        {
            "$type": "PermissionValidationRule",
            "permissions": "Own",
            "severity": "Error",
            "message": "You aren't the owner of the selected project.",
            "id": "is-project-owner"
        }
    ]
}

Each field must have an id and a $type. $type is a specific form element for BaseSpace.

Common Field JSON Elements

For each form element, there are a few JSON properties that exist commonly. Here is a list of common JSON elements in the form with descriptions of each:

  • $type: The type of field being specified. This is a required element for each field. The possible options are:
    • TextBox: Creates a HTML string Textbox element in the form.
    • ProjectChooser: Creates a Chooser that displays Projects for the user to select from.
    • SampleChooser: Creates a Chooser that displays Samples for the user to select from.
    • RunChooser: Creates a Chooser that displays Runs for the user to select from.
    • AppResultChooser: Creates a Chooser that displays AppResults for the user to select from.
    • FileChooser: Creates a Chooser that displays Files for the user to select from, they are organized under the Project and AppSession they are tied with.
    • CheckBox: Creates a HTML Checkbox element in the form.
    • RadioButton: Creates a HTML Radio Button element in the form.
    • Select: Creates a HTML Drop-Down list of items in the form.
    • Numeric: Creates a numeric HTML Textbox element in the form.
    • SectionBreak: Creates a Section Break in the form (horizontal line for separation.)
    • FieldSet: Groups together multiple fields, rules can then be applied to the entire Field Set rather than each individual field. For grouping purposes on the form.
  • id: The Id of this field in the form. This is a required element for each field. This will also be added to the AppSession's Property field in the JSON. So, when an app is launched, the Id's of each field will be saved in the following format: input.{id} or output.{id} where {id} is the Id of the field.
  • required: A Boolean value that determines if this is a field that is required to be filled out by the user. If true, the app will not launch unless this field has a value. If false, the field can be optionally filled out by the user but is not a requirement to run the app.
  • requiredMessage: The message that will be displayed to the user if they attempt to run the app without filling in this form field.
  • valueType: Determines whether the data selected is input data or output data. This element defaults to Input. Accepted values are: Input and Output. If Output is selected, the Property added to the AppSession will have output. appended to it. If Input is selected, the Property added to the AppSession will have input. appended to it.
  • size: The size of the HTML field in the form's UI.
  • label: The label for the field. This will be displayed in the UI to the left of the form field.
  • helpText: Adds help text to the field, the help text will display as a hover-over icon that will display the Help Text specified here.
  • rules: The validation rules that are applied to this field. The rule will be applied to the field if the Id of the rule is in this element.
  • searchQuery: Currently only supported for the SampleChooser, AppResultChooser, ProjectChooser, FileChooser, and Resource Matcher field elements. Filters through the list of the available items based on the query provided. This uses BaseSpace Search and the scope for the search is set to the resource type that is selected, you can search on any metadata (via the Rest API) associated with that resource
  • value: The default value of this field. Can be a string, a numeric, a double, or a boolean depending on the field.
  • togglers: This element will toggle the specified toggleFields when the value in the toggler is selected.
  • displayfields: For any Chooser $type, this element will add fields for each item selected in the Chooser. Accepted displayFields are Selects, RadioButtons, TextBoxes, CheckBoxes, and Numeric fields.

Textbox

Use this for any text input

In addition to Common Field JSON Elements, this field also supports the following elements:

  • minLength: the minimum amount of characters allowed for this field.
  • maxLength: the maximum amount of characters allowed for this field.
  • value: the default value of the field. The default value of this element is an empty string. If "default value!" is specified, the default value will instead be {App_Name Date Time}, for example if the App_Name was HelloWorld: HelloWorld 1/1/2014 00:00:01.

    {
            "$type": "TextBox",  
            "size": 300, 
            "value": "default value!",
            "label": "App Session Name",
            "required": true,
            "requiredMessage": "Please enter name for your app session.", 
            "id": "app-session-name", 
            "helpText": "this help text will display next to the control in a pop over" 
    }
    

If the "id" of a TextBox is "app-session-name", the Property will be stored as an AppSession instead of a string value.

Preview:

TextBox

Project Chooser

Initializes a project chooser so that the user can choose a project as input or output. When a user launches the app from a Project or a Sample page in BaseSpace, the ProjectChooser is automatically populated with that Project or the Project that the Sample is contained within.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • allowedPermissions: the permission of required for the selected Project. Allowed values are owner and read. owner means that the user must be the Owner of the Project. read means that the user must be at least a collaborator on the selected Project.
  • multiselect: A Boolean that, if true, allows multiple Projects to be selected by the user within this Chooser. The default value is false.
  • valueType: Specifies whether this Project is an Input or an Output. Accepted values are Input or Output, the default value is Input is unspecified. If Input is selected, the selected resource will be added to each AppSession's Property as an input. Property. If Output is selected, the selected Project will be added to each AppSession's Property as an output.{id} Property where {id} is the id of the ProjectChooser field.
  • searchQuery: Filters through the list of available Projects based on the query provided. This uses BaseSpace Search and the scope for the search is set to projects

    {
            "$type": "ProjectChooser", 
            "size": 300, 
            "allowedPermissions": "owner",
            "label": "Save Results To",
            "required": true,
            "requiredMessage": "Please choose a project",
            "id": "project-id",
            "rules": "is-project-owner" 
    }
    

Preview:

ProjectChooser

Sample Chooser

Initializes a sample chooser so that the user can choose a sample as input or output.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • genomeFilters: disallows the sample selection in the chooser for specified genomes (comma-separated.)
  • multiselect: A Boolean that, if true, allows multiple Samples to be selected by the user within this Chooser. The default value is false.
  • searchQuery: Filters through the list of available Samples based on the query provided. This uses BaseSpace Search and the scope for the search is set to samples, you can search on any metadata (via the Rest API) associated with that Sample as well

    {
            "$type": "SampleChooser",  
            "size": 300, 
            "label": "Sample",
            "required": true,
            "requiredMessage": "Please choose a sample",
            "genomeFilters": "hg19",
            "id": "samples", 
            "rules": "is-paired-end,min-cycles-1,min-cycles-2,is-sample-reader,sample-is-not-empty" 
    }
    

Preview:

SampleChooser

Run Chooser

Initializes a run chooser so that the user can choose a run as input.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • multiselect: A Boolean that, if true, allows multiple Runs to be selected by the user within this Chooser. The default value is false.
  • searchQuery: Filters through the list of the available Runs based on the query provided. This uses BaseSpace Search and the scope for the search is set to runs, you can search on any metadata (via the Rest API) associated with that Run

    {
            "$type": "RunChooser",  
            "size": 250,  
            "label": "run",
            "required": true,
            "requiredMessage": "Please choose a run",
            "id": "run-id"  
    }
    

Preview:

RunChooser

App Result Chooser

Initializes an app result chooser so that the user can choose an app result as input.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • multiselect: A Boolean that, if true, allows multiple AppResults to be selected by the user within this Chooser. The default value is false.
  • searchQuery: Filters through the list of available AppResults based on the query provided. This uses BaseSpace Search and the scope for the search is set to appresults, you can search on any metadata (via the Rest API) associated with that AppResult as well

    {
        "$type": "AppResultChooser",
        "size": 250,
        "valueType": "Input",
        "multiselect": "true",
        "label": "App Result",
        "required": true,
        "requiredMessage": "Please choose an app result",
        "id": "app-result-id",
        "searchQuery": "property.{property_name}.{content_path}:{value} AND App.Id:210210"
    }
    

The above formbuilder code example would filter the AppResults in the user's account using the searchQuery value. In this case, the only AppResults that would be displayed would be those that had the following metadata attached (found via the API for that AppResult):

  • App Id for the AppResult (meaning the Id of the App that created this result) is 210210
  • The Property property.{property_name} on the AppResult must have a value of value

Preview:

AppResultChooser

File Chooser

Initializes a file chooser so that the user can choose a file as input. These files must exist in BaseSpace under the user's account. The files will be displayed under the Project that they belong to.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • extensionFilters: file extensions to filter on. The user will not be able to select any file extensions that were not specified. This can be a comma-separated list to filter by. Examples are .vcf, .fastq, .bam.
  • multiselect: A Boolean that, if true, allows multiple Files to be selected by the user within this Chooser. The default value is false.
  • searchQuery: Filters through the list of available Files based on the query provided. This uses BaseSpace Search and the scope for the search is set to files, you can search on any metadata (via the Rest API) associated with that File as well

    {
        "$type": "FileChooser",
        "size": 500,
        "valueType": "Input",
        "extensionFilters": ".bam", 
        "multiselect": true,
        "label": "File",
        "requiredMessage": "Please choose a file",
        "id": "file-id"
    }
    

Resource Matcher

Note: The Matcher control may be used only for Sample groups. Support for other group types will be added in a future release.

The Matcher control includes all the capabilities of the chooser (searching, filtering, and selecting data), plus the ability to group selections together. Example uses include trio analyses, in which the user must identify the matching mother, father, and child per sample; or dual strand applications, in which the user must select the positive- or negative- stranded samples. The Resource Matcher also supports AppResults.

The user may search or filter to discover their data, and then drag and drop the selected items into a matrix.

Sample Matcher

The Basics

The Matcher allows users to arrange samples or appresults onto a drag-and-drop matrix.

  • The columns of this matrix represent the sample/appresult groups. For example, applications might include requiring the user to add samples/appresults to "positive strand" or a "negative strand" group; a "father" group versus a "mother" group. Each group may be of a single resource type (sample, app result, file, project), defined by you, the developer. (As noted above, only sample and appresult groups are currently supported.)
  • Rows represent related samples and appresults that should be analyzed together.

As the developer, you may write custom validation rules to enforce certain rules in a given cell, row, or column; or for the control as a whole. For example, you may specify that any sample in column A must have equal read length to its corresponding sample in column B.

When the user selects items and submits them, a set of input properties will be created on your app session describing what selections were made in the Resource Matcher control, and in what order.

The Sample Matcher (Resource Matcher using Samples) produces one sample array property per column. If you had created a matcher control named "mymatcher", and inside it a "father" column and a "mother" column, the resulting properties will include an Input.mymatcher.father property and an Input.mymatcher.mother property; both of these properties will contain an array of sample items. (See the Properties API for more details.) Each item in the array appears in the same order as the matcher control. So the items added at row number 5 will be accessible at fatherSamples.Items[4] and at motherSamples.Items[4] (4 and not 5, because the arrays use zero-based indices; see A Note on Matcher Row Numbers, below). The Matcher Properties are discussed at length below.

Matcher: Properties

Given a Matcher with the id "mymatcher" and the sample groups "positive" and "negative", the Matcher will produce the following properties:

  • A property describing the column properties: Input.mymatcher.columns. This is a string array property that simply lists the names of the column properties created for the mymatcher control.
  • A string property that specifies the number of columns in the control: Input.mymatcher.num-columns. The value of this property is simply the number of columns.
  • A sample array property per column:
    • Input.mymatcher.positive
    • Input.mymatcher.negative

Example JSON for the sample array properties:

{
    Type: "sample[]",
    Href: "v1pre3/appsessions/123/properties/Input.mymatcher.positive",
    Name: "Input.mymatcher.positive",
    Description: "",
    Items: [{
        UserOwnedBy: { /* user info */ },
        Name: "NA123a",
        SampleId: "NA123a",
        Status: "Complete"
        /* sample details go here */
    },
    {
        UserOwnedBy: { /* user info */ },
        Name: "NA456a",
        SampleId: "NA456a",
        Status: "Complete"
        /* sample details go here */
    }]
},
{
    Type: "sample[]",
    Href: "v1pre3/appsessions/123/properties/Input.mymatcher.negative",
    Name: "Input.mymatcher.negative",
    Description: "",
    Items: [{
        UserOwnedBy: { /* user info */ },
        Name: "NA123b",
        SampleId: "NA123b",
        Status: "Complete"
        /* sample details go here */
    },
    {
        UserOwnedBy: { /* user info */ },
        Name: "NA456b",
        SampleId: "NA456b",
        Status: "Complete"
        /* sample details go here */
    }]
}

Matcher: Form Builder JSON

In addition to Common Field JSON Elements, this field also supports the following elements:

  • maxRows: The maximum number of rows of data that user will be allowed to enter into the selection matrix. Currently, this value may not exceed 100.
  • rules: An array of the names of ScriptValidationRules to apply for the entire control. (See Validation Rules details below.)
  • buttonText: Determines the label of the button that opens the Matcher Dialog.
  • columns: An array of column definitions. Each column will produce a corresponding property array. Each column definition contains the following fields:
    • id: Like the controls themselves, the id property will determine the name of the property array for the column. For example, a column named negative on a control named sample-pairs will produce a property named Input.sample-pairs.negative.
    • label: The text that will appear in the header row of the drag-and-drop matrix.
    • allowunpairedcells: Allows uneven pairing of items in the Resource Matcher. For instance, instead of always requiring the same amount of items to be selected in column 1 and column 2, this would instead allow the number of items in each column to mismatch. In some cases, an app may require this type of input functionality.
    • rules: An array of the names of ScriptValidationRules to apply for each item added to this column. (See Validation Rules details below.)
    • resourceType: The type of resource that may be added to this column. Currently, only "Sample" and "Appresult" are supported.
  • searchQuery: Filters through the list of the available resourceType based on the query provided. This uses BaseSpace Search and the scope for the search is set to the resource type that is selected, you can search on any metadata (via the Rest API) associated with that resource

Example usage:

{
    "$type": "ResourceMatcher",
    "required": false,
    "id": "sample-grouper-id",
    "maxRows": 100,
    "columns":[
        {
            "id": "fpa",
            "label": "Fpa Samples",
            "resourceType": "Sample",
            "rules": "sample-reader,hg19-only,is-paired-end,min-cycles-1,min-cycles-2,min-reads,max-size"
        },
        {
            "id": "fpb",
            "label": "Fpb Samples",
            "resourceType": "Sample",
            "rules": "sample-reader,hg19-only,is-paired-end,min-cycles-1,min-cycles-2,min-reads,max-size"
        }
    ],
    "rules": "script-pairwise-cycle-match"
}

Matcher: Validation Rules

Validation rules may be applied at the level of the entire control, taken as a whole; at the level of the individual group; or at the level of rows or cells.

It's up to you to decide how specific your error message should be.

All validation rules should return an array of matcher error objects, of the form:

{
    rowNumber: '0',
    columnId: 'positive',
    message: 'This is an error.'
}

All fields are optional except the message. Based on the row or column information, the UI will attempt to guide the user to the cell that produced the error message.

Note that the UI display value of the row number will be one higher than what you specify -- see A Note on Matcher Row Numbers.

The following example demonstrates a control-level validation rule, which enforces that a given row must have matching read lengths.

{
    "$type": "ScriptValidationRule",
    "id": "script-pairwise-cycle-match",
    "severity": "error",
    "callback":"var columns = dataProvider.GetCurrentControlProperty();
                var samples = [];
                for(var i = 0; i < columns.length; i++){
                    var columnSamples = dataProvider.GetProperty(columns[i]);
                    samples.push(columnSamples);
                }

                var errors = [];
                for(var i = 0; i < samples[0].length; i++){
                    var col1Sample = samples[0][i];
                    var col2Sample = samples[1][i];
                    var col2 = columns[1].substring(columns[1].lastIndexOf('.') + 1);
                    if(col1Sample.Read1 != col2Sample.Read1){
                        errors.push({
                            rowNumber: (i) + '',
                            resourceId: col2Sample.Id,
                            message: 'sample ' + col2Sample.SampleId + ' read1 cycles of '+ col2Sample.Read1 + ' do not match its pair sample ' + col1Sample.SampleId + ' read 1 cycles of ' + col1Sample.Read1
                        });
                    }
                    if(col1Sample.Read2 != col2Sample.Read2){
                        errors.push({
                            rowNumber: (i) + '',
                            resourceId: col2Sample.Id,
                            message: 'sample ' + col2Sample.SampleId + ' read2 cycles of '+ col2Sample.Read2 + ' do not match its pair sample ' + col1Sample.SampleId + ' read 2 cycles of ' + col1Sample.Read2
                        });
                    }
                }

                return errors;"
}

A Note on Matcher Row Numbers

Note that all array properties, including the properties produced by each Matcher group, use zero-based indices. In the BaseSpace UI, however, the Matcher itself lists row numbers starting from 1 instead of 0. Be aware that when you return a validation error and specify a row number, BaseSpace will automatically add a 1 to the display value of the row number.

Tabular Field Set

Allows a grouping of form fields together into a set that can be duplicated by the user on the input form. This input form field is geared towards apps that have some repetitive steps in the input form for different groupings of the data in the form.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • seriesHeader: The header label for the first column in the tabular field set
  • maxrows: Maximum amount of rows that the user is able to add, used to limit the user from selecting more rows of data than the app is built for
  • headers: The headers displayed in each column, this field is an array of string values. For example, for a TabularFieldSet where there is only one additional column and we want to name that column Groups, the headers field would be ["Groups"]. However, if there were two additional columns and we want to name the columns Groups and Sets respectively, the headers field would be ["Groups","Sets"]
  • fields: An array of fields that can be added to each row of the TabularFieldSet, anything added to this array will be duplicated on each row on the TabularFieldSet when the user clicks on the + icon

    {
      "$type": "TabularFieldSet",
      "id": "sample-experiments",
      "seriesHeader": "Groups",
      "maxrows": 2,
      "headers": [
        "Samples",
        "AppResults"
      ],
      "fields": [
        {
          "$type": "SampleChooser",
          "size": 300,
          "allowedPermissions": "read",
          "required": true,
          "requiredMessage": "Please choose a sample",
          "multiselect": true,
          "id": "control-samples",
          "rules": "",
          "displayFields": [
            {
              "$type": "Select",
              "id": "select-1",
              "label": "Library Type",
              "multiselect": false,
              "choices": [
                {
                  "value": 0,
                  "text": "paired-end",
                  "selected": true
                },
                {
                  "value": 1,
                  "text": "single",
                  "selected": false
                },
                {
                  "value": 2,
                  "text": "mate pair",
                  "selected": false
                },
                {
                  "value": 3,
                  "text": "nextera mate pair",
                  "selected": false
                }
              ]
            },
            {
              "$type": "Select",
              "id": "select-2",
              "label": "Library Orientation",
              "multiselect": false,
              "choices": [
                {
                  "value": 0,
                  "text": "forward-reverse",
                  "selected": true
                },
                {
                  "value": 1,
                  "text": "reverse-forward",
                  "selected": false
                },
                {
                  "value": 2,
                  "text": "forward-forward",
                  "selected": false
                },
                {
                  "value": 3,
                  "text": "reverse-reverse",
                  "selected": false
                }
              ]
            }
          ]
        },
        {
          "$type": "AppResultChooser",
          "size": 250,
          "valueType": "Input",
          "multiselect": "true",
          "required": true,
          "requiredMessage": "Please choose an app result",
          "id": "app-result-id"
        }
      ]
    }
    

The above code snippet will create a TabularFieldSet with a SampleChooser and an AppResult chooser on each row, and the number of rows is limited to 2 because of the maxrows attribute. The SampleChooser is also set up with a couple of dropdown menus that will pop up. Space is limited, when creating a form it is good to ensure that it dispays appropriately to the user.

Preview TabularFieldSet

Checkbox

Defines a set of choices of which multiple can be chosen by the user as Checkboxes.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • choices: an array of the choices that the user can select from that will be displayed as Checkboxes.

    • value: the value of the selected Checkbox. This value will be added to the AppSession's Property Items when the app is launched.
    • label: the label for the Checkbox that will be displayed for the user.
    • checked: a Boolean that checks this Checkbox by default. The default value is false.

      {
            "$type": "CheckBox", 
            "id" : "checkbox-1", 
            "label": "checkbox control",
            "choices": [
              {
                "value": 0,
                "label": "zero"
              },
              {
                "value": 50,
                "label": "fifty",
                "checked": true 
              }
          ]
      }
      

Preview:

CheckBox

Radio Button

Defines a set of choices of which only one can be chosen by the user as HTML radiobuttons.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • value: default value, whichever choice matches this value will be selected.
  • choices: an array of the choices that the user can select from that will be displayed as RadioButtons.

    • value: the value of the selected RadioButtons. This value will be added to the AppSession's Property Items when the app is launched.
    • label: the label for the RadioButtons that will be displayed for the user.

      {
            "$type": "RadioButton", 
            "id": "random-radio", 
            "label": "Stranded?",
            "value": 1, 
            "choices": [
              {
                "value": 0,
                "label": "No"
              },
              {
                "value": 1,
                "label": "Yes"
              }
          ]
      }
      

Preview:

RadioButton

Select (Drop down list)

Define a list of selections that either on or more can be chosen by the user. This will display as a drop down list of values for the user to select from.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • multiselect: A Boolean that, if true, allows multiple items to be selected in this list by the user. The default value is false.
  • choices: an array of the choices that the user can select from that will be displayed as items in a drop-down list.

    • valuethe value of the selected list item. This value will be added to the AppSession's Property Items when the app is launched.
    • text: the label for the list item that will be displayed for the user.
    • selected: a Boolean that selects this list item by default. The default value is false.

      {
            "$type": "Select", 
            "id" : "select-1", 
            "label": "select control",
            "multiselect": false, 
            "choices": [
              {
                "$type": "SelectListItem",
                "value": 0,
                "text": "zero",
                "selected": false
              },
              {
                "$type": "SelectListItem",
                "value": 50,
                "text": "fifty",
                "selected": true
              }
          ]
      }
      

Preview:

DropdownList

Numeric Field

A Textbox field that allows only numeric input.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • min: The minimum value that the user will be allowed to input into this field
  • max: The maximum value that the user will be allowed to input into this field
  • numericType: Specifies whether the value will be a Floating Point or an Integer. Accepted values are: Integer and FloatingPoint. The default value is Integer.
  • value: The default value for this field.

    {
      "$type": "Numeric",
      "id": "circles",
      "size": 50, 
      "required": false,
      "label": "Location in Circles",
      "min": -6.28, 
      "max": 6.28,
      "value": 0,
      "numericType": "FloatingPoint", 
      "rules": "is-it-a-pi"
    } 
    

Preview:

NumericField

Section Break

Make a visible break in the form to mark the end of a section

  • title: the title of the Section, this is a header displayed to the user
  • description: the description of the section

    {
       "$type": "SectionBreak",
        "id": "section-break-1"
    }
    

Preview:

SectionBreak

Field Set

Method of grouping a set of controls, rules can then be applied to the entire Field Set or an entire Field Set could be a collapsible area in the form.

In addition to Common Field JSON Elements, this field also supports the following elements:

  • fields: an array of fields that are grouped together in this Field Set.
  • isCollapsible: A Boolean that, if true, can make this entire Field Set a Collapsible field on the form. The default value is false.
  • isOpen: If it is collapsible, then this Boolean value will determine whether the field set is Open by default or Closed. If true, the collapsible portion will be Open. The default value is false.
  • rules: Rules that are applied to the entire field set.

    {
        "$type": "FieldSet",
        "id": "address",
        "label": "Billing Address",
        "isCollapsible": true, 
        "isOpen": true, 
        "helpText": "Some useful paragraph on what this field set is about.",
        "fields": [
        {
            "$type": "TextBox",  
            "size": 300, 
            "value": "",
            "label": "Name",
            "required": true,
            "requiredMessage": "Please enter name for your app session.",
            "id": "name" 
        },
        {
            "$type": "TextBox",  
            "size": 300, 
            "value": "",
            "label": "Street",
            "required": true,
            "requiredMessage": "Please enter name for your app session.",
            "id": "street" 
        },
        {
            "$type": "Select", 
            "id" : "state", 
            "label": "State",
            "choices": [
                {
                  "$type": "SelectListItem",
                  "value": "CA",
                  "text": "California",
                  "selected": true
                },
                {
                  "$type": "SelectListItem",
                  "value": "Other",
                  "text": "Other State"
                }
            ]
        }
        ]
    }
    

Preview:

FieldSet

Display Fields

For choosers, you can optionally specify display fields which can be a set of checkboxes, radiobuttons and selects

  • displayFields: An array of fields that can be added per resource selected in a Chooser. Checkboxes, Radiobuttons, Numerics, and Selects are all acceptable items.

The following is an example of a SampleChooser field with Checkboxes, Radiobuttons, and Selects. When the user selects a Sample, these fields will pop up next to the Sample so that the user can specify more information per selection. If multiple Samples were selected, these fields would be duplicated per Sample.

{
    "$type": "SampleChooser",
    "size": 550,
    "valueType": "Input",
    "multiselect": true,
    "allowedPermissions": "read",
    "label": "Sample",
    "required": true,
    "requiredMessage": "Please choose a sample",
    "helpText": "This is help text.",
    "id": "samples-displayFields",
    "displayFields":[
        {
            "$type": "CheckBox",
            "id": "is-sample-awesome",
            "label": "Awesome?",
            "choices":[{
                "label": "Y",
                "value": 1
            },{
                "label": "Y+",
                "value": 2
            }
            ]
        },
        {
            "$type": "RadioButton",
            "id": "is-sample-wicked",
            "label": "Wicked?",
            "choices":[{
                "label": "Y",
                "value": 1
            },{
                "label": "N",
                "value": 0
            },{
                "label": "M",
                "value": 2
            }]
        },
        {
            "$type": "Select",
            "id": "is-sample-extraordinary",
            "label": "Extraordinary?",
            "multiselect": "true",
            "size": 3,
            "choices": [
                {
                    "text": "Oh, Yes!", "value": 1
                },
                {
                    "text": "Oh, No!", "value": 0
                },
                {
                    "text": "Close Contender", "value": 0.5
                }
            ]
        }
    ]
}

Togglers

For checkboxes, radiobuttons and selects, you can optionally specify togglers which allow you to enable or disable other controls under certain conditions.

A Toggler requires a value to be selected when the choices property is available on a field. When the value is selected, the fields specified in toggleFields are then toggled to enabled.

  • toggleOnValue: when this value is selected all toggleFields will get enabled. If this is a comma-separated list, then toggleFields will get enabled if any of the selected values is in the list. Use null to enable toggleFields when no selection is made.
  • toggleFields: id of the field or fields to toggle enabled/disabled. This can be a comma-separated list.

    {
        "$type": "CheckBox",
        "id": "requires-a-state",
        "label": "Requires Name and State?",
        "choices": [
            {
                "value": 1
            }
        ],
        "togglers": [
            {
                "toggleOnValue": 1, 
                "toggleFields": "name,state" 
            }    
        ]
    },
    {
        "$type": "Select", 
        "id" : "requires-a-street", 
        "label": "Requires Street?",
        "choices": [
            {
              "$type": "SelectListItem",
              "value": "1",
              "text": "Yes"
            },
            {
              "$type": "SelectListItem",
              "value": "0",
              "text": "No"
            }
        ],
        "togglers":[
            {
                "toggleOnValue": 1,
                "toggleFields": "street"
            }   
        ]
    }
    

Advanced Toggling

When enabling/disabling of fields requires more complex logic (e.g. toggling based on values of multiple fields or toggling Tabular Field Set fields) you can add the formUpdates JavaScript function to callback.js to achieve the desired behavior. Using formUpdates callback also allows toggling based on values of fields other than checkboxes, radiobuttons, and selects.

The following example demonstrate how you can enable/disable fields in all rows of a Tabular Field Set based on the selection in a checkbox.

{
    "$type": "Form",
    "fields": [
        {
            "$type": "CheckBox",
            "id": "disable-tabular-field-set",
            "label": "Disable Experiments",
                "choices": [
                    {
                        "value": 1
                    }
                ]
        },
        {
            "$type": "TabularFieldSet",
            "id": "sample-experiments",
            "seriesHeader": "Experiments",
            "headers": [
                "Control Samples",
                "Comparison Samples",
                "Diff. Expression?"
            ],
            "fields": [
                {
                    "$type": "SampleChooser",
                    "size": 150,
                    "allowedPermissions": "read",
                    "required": true,
                    "requiredMessage": "Please choose a sample",
                    "multiselect": true,
                    "id": "control-samples",
                    "rules": "is-paired-end,is-sample-reader,is-sample-empty"
                },
                {
                    "$type": "SampleChooser",
                    "size": 150,
                    "allowedPermissions": "read",
                    "required": true,
                    "requiredMessage": "Please choose a sample",
                    "multiselect": true,
                    "id": "comparison-samples",
                    "rules": "is-paired-end,is-sample-reader,is-sample-empty"
                },
                {
                    "$type": "CheckBox",
                    "id": "differential-expression",
                    "choices": [
                        {
                            "value": 1
                        }
                    ]
                }
            ]
        }
    ]
}

For this form, add the following function to callback.js

function formUpdates(dataProvider)
{
    var disable = ('' + dataProvider.GetProperty("input.disable-tabular-field-set")) === "1";
    var rowCount = dataProvider.GetProperty("input.sample-experiments.rowcount");
    for(var i = 1; i <= rowCount; i++){
        if (disable) {
            dataProvider.AttributeUpdates.Add({ ElementId: "sample-experiments.control-samples.row" + i, AttributeName: "disabled", AttributeValue: "disabled" });
            dataProvider.AttributeUpdates.Add({ ElementId: "sample-experiments.comparison-samples.row" + i, AttributeName: "disabled", AttributeValue: "disabled" });
            dataProvider.AttributeUpdates.Add({ ElementId: "sample-experiments.differential-expression.row" + i, AttributeName: "disabled", AttributeValue: "disabled" });          
        } else {
            dataProvider.AttributeUpdates.Remove({ ElementId: "sample-experiments.control-samples.row" + i, AttributeName: "disabled" });
            dataProvider.AttributeUpdates.Remove({ ElementId: "sample-experiments.comparison-samples.row" + i, AttributeName: "disabled" });
            dataProvider.AttributeUpdates.Remove({ ElementId: "sample-experiments.differential-expression.row" + i, AttributeName: "disabled" });
        }

    }
}

In the above example, we are changing the values of certain fields in the input form depending on the toggle. ElementId is the Id of the input form field (in this case its a path from sample-experiments to control-samples,comparison-samples, or differential-expression. AttributeName and AttributeValue are values that relate to the actual HTML elements that are created in the form. You can view the AttributeName by looking at the source in your browser to find the name of the attribute on the field that you want to toggle.

The above example will enable all of the fields or disable all of the fields in the TabularFieldSet depending on the toggler.

Rulesets

Rulesets are optional and can be applied to any field and even the form itself. To use rulesets, you will need to define some rulesets in the rules array of the form, then choose which rulesets apply to each field in the form.

All rules require a $type, id, and a message to be shown to the user.

When does the validation occur?

Common Ruleset JSON Elements

For each ruleset element, there are a few JSON properties that exist commonly. Here is a list of common JSON elements in the rulesets with descriptions of each:

  • $type: Specifies the type of ruleset that will follow. This is a required field.
  • severity: The severity of the validation issue. Accepted values: Warning or Error. If Error, the form will display the message as red, and the user cannot complete the form and launch the app until fixing the error. If Warning, the form will display the message as yellow, and the user can choose to ignore it and proceed with the app.
  • id: The Id of the Ruleset, this is applied to each field that this validation will be performed on. Id is required.
  • message: The validation message that will be displayed to the user when the validation fails.

Value

General validation of a fields value

In addition to Common Ruleset JSON Elements, this field also supports the following elements:

  • "relation": The relation of the value the user selected with the value in the ValueValidationRule. Allowed values: Equals, LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo, Contains, NotContains, and NotEqual.
  • "value": The value that the comparison operator will be comparing the user's input value with. This can be a numeric (Double) or a string.

In the following example, we have a "TextBox" field and we are applying the "ValueValidationRule" which checks to see if the value in the TextBox equals 3.14159265359.

{
    "$type": "Form",
    "fields": [
        {
            "$type": "TextBox",  
            "size": 300, 
            "label": "Enter a Number",
            "required": true,
            "requiredMessage": "Please enter a number.", 
            "id": "enter-number", 
            "helpText": "this help text will display next to the control in a pop over",
            "rules": "is-it-pi" 
        }
    ],
    "rulesets": [
        {
            "$type": "ValueValidationRule",
            "relation": "Equals", 
            "value": 3.14159265359, 
            "message": "That is not pi", 
            "severity": "Warning", 
            "id": "is-it-pi" 
        }
    ],
    "id": "form-container"
}

Permission

Tests the user's access permissions to a basespace resource.

In addition to Common Ruleset JSON Elements, this field also supports the following elements:

  • "permissions": The permission that the user needs on the resource or file in order to be acceptable for this field. Allowed values: Browse, Read, Write, Own, Create.

    {
        "$type": "Form",
        "fields": [
            {
                "$type": "SampleChooser",  
                "size": 300, 
                "allowedPermissions": "read", 
                "label": "Input Sample",
                "required": true,
                "requiredMessage": "Please choose a sample",
                "id": "samples",
                "rules": "sample-reader"
            }
        ],
        "rulesets": [
            {
                "$type": "PermissionValidationRule",
                "permissions": "Read", /* Browse, Read, Write, Own, Create */
                "severity": "Error",
                "message": "You do not have read access to the selected sample",
                "id": "sample-reader"
            }
        ],
        "id": "form-container"
    }
    

Open Ended Script Validation

Allows the developer to run custom javascript validation for any form elements. This Ruleset may be applied to the entire form or to a field. If it is on the field, the validation error message will be displayed next to the field.

In addition to Common Ruleset JSON Elements, this field also supports the following elements:

  • "callback": This is an open-ended javascript function that can be used to perform validation on any fields in the form. The callback will generally use the dataProvider.GetProperty() method to obtain data selected in the form.

What to return

The callback javascript needs to have a return statement. In general, you can return a string or value to the user whenever validation does not pass, this message is then displayed to the user upon failure. Return null if the validation is passed.

dataProvider.GetProperty()

In order to do more complex form validation, it is mandatory to be able to access the values selected by the user in the form via a method in the Form builder tool. Fortunately, this functionality is available via the dataProvider's GetProperty() method.

The GetProperty() method takes a Property name as input. When an app is launched and the form is submitted, the values selected in the form are saved to the AppSession that is created for this analysis (for native apps, this is the appsession.json file that is saved to the input directory.) For more information about how form values are saved as Properties on an AppSession, please refer to the How to Obtain Data Selected in the Form section above.

How to Use the dataProvider.GetProperty() Method

dataProvider.GetProperty() takes a Property name as input. When the form is submitted, formbuilder will automatically append input. or output. to the id of your form field and save that as the Property name in the Property Items on the AppSession that is created. In general, Properties will have input. appended but if an Output Project or AppResult is selected by the user then it is appended by output. instead. For example, if the Id of the SampleChooser field in a form was sample-1, the following can be used to get the Sample that was selected by the user:

dataprovider.GetProperty("Input.sample-1")

If the Property Type for the Property is a BaseSpace resource (e.g. it is a run, project, appresult, or sample, or an array of those), the value returned will be the full BaseSpace resource or an array of full BaseSpace resources. In addition, if the id of the field in the form is app-session-id, the entire AppSession will be returned via this method.

Since the entire resource is returned, you may want to find specific information about the selected resource. For example, if we use dataProvider.GetProperty("Input.sample-1"), the Property on the AppSession (if the Sample's Id was 888888) will be the following:

{
    "Type": "sample[]",
    "Href": "v1pre3/appsessions/2695119/properties/Input.Samples",
    "Name": "Input.Samples",
    "Description": "",
    "Items": [
      {
        "Id": "888888",
        "Href": "v1pre3/samples/888888",
        "UserOwnedBy": {
          "Id": "3003",
          "Href": "v1pre3/users/3003",
          "Name": "Illumina Inc",
          "GravatarUrl": "https://secure.gravatar.com/avatar/702e4f8795f80bd0929a8b818bb19f65.jpg?s=20&d=https%3a%2f%2fbasespace.illumina.com%2fpublic%2fimages%2fDefaultCustomerGravatar.png&r=PG"
        },
        "Name": "HBr1",
        "SampleId": "HBr1",
        "Status": "Complete",
        "StatusSummary": "",
        "DateCreated": "2013-10-16T17:19:56.0000000",
        "TotalSize": 0,
        "Genome": {
          "Id": "4",
          "DisplayName": "Homo Sapiens - UCSC (hg19)",
          "SpeciesName": "Homo sapiens",
          "Source": "UCSC",
          "Build": "hg19",
          "Href": "v1pre3/genomes/4",
          "HrefFileSets": "v1pre3/genomes/4/filesets",
          "HrefAnnotations": "v1pre3/genomes/4/annotations"
        },
        "Read1": 51,
        "Read2": 51
      }
    ],
    "HrefItems": "v1pre3/appsessions/2695119/properties/Input.Samples/items",
    "ItemsDisplayedCount": 1,
    "ItemsTotalCount": 1
}

Now, any information from this response can be accessed by the form. If we want to return Read1 for the above Sample, we can use simple dot operators in the following way:

dataProvider.GetProperty("Input.sample-id").Read1

This will return 51 since that is the value for Read1 in the above response.

All of the information included in each full BaseSpace resource is described in the Rest API Reference.

If the Property Type is not any of the above and the id of the field is not app-session-id, the above method would instead return the value that the is in the form (either set by the user or by the form by default.)

For example, if the Type was a Textbox with id textbox-1 and the user input was hello, then dataProvider.GetProperty("Input.textbox-1") will return the value hello as a String.

An example of a Sample Chooser with "multiselect":"true" with a custom ScriptValidationRule that checks to see if the user selected a Sample that is PairedEnd or not:

    {
        "$type": "Form",
        "fields": [
            {
                "$type": "SampleChooser",  
                "size": 300, 
                "allowedPermissions": "read", 
                "label": "Input Sample",
                "required": true,
                "multiselect": true,
                "requiredMessage": "Please choose a sample",
                "id": "samples",
                "rules":"is-paired-end"
            }
        ],
        "rulesets": [
        {
                "$type": "ScriptValidationRule",
                "callback": "
                var samples = dataProvider.GetProperty(\"Input.samples\");
                for(var i = 0; i < samples.length; i++)
                {
                    var sample = samples[i];

                    if(!sample.IsPairedEnd)
                    {
                        return {Message:'This Sample is not Paired-End'};
                    }
                    if(sample.TotalClustersRaw>3000000) {
                        return {Message:'Coverage to high. This app is designed for <100X bacterial data.'};
                    }
                }
                return null;",
                "id": "is-paired-end"
        },

        ],
        "id": "form-container"
    }

Sample Validation Rules

The following rules are specific to samples, these are applied to any SampleChooser field:

Empty

Validate that the sample(s) selected in the SampleChooser field is not empty

{
    "$type": "Form",
    "fields": [
        {
            "$type": "SampleChooser",  
            "size": 300, 
            "allowedPermissions": "read", 
            "label": "Input Sample",
            "required": true,
            "requiredMessage": "Please choose a sample",
            "id": "samples",
            "rules": "sample-is-not-empty"
        }
    ],
    "rulesets": [
        {
            "$type": "EmptySampleValidationRule",
            "message": "The sample cannot be empty",
            "id": "sample-is-not-empty"
        }
    ],
    "id": "form-container"
}

Genome

Validate that the selected Sample is tagged with the specified Genome reference.

In addition to Common Ruleset JSON Elements, this field also supports the following elements:

  • value: The value of the Genome that is supported by the app. Possible values:
    • Arabidopsis_thaliana
    • Bos_taurus
    • Escherichia_coli_K_12_DH10B
    • Homo_sapiens
    • Mus_musculus
    • PhiX
    • Rhodobacter_sphaeroides_2.4.1
    • Rattus_norvegicus
    • Saccharomyces_cerevisiae
    • Staphylococcus_aureus_NCTC_8325
    • BacillusCereus

For example, to display a Warning in the app when a Sample with a non-Homo_Sapiens genome is selected:

{
    "$type": "Form",
    "fields": [
        {
            "$type": "SampleChooser",  
            "size": 300, 
            "allowedPermissions": "read", 
            "label": "Input Sample",
            "required": true,
            "requiredMessage": "Please choose a sample",
            "id": "samples",
            "rules": "hg19-only"
        }
    ],
    "rulesets": [
{
            "$type": "GenomeSampleValidationRule",
            "message": "This app currently only supports Samples with the Human Genome (hg19).",
            "value": "Homo_sapiens",
            "severity": "Warning",
            "id": "hg19-only"
        }
    ],
    "id": "form-container"
}

Max Size

Validate sample size

In addition to Common Ruleset JSON Elements, this field also supports the following elements:

  • relation: The relation of the value the user selected with the value in the ValueValidationRule. Allowed values: Equals, LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo, Contains, NotContains, and NotEqual.
  • value: The value that the comparison operator will be comparing the user's input value with. This can be a numeric (Double) or a string.

    {
        "$type": "Form",
        "fields": [
            {
                "$type": "SampleChooser",  
                "size": 300, 
                "allowedPermissions": "read", 
                "label": "Input Sample",
                "required": true,
                "requiredMessage": "Please choose a sample",
                "id": "samples",
                "rules": "sample-size-maximum"
            }
        ],
        "rulesets": [
            {
                "$type": "MaxSizeSampleValidationRule",
                "message": "This app currently only supports samples with less than 200 gigabases.",
                "relation": "LessThan",
                "value": 200000000000,
                "severity": "Warning",
                "id": "sample-size-maximum"
            }
        ],
        "id": "form-container"
    }
    

Min Cycles Read 1

Validate cycles for read 1 of the sample

In addition to Common Ruleset JSON Elements, this field also supports the following elements:

  • relation: The relation of the value the user selected with the value in the ValueValidationRule. Allowed values: Equals, LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo, Contains, NotContains, and NotEqual.
  • value: The value that the comparison operator will be comparing the user's input value with. This can be a numeric (Double) or a string.

    {
        "$type": "Form",
        "fields": [
            {
                "$type": "SampleChooser",  
                "size": 300, 
                "allowedPermissions": "read", 
                "label": "Input Sample",
                "required": true,
                "requiredMessage": "Please choose a sample",
                "id": "samples",
                "rules": "min-cycles-1"
            }
        ],
        "rulesets": [
            {
                "$type": "MinCycles1SampleValidationRule",
                "message": "This app currently only supports a minimum read-length of 32 base pairs.",
                "relation": "GreaterThan",
                "value": 32,
                "severity": "Error",
                "id": "min-cycles-1"
            }
        ],
        "id": "form-container"
    }
    

Min Cycles Read 2

Validate cycles for read 2 of the sample

In addition to Common Ruleset JSON Elements, this field also supports the following elements:

  • relation: The relation of the value the user selected with the value in the ValueValidationRule. Allowed values: Equals, LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo, Contains, NotContains, and NotEqual.
  • value: The value that the comparison operator will be comparing the user's input value with. This can be a numeric (Double) or a string.

    {
        "$type": "Form",
        "fields": [
            {
                "$type": "SampleChooser",  
                "size": 300, 
                "allowedPermissions": "read", 
                "label": "Input Sample",
                "required": true,
                "requiredMessage": "Please choose a sample",
                "id": "samples",
                "rules": "min-cycles-2"
            }
        ],
        "rulesets": [
            {
                "$type": "MinCycles2SampleValidationRule",
                "message": "This app currently only supports a minimum read-length of 32 base pairs.",
                "relation": "GreaterThan",
                "value": 32,
                "severity": "Error",
                "id": "min-cycles-2"
            }
        ],
        "id": "form-container"
    }
    

Min Reads

Validate minimum reads a sample must have

In addition to Common Ruleset JSON Elements, this field also supports the following elements:

  • relation: The relation of the value the user selected with the value in the ValueValidationRule. Allowed values: Equals, LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo, Contains, NotContains, and NotEqual.
  • value: The value that the comparison operator will be comparing the user's input value with. This can be a numeric (Double) or a string.

    {
        "$type": "Form",
        "fields": [
            {
                "$type": "SampleChooser",  
                "size": 300, 
                "allowedPermissions": "read", 
                "label": "Input Sample",
                "required": true,
                "requiredMessage": "Please choose a sample",
                "id": "samples",
                "rules": "minimum-sample-reads"
            }
        ],
        "rulesets": [
            {
                "$type": "MinReadsSampleValidationRule",
                "explanation": "This app normally only supports samples with a minimum of 100,000,000 reads. This sample contains  reads.",
                "message": "Insufficient number of reads.",
                "relation": "GreaterThanOrEqualTo",
                "value": 100000000,
                "severity": "Warning",
                "id": "minimum-sample-reads"
            }
        ],
        "id": "form-container"
    }
    

Paired End

Validate whether the sample is paired end or not

In addition to Common Ruleset JSON Elements, this field also supports the following elements:

  • relation: The relation of the value the user selected with the value in the ValueValidationRule. Allowed values: Equals, LessThan, GreaterThan, LessThanOrEqualTo, GreaterThanOrEqualTo, Contains, NotContains, and NotEqual.
  • value: The value that the comparison operator will be comparing the user's input value with. This can be a numeric (Double) or a string.

    {
        "$type": "Form",
        "fields": [
            {
                "$type": "SampleChooser",  
                "size": 300, 
                "allowedPermissions": "read", 
                "label": "Input Sample",
                "required": true,
                "requiredMessage": "Please choose a sample",
                "id": "samples",
                "rules": "is-paired-end"
            }
        ],
        "rulesets": [
            {
                "$type": "PairedEndSampleValidationRule",
                "message": "This app currently only supports paired-end reads.",
                "relation": "Equals",
                "value": true,
                "severity": "Error",
                "id": "is-paired-end"
            }
        ],
        "id": "form-container"
    }
    

Popular Rulesets

Here is a list of popular rulesets, including a custom ruleset below:

"rulesets": [
    {
        "$type": "PermissionValidationRule",
        "permissions": "Own",
        "severity": "Error",
        "message": "Youmustbeanownertocreateappresultsintheselectedproject",
        "id": "is-project-owner"
    },
    {
        "$type": "GenomeSampleValidationRule",
        "message": "ThisappcurrentlyonlysupportsalignmenttotheHumanGenome(hg19).",
        "relation": "Equals",
        "value": "Homo_sapiens",
        "severity": "Warning",
        "id": "hg19-only"
    },
    {
        "$type": "PairedEndSampleValidationRule",
        "message": "Thisappcurrentlyonlysupportspaired-endreads.",
        "relation": "Equals",
        "value": true,
        "severity": "Error",
        "id": "is-paired-end"
    },
    {
        "$type": "MinCycles1SampleValidationRule",
        "message": "Thisappcurrentlyonlysupportsaminimumread-lengthof32basepairs.",
        "relation": "GreaterThan",
        "value": 32,
        "severity": "Error",
        "id": "min-cycles-1"
    },
    {
        "$type": "MinCycles2SampleValidationRule",
        "message": "Thisappcurrentlyonlysupportsaminimumread-lengthof32basepairs.",
        "relation": "GreaterThan",
        "value": 32,
        "severity": "Error",
        "id": "min-cycles-2"
    },
    {
        "$type": "PermissionValidationRule",
        "permissions": "Read",
        "severity": "Error",
        "message": "Youdonothavereadaccesstotheselectedsample",
        "id": "is-sample-reader"
    },
    {
        "$type": "EmptySampleValidationRule",
        "message": "Insufficientnumberofreads.",
        "relation": "GreaterThan",
        "value": 0,
        "severity": "Error",
        "id": "sample-is-not-empty"
    },
    {
        "$type": "MaxSizeSampleValidationRule",
        "message": "Thisappcurrentlyonlysupportssampleswithlessthan220gigabases.",
        "relation": "LessThan",
        "value": 220000000000,
        "severity": "Warning",
        "id": "normal-sample-size-maximum"
    },
    {
        "$type": "MaxSizeSampleValidationRule",
        "message": "Thisappcurrentlyonlysupportssampleswithlessthan390gigabases.",
        "relation": "LessThan",
        "value": 390000000000,
        "severity": "Warning",
        "id": "tumor-sample-size-maximum"
    },
    {
        "$type": "MinReadsSampleValidationRule",
        "message": "Insufficientnumberofreads.",
        "relation": "GreaterThanOrEqualTo",
        "value": 100000000,
        "severity": "Warning",
        "id": "minimum-sample-reads"
    },
    {
        "$type": "ApplicationPaymentValidationRule",
        "maxFreeAllowed": 5,
        "severity": "Error",
        "message": "Thisapponlysupports5freeruns",
        "id": "max-free-analyses"
    },
    {
        "$type": "ScriptValidationRule",
        "callback": "
    var inputs = dataProvider.GetInputs(currentControl);
        var samples = new Array();
        if (inputs.Length > 0) {
            var sample;
            for (var i=0; i < inputs.Length; i++) {
                sample = inputs[i].ContentSample;
                if (sample) 
                {
                    samples.push(sample);
                }
            }

            if (samples.length < 2)
            {
                return { Message: 'Please specify a tumor and a normal sample. Both a tumor and a normal sample need to be specified.' };
            }
            else
            {
                if (samples[0].Id != samples[1].Id)
                {
                    return null;
                }
                else
                {
                    return { Message: 'The tumor and the normal sample specified must be different. Both tumor and normal samples specified are the same.'};
                }
            }
        }
        return null;",
        "id": "tumor-normal-custom"
    }
]

Callbacks Script

The callbacks.js script can be edited by opening a form, clicking on the dropdown next to Current Template, and selecting callbacks.js. The callbacks.js script is used to connect the input form information with the app and to build a real-time shopping cart for billing.

Within the Callbacks Script, the following javascript functions can be configured:

  • launchSpec(): The launchSpec function is configured for Native Apps in order to specify the run parameters for the application before it is launched. The launchSpec function will specify which docker image to use and which command to send to the docker image in order to run the analysis. In addition, the launchSpec function can be used to pass custom properties, run on one or multiple nodes, and pass other parameters into the application.
  • billingSpec(): The billingSpec function can be configured for any apps using the Formbuilder tool in order to bill directly on the input form. The billingSpec function allows the app to build a real-time shopping cart on the same screen where users are configuring the app's input form.
  • formUpdates(): The formUpdates function allows the app to add/remove field attributes following any changes to form elements.

launchSpec function

Native apps can be run on one Node or the process can be optimized to be run on multiple Nodes. The documentation will go through both scenarios. This requires a change to the launchSpec.

Single-Node Template:

function launchSpec(dataProvider)
{
    return 
        {
            commandLine: ["/helloWorld.sh"],
            containerImageId:"tliu1/helloworld"
        };
}

This is a Single-Node analysis template, which means that the app will run on one node and that node will have all of the input data.

In the above example, we see the following actions in the callbacks.js script:

  • return : This is the return statement that will be sent to the machine that is running the app.
  • commandLine: Designates that the following commands will be entered into the command-line of your Docker container to start your application
    • ["/helloworld.sh"] : This will generate the following command-line argument /helloworld.sh which means to run the /helloworld.sh Shell script located in the root folder. If it is in another path, the path should be specified in this command.
  • containerImageId: The Docker container in the Docker registry for this application
    • "tliu1/helloworld": This is the Docker container in the Docker registry. tliu1 is the username and helloworld is the name of the Docker image. This container is where the above command-line script will be entered.

In addition to the above, the Callbacks.js script can also be used to specify running an analysis across multiple nodes.

Single-Node Analysis Using Multi-Node Template:

When a Multi-Node Template app is started, one parent AppSession is create for the aggregation of each node, and one child AppSession is created per node of the analysis. The parent AppSession will contain all of the input Properties from the form, however the child node's AppSession needs to be explicitly assigned Properties from the Callbacks.js script otherwise it will have no Properties.

function launchSpec(dataProvider)
{
    var retval = { nodes: [] };

    var samples = dataProvider.GetProperty("Input.samples");

    retval.nodes.push({
          commandLine: ["/helloworld.sh"],
          containerImageId:"tliu1/helloworld”,
                  properties: {
                                “Input.Samples”: [samples[0]] 
                  }
    });

    return retval;
} 
  • var samples = dataProvider.GetProperty("Input.samples"); : This command is setting the variable samples as the Id of the Property Input.samples that was set for a field in the form for this app. If multiple Samples are selected as input, this variable will be an array of Sample Ids.
  • return : This is the return statement that will be sent to the machine that is running the app.
  • commandLine: Designates that the following commands will be entered into the command-line of your Docker container to start your application
    • ["/helloworld.sh"] : This will generate the following command-line argument /helloworld.sh which means to run the /helloworld.sh Shell script located in the root folder. If it is in another path, the path should be specified in this command.
  • containerImageId: The Docker container in the Docker registry for this application
    • "tliu1/helloworld": This is the Docker container in the Docker registry. tliu1 is the username and helloworld is the name of the Docker image. This container is where the above command-line script will be entered.

Multi-Node Analysis Using Multi-Node Template:

When a Multi-Node Template app is started, one parent AppSession is create for the aggregation of each node, and one child AppSession is created per node of the analysis. The parent AppSession will contain all of the input Properties from the form, however the child node's AppSession needs to be explicitly assigned Properties from the Callbacks.js script otherwise it will have no Properties.

function launchSpec(dataProvider)
{
    var retval = { nodes: [] };

    var samples = dataProvider.GetProperty("Input.samples");
    var project = dataProvider.GetProperty("Input.project-id");

    for(var i = 0; i < samples.length; i++)
    {
        retval.nodes.push({
              commandLine: ["/helloworld.sh"],
              containerImageId:"tliu1/helloworld",
          properties: {
            “Input.Samples”: [ samples[i] ],
            "Input.project-id": project
          }
        });
    }

    return retval;
}

In the above callbacks.js script, the samples variable is an array of multiple Samples. This array is iterated through in the following for loop and each Node gets a new Sample from the samples[i] value.

Here, the app manually passes in properties to the appsession for each node for analysis. The current limit for the number of properties that can be set manually for each node is 100.

For multi-node apps, the information from the input form will have to be passed from the callback.js to the node via the Properties. In order to download/mount the input data successfully, the Input.Samples, Input.AppResults, and Input.Files Properties must be passed. All of these Properties are arrays and should be passed to each node as an array even if it is an array with one value. The specified data is downloaded to each node. In most cases, apps will have a multiselect Chooser on the input form and will pass each item on the Chooser to a different node. All of these Properties will be stored in the standard AppSession.json file.

In the future, the callbacks.js script will also be used to specify compute requirements for your application.

billingSpec function

The billingSpec function is configured in much the same way as the launchSpec function for Native Apps. The billingSpec is a javascript function that will create the Shopping Cart for the user after they launch the app and configure the input form with data. The billingSpec function is configured within the callbacks.js script in the Formbuilder window.

The return value for the billingSpec should be the ShoppingCart. The billingSpec incrementally builds the ShoppingCart by pushing Product Id and Product Quantity to the ShoppingCart object. In this way, the app can be configured with a billingSpec that changes the Quantities of the Products based on the selection(s) the user makes in the input form.

For example, if the app is configured with three Non-Persistent Products with the following characteristics:

Product 1
    - Name: Product 1 Name
    - Id: 123
    - Rate: 1 iCredit(s)

Product 2
    - Name: Product 2 Name
    - Id: 456
    - Rate: 2 iCredit(s)

Product 3
    - Name: Compute Product Name
    - Id: 789
    - Rate: 1 iCredit(s)

The billingSpec would be the following:

function billingSpec(dataProvider)
{

    var Product1Quantity = 0;  
    var Product2Quantity = 0;
    var ComputeQuantity = 0;
    var Samples = dataProvider.GetProperty("Input.sample-id"); 

    for (var x = 0; x < Samples.length; ctr++)
    {
        // functions that calculate the Product1Quantity, Product2Quantity, and ComputeQuantity.  
    }

    ShoppingCart.push({ "Id": "123", "Quantity": Product1Quantity });  
    ShoppingCart.push({ "Id": "456", "Quantity": Product2Quantity });      
    ShoppingCart.push({"Id": "789", "Quantity": (Math.round(ComputeQuantity * 100) / 100)});

    return ShoppingCart;
}

Here the values Product1Quantity, Product2Quantity, and ComputeQuantity are first set to 0.

Next, the Samples variable is assigned to the values the user selected on the input form field with the Id sample-id which is a SampleChooser in this case. So, Samples will be an array of Samples selected in the input form. More information about using the GetProperty() function is available in the Formbuilder Documentation.

Then, as the user selects certain values on the input form, the billingSpec will simply increment the Quantity of the Products using any functions configured within the billingSpec function.

formUpdates function

The formUpdates function is called after every change to the input form. By implementing this function the app can add or remove attributes from form elements using dataProvider.AttributeUpdates.Add and dataProvider.AttributeUpdates.Remove methods.

Warning: this is an advance feature and should be used with caution.

The following example demonstrates how to enable/disable a checkbox and add/remove its tooltip based on a selection in another checkbox.

function formUpdates(dataProvider)
{
    var checked = ('' + dataProvider.GetProperty("input.disable-child-check")) === "1";
    if (checked) {
        dataProvider.AttributeUpdates.Add({ ElementId: "child-check", AttributeName: "disabled", AttributeValue: "disabled" });
        dataProvider.AttributeUpdates.Add({ ElementId: "child-check", AttributeName: "title", AttributeValue: 'Uncheck "Disable Child" to enable' });
    } else {
        dataProvider.AttributeUpdates.Remove({ ElementId: "child-check", AttributeName: "disabled" });
        dataProvider.AttributeUpdates.Remove({ ElementId: "child-check", AttributeName: "title" });
    }
}

The Developer Tools Section

This section offers a few useful options for developers that wish to use the Forms Builder during development. You can see the Developer Tools section in the right side pane of the Formbuilder window.

There are three buttons listed here:

  • Simulate Launch: Simulates launching the app by showing the developer a page that has a mock AppSession created with the Properties of the input form.

  • Create AppSession: Simulates launching the app by creating the AppSession with Properties based on the input form

  • Send to Local Agent: Creates a new job specified by the Input Form and sends that job from BaseSpace to your local Virtual Machine to be run locally, if you followed the previous step and ran the sudo spacedock ... command you will see a job being submitted to your local terminal as soon as this button is pressed

Simulate Launch

The Simulate Launch option takes the developer to another page that shows the information that is created upon submittal of the form and the launch of the app.

This information includes:

  • The AppSession id in BaseSpace for the AppSession that would normally be generated (this option does not actually create the AppSession, see message at the top of the screenshot above)
  • The access token that was generated for the app to have access to the appropriate data in a user's account
  • The scope of the permissions that are allowed by the access token (based on your configured form)
  • The launch specification which includes the Id of your Docker Image in the registry and the command line that will be fed to your app upon launch (For Native Apps)
  • An area that displays the full AppSession with properties included.

Create AppSession

The Create AppSession option takes the developer to another page that shows the information that is created upon submittal of the form and the launch of the app. This option is different from Simulate Launch because this option actually creates the new AppSession instead of just simulating the AppSession that would be created, so you can access that AppSession via the REST API for BaseSpace if needed.

Otherwise, the page that the developer is taken to after clicking on this button is the same as the one for Simulate Launch except that the message at the top is different and indicates that an AppSession was actually created.

Send to Local Agent

The Send to Local Agent option is slightly different from the other options in the Developer Tools because it is only usable for Native Apps. Clicking on Send to Local Agent will send the job from BaseSpace's job scheduler to the local Native Apps Virtual Machine that is running on your machine. BaseSpace will send this job to the Virtual Machine where you pasted the Sample command-line to start local agent information from the Developer Tools.

The job that BaseSpace sends to your local Virtual Machine will include all of the information that is generated via the Create AppSession and Simulate Launch options. The command-line argument in your callbacks.js script is fed to the Docker image once it is found or downloaded locally and then it is executed.

To use the Send to Local Agent option, you will need to follow these steps:

  1. Run the Native Apps Virtual Machine locally

  2. SSH into the Virtual Machine from your terminal and login (the username and password are both basespace)

  3. Go to your form in the Formbuilder and copy the line after Sample command-line to start local agent and paste it into the terminal where you are logged into the virtual machine via SSH

    sudo spacedock -a ... -m https://hoth-mission.basespace.illumina.com
    

    Once successful, you should see a message in your terminal that says successfully pinged docker service, this means that your local Virtual Machine is now polling the BaseSpace Job Scheduler for work. Any time a new job for this application is submitted from BaseSpace, if the Send to Local Agent option is chosen by the developer, the job will execute in their local Virtual Machine and you can see this process in real-time!

    The value after the -a is your specific Agent Id, this is how BaseSpace knows to send jobs from this application to this local Virtual Machine. The url is the URL to BaseSpace's Job Scheduler.

  4. Ensure that your callbacks.js

  5. file is referencing the correct Docker image for your app and that the command line argument that is being sent is sufficient for your app to run

  6. Click Send to Local Agent

    You should now be taken to the AppSession page for this job in BaseSpace in the Formbuilder window. You can see a running log of output from the app.

    If you switch to the terminal where you are logged into the virtual machine via SSH, you will see the app execute by doing the following:

    • Downloading the Docker image
    • Downloading the input data from the form to the data/input folder
    • Running the command-line argument from the callbacks.js
    • Execute your script within your Docker container
    • Uploading results back to BaseSpace from the data/output
    • Mark the AppSession as Complete

    The app will keep updating the AppSession with Status and Status Summary throughout the above process.

The Launch Button

The Launch button behaves differently for different types of apps.

For Web and Desktop Apps

After the user selects the data for the input form and clicks Launch, the user is redirected to the app's redirect_uri with an appsessionuri. This behavior is described in more detail in Application Triggering From BaseSpace.

As described above, an AppSession will be created with all of the selected input form values stored in its Properties metadata.

For Native Apps

The Launch option will launch the app in Amazon S3 instead of sending it to your local Virtual Machine. The job is sent to the BaseSpace Job Scheduler, which then finds or creates an Amazon Machine Image (AMI) to run the app. This AMI's specifications are similar to that of the Native Apps Virtual Machine that we provide. Once the AMI receives the job from the Job Scheduler, it downloads the Docker image to the AMI from the Docker registry and runs the command-line argument in the callbacks.js.

The Launch button is meant to test launch the app as a user would using Amazon S3 infrastructure rather than your local machine with the Virtual Machine running.

Examples

Isaac v2

Form UI:

Code:

{
"$type": "Form",
    "fields": [

         {
            "$type": "SampleChooser",
            "size": 250,
            "valueType": "Input",
            "allowedPermissions": "read",
            "label": "Sample",
            "required": true,
            "requiredMessage": "Please choose a sample",
            "readOnly": true,
            "id": "samples",
            "rules": "min-cycles-1,min-cycles-2,is-sample-reader,sample-is-not-empty"
        },      
        {
        "$type": "Select",
         "id": "genome-id",
         "label": "Reference Genome",
         "choices": [ 
          { 
              "value": "Human",
              "text": "Human (UCSC HG 19)",
              "selected": "true"
          },
          { 
              "value": "Arabidopsis",
              "text": "Arabidopsis (NCBI)",
              "selected": "false"
          },
          { 
              "value": "B. Taurus",
              "text": "B. Taurus  (Ensembl UMD3.1)",
              "selected": "false"
          },
          { 
              "value": "E. Coli DH10B",
              "text": "E. Coli DH10B (NCBI 2008-03-17)",
              "selected": "false"
          },
          { 
              "value": "E. Coli MG1655",
              "text": "E. Coli MG1655 (NCBI 2001-10-15 )",
              "selected": "false"
          },

          { 
              "value": "Mouse",
              "text": "Mouse (UCSC MM9)",
              "selected": "false"
          },
          { 
              "value": "Phi X",
              "text": "Phi X (Illumina)",
              "selected": "false"                        
          },
          {
              "value": "S. Aureus NCTC 8325",
              "text": "S. Aureus NCTC 8325 (NCBI 2006-02-13)",
              "selected": "false"
          },
          { 
              "value": "Rat",
              "text": "Rat (UCSC RN5)",
              "selected": "false"
          },
          { 
            "value": "Rhodobacter",
            "text": "Rhodobacter  (NCBI 2005-10-07)",
            "selected": "false"
          },
          { 
            "value": "S. Cerevisia",
            "text": "S. Cerevisia (UCSC sacCer2)",
            "selected": "false"
          }
          ]
        },     

        {
          "$type": "SectionBreak"
        },
        {
            "$type": "TextBox",
            "size": 250,
            "minLength": 0,
            "maxLength": 150,
            "value": "BWA WGS v1 [LocalDateTime]",
            "label": "Analysis Name",
            "required": true,
            "requiredMessage": "Please enter name for your app session.",
            "id": "app-session-name"
        },
        {
            "$type": "ProjectChooser",
            "size": 250,
            "valueType": "Output",
            "allowedPermissions": "owner",
            "label": "Save Results To",
            "required": true,
            "requiredMessage": "Please choose a project",
            "id": "project-id",
            "rules": "is-project-owner"
        },
      {
          "$type": "CheckBox",
          "id": "SV_CNV_Call",
          "label": "Enable SV/CNV Calling (use with paired-end data only)",
          "choices": [ 
            { 
              "value": 1
            }
          ]
      },


       {
      "$type": "RadioButton", 
      "id": "AnnotationSource",
      "label": "Annotation",
      "value": "Ensembl", 
      "choices": [
        {
          "value": "RefSeq",
          "label": "RefSeq"
        },

        {
          "value": "Ensembl",
          "label": "Ensembl"
        }
        ]
    },

      {
            "$type": "SectionBreak",
            "title": "Advanced"
      },
      {
          "$type": "Numeric",
          "id": "GQX-id",
          "size": 30, 
          "required": true,
          "requiredMessage": "Please enter Min GQX for Variants.",
          "label": "Min GQX for Variants",
          "min": 0, 
          "max": 99,
          "value": 30,
          "numericType": "Integer", 
          "rules": "noop"
        },
        {
            "$type": "Numeric",
            "size": 30,
            "minLength": 0,
            "maxLength": 6,
            "label": "Max Strand Bias for Variants",
            "required": true,
            "requiredMessage": "Please enter Max StrandBias for Variants.",
            "value": 10,
            "min": 0,
            "max":99,
            "id": "StrandBias-id",
            "rules": "noop"
      },
      {
          "$type": "CheckBox",
          "index": 1,
          "id": "FlagPCRDuplicates",
          "label": "Flag PCR Duplicates (use with paired-end data only)",
          "choices": [
            { 
              "value": 1,
              "checked": true
            }
          ]
      }
    ],
    "rulesets": [
      {
          "$type": "PermissionValidationRule",
          "permissions": "Own",
          "severity": "Error",
          "message": "You must be an owner to create app results in the selected project",
          "id": "is-project-owner"
      },
      {
          "$type": "MinCycles1SampleValidationRule",
          "relation": "GreaterThan",
          "value": 32,
          "severity": "Error",
          "id": "min-cycles-1"
      },
      {
          "$type": "MinCycles2SampleValidationRule",
          "relation": "GreaterThan",
          "value": 32,
          "severity": "Warning",
          "id": "min-cycles-2"
      },
      {
          "$type": "PermissionValidationRule",
          "permissions": "Read",
          "severity": "Error",
          "message": "You do not have read access to the selected sample",
          "id": "is-sample-reader"
      },
      {
          "$type": "EmptySampleValidationRule",
          "message": "Insufficientnumberofreads.",
          "relation": "GreaterThan",
          "value": 0,
          "severity": "Error",
          "id": "sample-is-not-empty"
      }
    ]
}