Skip to content

Instantly share code, notes, and snippets.

@davejlong
Last active June 17, 2019 23:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davejlong/e2adb6e2f301672500d4b13e0a9a7de2 to your computer and use it in GitHub Desktop.
Save davejlong/e2adb6e2f301672500d4b13e0a9a7de2 to your computer and use it in GitHub Desktop.

JIRA Kitto Plugin

Adds the ability to display lists of issues or a count of issues for filters from JIRA. The plugin is composed of 2 parts:

  • JIRA Job - A Kitto job definition
  • JIRA Table Widget - A Kitto widget for displaying JIRA issues in a table

Installation

  1. Install into your dashboard with mix kitto.install --gist e2adb6e2f301672500d4b13e0a9a7de2
  2. Setup config/config.exs with the correct configuration variables:
config :my_dashboard,
  jira_url: "https://example.atlassian.net",
  jira_username: "a valid JIRA username",
  jira_password: "the password for {JIRA_USERNAME}"
  1. Update jira.exs#L4 with the names and filter IDs of JIRA filters

Use

The JIRA job defines 2 data sources for each filter: a list of issues and a count of the issues. The count data sources are compatible with the standard Kitto Number widget. The list data sources are built for the JiraTable widget.

JIRA Table

To display the list of issues for a filter use the JiraTable widget in your dashboard:

<div class="widget-jira"
     data-source="high_priority_list"
     data-widget="JiraTable"
     data-title="High Priority Issues"
     data-moreinfo="Blocker and Critical"></div>
# lib/apis/jira.ex
defmodule Jira do
def issues({:filter, filter}) do
jql = "filter=" <> to_string(filter) <> "+order by priority DESC,updated ASC"
issues({:jql, jql})
end
def issues({:jql, jql}) do
url = URI.parse(url_root() <> "/rest/api/2/search?maxResults=25&jql=" <> URI.encode(jql))
HTTPoison.get!(url, authentication).body
|> Poison.decode!()
end
def count(issues) do
issues["total"]
end
def issue_for_dashboard(issue) do
%{
id: issue["key"],
summary: issue["fields"]["summary"],
priority: issue["fields"]["priority"]
}
end
defp username, do: Application.get_env(:my_dashboard, :jira_username)
defp password, do: Application.get_env(:my_dashboard, :jira_password)
defp url_root, do: Application.get_env(:my_dashboard, :jira_url)
defp authentication do
["Authorization": "Basic " <> Base.encode64("#{username()}:#{password()}")]
end
end
# jobs/jira.exs
use Kitto.Job.DSL
filters = [
"high_priority": {:filter, "10300"}, # <= All open issues with critical or higher priority
"bugs": {:jql, "issuetype = Bug"} # <= All open bugs
]
Enum.each(filters, fn ({name, filter}) ->
job name, every: {5, :minutes} do
issues = Jira.issues(filter)
list = %{items: issues["issues"] |> Enum.map(&Jira.issue_for_dashboard/1)}
count = %{value: Jira.count(issues)}
broadcast! to_string(name) <> "_list", list
broadcast! to_string(name) <> "_count", count
end
end)
import React from 'react';
import {Widget, Helpers} from 'kitto';
import './jira_table.scss';
class TableRow extends React.Component {
render() {
return (
<tr>
<td><img className="priority-icon" src={this.props.priorityIcon} alt={this.props.priority} /></td>
<td className="issue-key">{this.props.id}</td>
<td className="issue-summary">{truncate(this.props.summary, this.props.summaryLength || 80)}</td>
</tr>
)
}
}
export class JiraTable extends Widget {
renderRows(issues) {
return issues.map((item, i) => {
return <TableRow key={i}
id={item.id}
summary={item.summary}
summaryLength={+this.props.summaryLength}
priority={item.priority.name}
priorityIcon={item.priority.iconUrl}/>;
});
}
render() {
return (
<div className={this.props.className}>
<h1 className="title">{this.props.title}</h1>
<h3>{this.props.text}</h3>
<table>
<thead>
<tr>
<th>&nbsp;</th>
<th>Key</th>
<th>Summary</th>
</tr>
</thead>
<tbody>{this.renderRows(this.state.items || [])}</tbody>
</table>
<p className="more-info">{this.props.moreinfo}</p>
<p className="updated-at">{this.updatedAt(this.state.updated_at)}</p>
</div>
)
}
}
Widget.mount(JiraTable);
export default JiraTable;
// widgets/jira_table/jira_table.scss
// ----------------------------------------------------------------------------
// Sass declarations
// ----------------------------------------------------------------------------
$background-color: #12b0c5;
$title-color: rgba(255, 255, 255, 0.7);
$zebra-color: rgba(255, 255, 255, 0.3);
$moreinfo-color: rgba(255, 255, 255, 0.7);
// ----------------------------------------------------------------------------
// Widget-JiraTable styles
// ----------------------------------------------------------------------------
.widget-jiratable {
background-color: $background-color;
tbody tr td:last-child { text-align: left; }
tbody tr:nth-child(even) { background-color: $zebra-color; }
.priority-icon {
width: 20px;
height: 20px;
}
.issue-key { font-size: 0.8rem; }
.more-info, .updated-at { color: $moreinfo-color; }
}
@zorbash
Copy link

zorbash commented Nov 23, 2016

Consider mentioning poison@3.0.0 since that's the version Kitto depends on, see kittoframework/kitto@b8657b8.

@zorbash
Copy link

zorbash commented Feb 21, 2017

The widget has to be updated as seen below to work with Kitto@0.5.1

import React from 'react';
import {Widget, Helpers} from 'kitto';

import './jira_table.scss';

class TableRow extends React.Component {
  render() {
    return (
      <tr>
        <td><img className="priority-icon" src={this.props.priorityIcon} alt={this.props.priority} /></td>
        <td className="issue-key">{this.props.id}</td>
        <td className="issue-summary">{Helpers.truncate(this.props.summary, this.props.summaryLength || 80)}</td>
      </tr>
    )
  }
}

export class JiraTable extends Widget {
  renderRows(issues) {
    return issues.map((item, i) => {
      return <TableRow key={i}
                       id={item.id}
                       summary={item.summary}
                       summaryLength={+this.props.summaryLength}
                       priority={item.priority.name}
                       priorityIcon={item.priority.iconUrl}/>;
    });
  }

  render() {
    return (
      <div className={this.props.className}>
        <h1 className="title">{this.props.title}</h1>
        <h3>{this.props.text}</h3>
        <table>
          <thead>
            <tr>
              <th>&nbsp;</th>
              <th>Key</th>
              <th>Summary</th>
            </tr>
          </thead>
          <tbody>{this.renderRows(this.state.items || [])}</tbody>
        </table>
        <p className="more-info">{this.props.moreinfo}</p>
        <p className="updated-at">{this.updatedAt(this.state.updated_at)}</p>
      </div>
    )
  }
}

Widget.mount(JiraTable);

@zorbash
Copy link

zorbash commented Jun 17, 2019

For this to work, you'll need to ensure that httpoison is started by updating your mix.exs

  def application do
    [applications: [:logger, :kitto, :httpoison]]
  end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment