Visualize Your Project Team as an Org Chart

Overview

When you live and breathe Jira, you can easily forget that not everyone knows every detail of every project. The set of people actually working on a project at any given time can be somewhat fluid, as they often complete their tasks related to one project and begin working on another.

Let's say you wanted to see a visual of everyone working on a specific project on a dashboard. They needed to be able to see this information in a quick-and-easy to understand format. VisualScript Studio is a great way to visualize your team members currently working on a project as an org chart and display it on a Jira dashboard.

The design for this particular visualization was very straightforward. I wanted to show a shape for each user who had at least one issue assigned to them in the project. To allow the end user to dig deeper, I also made the name of the team member a link back to the list of issues assigned to them.

Project team visualization

The user interface for rendering this visual is just an text box to enter the project name:

Project text box

How I Implemented It

Obtaining the Data

First, I gathered the information required from Jira. Using the parameters passed in from the UI, I use VSCallFunctionForJiraQuery to query Jira using the Jira REST API. The only parameter needed for the query is the project name provided by the user in the user interface.

VSCallFunctionForJiraQuery(gSDJSLocalHost, "project = " + params, queryResultsHandler);

Building the Model

Once the query completes, the queryResultsHandler function is called with the list of issues that were returned as the results of the query. I use the returned list of issues to build the model of the data that I will later build VisualScript markup from. The processing is straightforward: I scan each issue and examine its assignee. When I find an assignee that is not already in my model's assignee array, I add a new entry to the assignee list and some summary information about the issue assigned to that user into the assignee's issues list.

// Build the model. Build a list of all the assignees and the issues they're assigned to. len = issues.length; for (i = 0; i < len; i++) { if (!issues[i].fields.assignee) { continue; } if (!assignees[issues[i].fields.assignee.key]) { assignees[issues[i].fields.assignee.key] = { name: issues[i].fields.assignee.displayName, avatar: issues[i].fields.assignee.avatarUrls["48x48"], issues: [] }; } assignees[issues[i].fields.assignee.key].issues.push({ key: issues[i].key, desc: issues[i].fields.summary, url: localhost + "/browse/" + issues[i].key }); // Add the issue to the list of issues that the user is assigned to }

Constructing the VisualScript from the Model

I use the model to construct VisualScript SDK objects. After setting up the document as an org chart, I iterate through my model (the assignees array), adding a shape for each assignee. Each shape contains a table with the assignee's avatar on the left side and the assignee's full name on the right. I also add a hyperlink to each user's name which opens the list of issues assigned to that person.

// Build the VisualScript vs = new VS.Document(); vs.SetTemplate(VS.Templates.Orgchart); rootShape = vs.GetTheShape() .SetLabel("Project - " + params) .SetFillColor("#FBD585") .SetLineThickness(0); var connector = rootShape.AddShapeConnector(); // Now add a shape for each assignee....shape has a table for the assignee's avatar and display name for (var assigneeKey in assignees) { nameAndAvatarShape = connector.AddShape() .SetFillColor("#EEEEEE") .SetLineThickness(0) .SetTextGrow(VS.TextGrow.Horizontal); var table = nameAndAvatarShape.AddTable(1,2) .SetColumnWidth(24) .SetRowHeight(24); table.AddCell(1, 1) .SetImage(assignees[assigneeKey].avatar); table.AddCell(1, 2) .SetLabel(assignees[assigneeKey].name) .SetTextHyperlink(getBrowseUrlForAssigneesIssues(assignees, assigneeKey, params)); }

Rendering the VisualScript

The last step is to use callback script to hand off the VisualScript markup to generate a visual.

// Render the VisualScript
callback(vs.toJSON());

Creating the UI

After the script is complete, I set up the UI so that the user could provide the required parameters. In the top section of the VisualScript Studio edit page, you'll see a field labeled "Parameter Template". The specification string for the UI Builder's "Parameter Template" is:

Project parameter template

When this string is entered, a form appears that lets me fill in additional information about the parameter:

Project parameters

All that really needs to be done here is to make the "displayed name" a bit more friendly:

Project name

More Information

This is just one example of the useful visuals that can be produced using VisualScript and VisualScript Studio with a minimum of development effort.

The full source for this script can be seen here. To make the code easier to understand, I highlighted the part used for querying the data in green, the part for building the model in orange, and the part that creates VisualScript from the data in blue.

function VisualScript(localhost, params, callback) {
 
    // Shows a graphic display of all the users assigned to issues in the parameter project.
 
    debugger;
 

    
VSCallFunctionForJiraQuery(gSDJSLocalHost, "project = " + params, queryResultsHandler); // Handle the response from the query function queryResultsHandler(issues) { var vs = {}, rootShape = {}; var i, j, len, assignees = {}; //debugger; if (!issues) { alert((!params || (params.length === 0)) ? "No parameter provided. Please provide a project key in the parameters" : "No issues found for project " + params); callback(null); return; }
// Build the model. Build a list of all the assignees and the issues they're assigned to. len = issues.length; for (i = 0; i < len; i++) { if (!issues[i].fields.assignee) { continue; } if (!assignees[issues[i].fields.assignee.key]) { assignees[issues[i].fields.assignee.key] = { name: issues[i].fields.assignee.displayName, avatar: issues[i].fields.assignee.avatarUrls["48x48"], issues: [] }; } assignees[issues[i].fields.assignee.key].issues.push({ key: issues[i].key, desc: issues[i].fields.summary, url: localhost + "/browse/" + issues[i].key }); // Add the issue to the list of issues that the user is assigned to }
// Build the VisualScript vs = new VS.Document(); vs.SetTemplate(VS.Templates.Orgchart); rootShape = vs.GetTheShape() .SetLabel("Project - " + params) .SetFillColor("#FBD585") .SetLineThickness(0); var connector = rootShape.AddShapeConnector(); // Now add a shape for each assignee....shape has a table for the assignee's avatar and display name for (var assigneeKey in assignees) { nameAndAvatarShape = connector.AddShape() .SetFillColor("#EEEEEE") .SetLineThickness(0) .SetTextGrow(VS.TextGrow.Horizontal); var table = nameAndAvatarShape.AddTable(1, 2) .SetColumnWidth(24) .SetRowHeight(24); table.AddCell(1, 1) .SetImage(assignees[assigneeKey].avatar); table.AddCell(1, 2) .SetLabel(assignees[assigneeKey].name) .SetTextHyperlink(getBrowseUrlForAssigneesIssues(assignees, assigneeKey, params)); } // Render the VisualScript callback(vs.toJSON()); } function getBrowseUrlForAssigneesIssues(assignees, assigneeKey, projectKey) { return localhost + "/browse/" + assignees[assigneeKey].issues[0].key + "?jql=" + encodeURIComponent("Project=" + projectKey + " AND assignee=" + assigneeKey); } }