Instantly share code, notes, and snippets.

@renenz /README.md forked from matt-snider/README.md
Last active Aug 2, 2016

Embed
What would you like to do?
GitLab Milestones Dashing Widget

Preview

Description

A Dashing widget that displays all currently open GitLab milestones. Based off of the widget: GitLab Group Open Merge Requests.

Dependencies

The only dependency is gitlab.

Add it to Dashing's Gemfile:

gem 'gitlab'

and run bundle install.

Usage

To use this widget, simply run:

dashing install 3d3ed6b7beee0e4994b8

To add the widget to your dashboard, include the following snippet in the layout file:

<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
  <div data-view="GitlabMilestones" data-title="Milestones" data-id="gitlab-milestones"></div>
</li>

Settings

Substitute the following placeholders in gitlab_milestones.rb with the appropriate values:

  • gitlab_uri: The API url for your GitLab, only change this if you host your own GitLab.
  • gitlab_token: The API token from your account
  • use_business_days: Choose whether the count of days remaining counts weekdays only or all days.

The job to update the milestones is run every minute but you can adjust this as needed.

class Dashing.GitlabMilestones extends Dashing.Widget
ready: ->
# This is fired when the widget is done being rendered
onData: (data) ->
# Handle incoming data
# You can access the html node of this widget with `@node`
# Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in.
<h1 class="header" data-bind="title"></h1>
<ul class="list">
<li data-foreach-milestone="milestones" class="milestone">
<div class="milestone-title" data-bind="milestone.title"></div>
<div class="milestone-due-days" data-bind="milestone.due_days"></div>
<div class="progress">
<div class="progress-bar progress-bar-success" data-bind-width="milestone.progress_bar"></div>
</div>
<div class="milestone-info">
<div data-bind="milestone.progress"></div>
<div>&nbsp;&middot;&nbsp;</div>
<div data-bind="milestone.repo"></div>
<div>&nbsp;&middot;&nbsp;</div>
<div data-bind="milestone.due_date"></div>
</div>
<div style="clear: both;"></div>
</li>
</ul>
<p class="updated-at" data-bind="updatedAtMessage"></p>
require 'gitlab'
require 'date'
gitlab_uri = 'https://gitlab.com/api/v3'
gitlab_token = 'PRIVATE_TOKEN_GOES_HERE'
use_business_days = true
Gitlab.configure do |config|
config.endpoint = gitlab_uri
config.private_token = gitlab_token
end
pr_widget_data_id = 'gitlab-milestones'
SCHEDULER.every '1m', :first_in => 0 do |job|
uri = URI("#{gitlab_uri}/projects?private_token=#{gitlab_token}")
response = Net::HTTP.get_response(uri)
if response.code != '200'
puts "\e[33mGitlab Milestone connection error, is your path and token set correctly? (HTTP_CODE: #{response.code})\e[0m"
next
end
data = JSON.parse(response.body)
projects = data.map do |proj|
{ :id => proj['id'], :name => proj['name'] }
end
open_milestones = projects.inject([]) { |milestones, proj|
Gitlab.milestones(proj[:id]).each do |milestone|
next if milestone.state == 'closed'
all_issues = Gitlab.milestone_issues(proj[:id], milestone.id, {})
closed_issues = all_issues.select {|x| x.state == 'closed'}.size
percent_complete = closed_issues.to_f / all_issues.size * 100.0
due_date = ( milestone.due_date.nil? ? 'no due date' : DateTime.parse(milestone.due_date).strftime("%-d %b %Y") )
if milestone.due_date.nil?
due_days = ''
else
due_days = days_between(Date.today, Date.parse(milestone.due_date), use_business_days)
end
progress = "#{percent_complete.round(0) }%" rescue "0%"
progress_bar = ((percent_complete*2).round(-1)/2) rescue 0
milestones.push({
title: milestone.title,
repo: proj[:name],
due_days: due_days,
due_date: due_date,
progress: progress,
progress_bar: progress_bar
})
end
milestones
}
open_milestones.sort_by! do |m|
begin
DateTime.parse(m[:due_date]).to_date.to_s
rescue
m[:title] || 'zzz'
end
end
send_event(pr_widget_data_id, {milestones: open_milestones})
end
private
def days_between(date1, date2, business_days)
days = 0
if (date2 > date1)
bigger_date = date2
smaller_date = date1
overdue = false
else
bigger_date = date1
smaller_date = date2
overdue = true
end
while bigger_date > smaller_date
if !business_days or !(bigger_date.saturday? or bigger_date.sunday?)
days = days + 1
end
bigger_date = bigger_date - 1
end
if (days == 1)
"Tomorrow"
elsif (days == 0)
"Today"
else
"#{days} days#{overdue ? ' overdue' : '' }"
end
end
// ----------------------------------------------------------------------------
// Sass declarations
// ----------------------------------------------------------------------------
$background-color: #71388a;
$heading-color: rgba(255, 255, 255, 0.7);
$milestone-title-color: rgba(255, 255, 255, 1.0);
$milestone-due-date-color: #cdaadc;
$milestone-info-color: rgba(255, 255, 255, 1.0);
// ----------------------------------------------------------------------------
// Widget-gitlab-milestones styles
// ----------------------------------------------------------------------------
.widget-gitlab-milestones {
background-color: $background-color;
vertical-align: top !important;
.header {
margin-bottom: 3px;
//font-size: x-large;
color: $heading-color;
}
.sub-header {
color: $heading-color;
font-size: large;
margin-bottom: 1vh;
}
.milestone {
margin-bottom: 1vh;
}
.milestone-title {
font-size: medium;
font-weight: bold;
color: $milestone-title-color;
float:left;
}
.milestone-info {
font-size: small;
font-style: italic;
color: $milestone-info-color;
}
.milestone-due-days {
font-size: medium;
font-weight: bold;
color: $milestone-due-date-color;
float: right;
}
.milestone-info div {
float:left;
}
.list {
list-style: none;
}
.updated-at {
color: rgba(0, 0, 0, 0.3);
}
ol, ul {
margin: 0 15px;
text-align: left;
}
ol {
list-style-position: inside;
}
.progress {
margin-top: 2px;
clear:both;
height: 6px;
display: block;
overflow: hidden;
background-color: #f5f5f5;
border-radius: 3px;
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,0.1);
box-shadow: inset 0 1px 2px rgba(0,0,0,0.1);
}
.progress-bar {
float: left;
width: 0%;
height: 100%;
font-size: 13px;
color: #fff;
text-align: center;
background-color: #2D9FD8;
-webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,0.15);
box-shadow: inset 0 -1px 0 rgba(0,0,0,0.15);
}
.progress-bar-success {
background-color: #2FAA60;
}
[width='0'] {
width: 0%;
}
[width='5'] {
width: 5%;
}
[width='10'] {
width: 10%;
}
[width='15'] {
width: 15%;
}
[width='20'] {
width: 20%;
}
[width='25'] {
width: 25%;
}
[width='30'] {
width: 30%;
}
[width='35'] {
width: 35%;
}
[width='40'] {
width: 40%;
}
[width='45'] {
width: 45%;
}
[width='50'] {
width: 50%;
}
[width='55'] {
width: 55%;
}
[width='60'] {
width: 60%;
}
[width='65'] {
width: 65%;
}
[width='70'] {
width: 70%;
}
[width='75'] {
width: 75%;
}
[width='80'] {
width: 80%;
}
[width='85'] {
width: 85%;
}
[width='90'] {
width: 90%;
}
[width='95'] {
width: 95%;
}
[width='100'] {
width: 100%;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment