Using VisualScript Studio's JavaScript Editor

Introduction

VisualScript Studio lets you create, store, and edit scripts directly from the gadget or macro you're using to display the output. This tutorial will cover the following topics to help you become familiar with VisualScript Studio:

  1. Add the VisualScript Editor gadget to your page
  2. Familiarize yourself with the editor
  3. Add a new script to the editor
  4. Monitor the script's execution using a web browser debugger
  5. Modify the sample script to produce the desired results
  6. Add a user interface
  7. Script management

We'll walk through the steps of setting up a VisualScript Studio Gadget on Jira. We will then create, execute and test a script that will display the current open issues of the user who is running the script. Finally, we'll examine scenarios where you can work with multiple scripts.

Add the VisualScript Editor Gadget

The first step to setting using the Visual Studio gadget in Jira is to add it to your dashboard.

To begin, go to the dashboard you wish to use. If you don't already have a dashboard set up, you can create one using the "Manage Dashboards" option in Jira's "Dashboard" menu item:

Jira dashboard dropdown

On the dashboard, use the "add a new gadget" link to open the gadget browser.

Add new gadget

The "Add a gadget" dialog contains a list of gadgets that have already been loaded, but you'll almost certainly need to click the "Load All Gadgets" link in the "More Gadgets Available" box.

Gadget dialog

After you click the "Load all Gadgets" link, a scrolling list of gadgets will appear. You can either scroll down to the list of VisualScript gadgets, or you can type "VisualScript" into the search/filter box in the top left area of the list. You'll want to choose "VisualScript Editor" to add the gadget that will give you a custom scripting environment where you can write your own code.

Gadgets list

The VisualScript Editor gadget is now set up on your dashboard and ready for you to begin configuring it.

Gadget ready to configure

Configure the Editor

On the VisualScript Studio gadget, click the "Configure" button to launch the VisualScript Editor user interface.

Gadget ready to configure

The interface has four main sections:

Script Information

The Script Information section contains:

  • Script Name: Name of the script as it will appear in the Scripts List (bottom section).
  • Script Description: Description of the script as it will appear in the Scripts List.
  • Parameter Template: Specification string for the parameter to the script. More about this later in the "Add a user interface" section.
  • Buttons for "Save and Close" to exit the editor with save, and "Cancel" to exit the editor without saving.
Code Editor

The Code Editor is a feature-rich JavaScript editor in which you will create and modify your script's code. It provides many convenient and familiar features of lightweight modern code editors such as syntax highlighting (primarily via color), bracket-matching, auto-complete of brackets, parenthesis and quotation marks. The Code Editor also alerts you to syntactical errors.

Script Actions Button Bar

The Script Actions button bar allows you to take "file level" actions on your script:

  • New Script: Creates a new script, with boilerplate/example code as well as placeholder name and description information.
  • Save Script: Saves the current script as a new script in the Scripts List.
  • Update Script: Updates the current script (without leaving the editor).
  • Export Script: Exports the current script and causes the web browser to download the file.
  • Delete Script: Deletes the current script.
  • Run Script: Runs the current script. This performs an Update Script prior to running it.
Scripts List

At the bottom section of the editor is a list of scripts. This list is initially empty. It is populated as you create scripts using the interface. Each script in the list will have a "select" button in its first column that will allow you to make that script the current script by loading it into the Code Editor section.

Add a New Script to the Editor

To begin, add a new script to the editor. This can easily be done by clicking the "New Script" button in the "Script Actions" button bar. This will provide default name and description for your script in the Script Information section. It will also load an example script into the Code Editor. The example script implements a "Hello World" program. It will actually place any text that you enter into the parameters into the visual output, but "Hello World" is provided by default.

Add script

At this point, you can click the "Save and Close" button in the upper-right corner of the gadget, then click "Run" to see the output. Alternatively, you can click the "Update Existing Script" button in the Script Actions button bar, then click "Run Script". You should see the following output:

First script

Congratulations! You've just created and run your first script using the VisualScript Editor.

Monitor the Script's Execution

You're probably already familiar with using your web browser's debugging capabilities. If you're not, search the web for "JavaScript debugging" and add the name of the web browser you're using.

By far the easiest way to get visibility into your script is to use the debugger; statement inside your script at a point prior to any substantive processing. This will cause the debugger to stop at that point, and will allow you to view the code as it's executing, step through it and set breakpoints.

The process of debugging a script is to make changes and fixes in the Code Editor, click the "Update Existing Script" button in the Script Actions button bar, then click "Run Script". The web browser's debugger will stop the execution at the "debugger;" statement allowing you to step through the code and examine the value of variables, as well as see any exceptions that may be thrown (in the web browser debugger's console output area).

Modify the Sample Script

Now that you have a sample script set up and working with your web browser debugger, you can begin to modify it to achieve the results that you're looking for. Most scripts will follow the pattern:

  1. Issue REST API query to obtain data
  2. Process the returned data into a model
  3. Use the model to produce VisualScript
  4. Render the VisualScript into a visual representation

Let's walk through each of these steps as we modify the sample script to produce our desired outcome: a list of Jira issues containing a word or phrase in its summary.

Issue REST API Query To Obtain Data

First, we should delete all the code between the enclosing curly braces of the outer function. We'll then add code to implement our script.

You can use standard JavaScript libraries and techniques to issue REST API calls, but you might find it easier and more convenient to use VisualScript functions to get the data from Jira. For our purposes, we want to issue a query for all issues that have the word "market" in the summary. The JQL (Jira Query Language) for that filter is "summary ~ market". So the first part of our call is:

VSCallFunctionForJiraQuery(localhost, "summary ~ market", <more to come>);

The VisualScript function "VSCallFunctionForJiraQuery" accepts as its first parameter the URL of the Jira instance we need information from. Almost always we will want to use the "localhost" that was passed as the first parameter to the script we're writing. The 2nd parameter is our JQL query, which in our case just filters for the issues that contain the word "market" in its summary.

The next step is to handle the results of the query. The results are returned asynchronously to the function passed as a 3rd argument to VSCallFunctionForJiraQuery. So to handle the response, we create a function named handleQueryResponse and pass it to VSCallFunctionForJiraQuery:

VSCallFunctionForJiraQuery(localhost, "summary ~ market", handleQueryResponse);
 
function handleQueryResponse(issues) {
 
}

Process the Returned Data into a Model

At this point, we have received the results from our query and need to process it into a model of the data we want to visually represent. This processing can range from trivial (which will be our case) to complex designs requiring multiple data structures and multiple asynchronous API calls. To produce our model, we really only need to loop through the list of returned issues, adding the issue's key, summary description and issue type to the model array.

VSCallFunctionForJiraQuery(localhost, "summary ~ market", handleQueryResponse);
 
function handleQueryResponse(issues) {
    var model = [];
     
    // Build the model from the issues
    for (var i = 0; i < issues.length; i++) {
        model.push({key: issues[i].key, summary: issues[i].fields.summary, issueType: issues[i].fields.issuetype.name});
    }
}

Use the Model to Produce VisualScript

Now that we have our model built, we're ready to use that model to produce VisualScript. After setting up a VisualScript document, we get the main shape, add a shape connector to it, then loop through our model, adding shapes for each entry in our model.

VSCallFunctionForJiraQuery(localhost, "summary ~ market", handleQueryResponse);
 
function handleQueryResponse(issues) {
    var model = [];
 
    // Build the model from the issues
    for (var i = 0; i < issues.length; i++) {
        model.push({key: issues[i].key, summary: issues[i].fields.summary, issueType: issues[i].fields.issuetype.name});
    }
 
    // Build the VisualScript from the model
    var visualScript = buildVisualScript(model);
}
 
function buildVisualScript(model) {
    // Set up the VisualScript document
    var vs = new VS.Document();
     
    // Get the main shape and add a shape connector to it.
    var mainShape = vs.GetTheShape();
    var connector = mainShape.AddShapeConnector();
     
    // Add a shape to the connector for each entry in the model
    for (var i = 0; i < model.length; i++) {
        connector.AddShape()
                    .SetLabel(model[i].key + "\n" + model[i].summary);
    }
     
    return vs;
}

Render the VisualScript into a Visual Representation

Finally, we use the callback that was passed to our script when it was called to start the process of displaying the VisualScript as a SmartDraw visual.

VSCallFunctionForJiraQuery(localhost, "summary ~ market", handleQueryResponse);
 
function handleQueryResponse(issues) {
    var model = [];
 
    // Build the model from the issues
    for (var i = 0; i < issues.length; i++) {
        model.push({key: issues[i].key, summary: issues[i].fields.summary, issueType: issues[i].fields.issuetype.name});
    }
 
    // Build the VisualScript from the model
    var visualScript = buildVisualScript(model);
 
    // Render the VisualScript
    callback(visualScript.toJSON());
}
 
function buildVisualScript(model) {
    // Set up the VisualScript document
    var vs = new VS.Document();
     
    // Get the main shape and add a shape connector to it.
    var mainShape = vs.GetTheShape();
    var connector = mainShape.AddShapeConnector();
     
    // Add a shape to the connector for each entry in the model
    for (var i = 0; i < model.length; i++) {
        connector.AddShape()
                    .SetLabel(model[i].key + "\n" + model[i].summary);
    }
     
    return vs;
}

The entire script in the Code Editor should look like this:

function VisualScript(localhost, params, callback) {
 
    // Issue the query in the params. Calls the handler with the issues list
    VSCallFunctionForJiraQuery(localhost, "summary ~ market ORDER BY created ASC", handleQueryResponse);
 
    function handleQueryResponse(issues) {
        var model = [];
 
       // Build the model from the issues
        for (var i = 0; i < issues.length; i++) {
            model.push({key: issues[i].key, summary: issues[i].fields.summary, issueType: issues[i].fields.issuetype.name});
        }
 
        // Build the VisualScript from the model
        var visualScript = buildVisualScript(model);
 
        // Render the VisualScript
        callback(visualScript.toJSON());
    }
 
    function buildVisualScript(model) {
        // Set up the VisualScript document
        var vs = new VS.Document();
         
        // Get the main shape and add a shape connector to it.
        var mainShape = vs.GetTheShape();
        var connector = mainShape.AddShapeConnector();
 
        // Add a shape to the connector for each entry in the model
        for (var i = 0; i < model.length; i++) {
            connector.AddShape()
                            .SetLabel(model[i].key + "\n" + model[i].summary);
        }
 
        return vs;
    }
}

Presuming you have some sample data in your Jira installation that includes issues with the word "market" in the summary, your results when you run this script should look something like this:

Script result

From here, you're free to tinker with the appearance. The default view is "org chart", but you can very easily display this as a mind map by adding the following statement after the new VS.Document() statement:

vs.SetTemplate(VS.Templates.Orgchart);

While we're tinkering, let's give the root shape a label, make the issues rounded in appearance, and have a specific color for the issue type.

function buildVisualScript(model) {
       // Set up the VisualScript document
       var vs = new VS.Document();
        
       vs.SetTemplate(VS.Templates.Mindmap);
        
       // Get the main shape and add a shape connector to it.
       var mainShape = vs.GetTheShape()
                       .SetLabel("Issues containing: market");
        
       var connector = mainShape.AddShapeConnector();
 
       // Add a shape to the connector for each entry in the model
       for (var i = 0; i < model.length; i++) {
           // Assign a color based on the issue type
           var color;
           switch(model[i].issueType) {
               case "Story": color = "#91AECF";
                           break;
               case "Sub-task": color = "FADE9E";
                           break;
               default: color = "#ACE2FC";
               }         
            
           connector.AddShape()
                       .SetLabel(model[i].key + "\n" + model[i].summary)
                       .SetShapeType(VS.ShapeTypes.RoundedRectangle)
                       .SetFillColor(color);
       }
 
       return vs;
   }

These small modifications change the appearance of the output visual:

New script output

Add a User Interface

The example we developed in the preceding section is useful, but would be much more useful if we could provide a parameter to it that would let us filter for other words than just "marketing". To accomplish that, we will add a user interface and pass it to our script as a parameter.

The user interface is controlled in the Script Information section at the top of the VisualScript Studio Editor. If the parameter is not changeable by the user, then just type marketing into the "Parameter Template" field. If, however, we want the user to be able to change that value to something else, we enter a parameter name surrounded by 2 pairs of curly braces (as shown below):

Parameter template

As soon as you enter the last "ending" curly brace, a form will appear that allows you to customize the user interface with respect to this parameter:

Now if we click the "Update Script", then "Run" button, we will see that we've create some UI for the user.

New UI

If we set a breakpoint inside the code right at the top, before the query, we will see that whatever the user types into this field is passed in via the params parameter (in the very top line of the script). We can modify the script to use that param:

function VisualScript(localhost, params, callback) {
 
    // Issue the query in the params. Calls the handler with the issues list
    VSCallFunctionForJiraQuery(localhost, "summary ~ " + params + " ORDER BY created ASC", handleQueryResponse);

Now when we "update existing script", then run it, we can enter another word to filter on. We'll try "product":

Update script

The output now filters only for issues that have "product" in the summary:

Updated script

Notice that the main/root shape still says "Issues containing: market". We had hard-coded that before. To update that, change the .SetLabel() call when setting up the main shape to use the params value:

// Get the main shape and add a shape connector to it.
var mainShape = vs.GetTheShape()
                                .SetLabel("Issues containing: " + params);
A User Interface with Multiple Parameters

Frequently, you will need a user interface that collects multiple parameters from the user and uses them in the script. To accomplish this, you will need to use the Parameter Template to specify a 2nd parameter. You can do this by entering a separator character (a comma, for example), and then a 2nd identifier surrounded by double-curly-braces, For example, let's add a 2nd parameter of "project" so that the user can limit the results to only a single project.

UI with multiple parameters

When we run this script now, if we enter "product" for the keyword and "viewpoint" for the product, the params string passed to the script will be product,viewpoint. Inside the script, it will need to break the params string into its two pieces (at the comma) and assign variables to each piece.

function VisualScript(localhost, params, callback) {
 
    debugger;
     
    var paramParts = params.split(',');
     
    var keyword = paramParts[0];
    var project = paramParts[1];
     
    // Issue the query in the params. Calls the handler with the issues list
    VSCallFunctionForJiraQuery(localhost, "summary ~ " + keyword + " and project = "+ project +" ORDER BY created ASC", handleQueryResponse);

Hopefully you can now see that the parameter template is in fact a template. The params will be passed exactly as that string is typed in to the Parameter Template field, with the variables enclosed in double-curly braces substituted for what the user typed in to the user interface form.

A useful but slightly more complicated variation of this use of the template is to create a JSON string in the Parameter Template that is then parsed into a JSON object when the script runs. To do this, change the Parameter Template to look like a stringified JavaScript object.

Stringified parameter template

Now when the script runs, it is passed a string that can be parsed into a JavaScript object.

function VisualScript(localhost, params, callback) {
 
   var parmsObj = JSON.parse(params);
     
    // Issue the query in the params. Calls the handler with the issues list
    VSCallFunctionForJiraQuery(localhost, "summary ~ " + parmsObj.keyword + " and project = "+ parmsObj.project +" ORDER BY created ASC", handleQueryResponse);

Now we can parse the params string into an object, and use paramsObj.keyword and paramsObj.project in our query. Note that JSON.parse() is very particular about quotes being placed around both the keyword and the value.

Script Management

Scripts you add to the VisualScript Studio Scripts List are shared by all users who have access to Jira. By default, all Jira Administrators can add, edit and delete all scripts (not just the ones they themselves create). All non-administrators can execute all scripts, but may not create, modify or delete them. Each user's own account is used to access the underlying Jira objects queried in the scripts, so using VisualScript Studio scripts does not give a user greater or lesser access to Jira information than they would have had otherwise.