Commit 3d009f77 authored by Jacob Schatz's avatar Jacob Schatz

Merge branch 'updated-contrib-calendar' into 'master'

POC: Updated contrib calendar

In an effort to cut down the JS file size - i've removed the heatmap calendar used for the contributing calendar on users profiles. We already have d3 on the page so why not use it instead of using a library which uses it?

![Screen_Shot_2016-04-27_at_11.08.41](/uploads/64c40f0c766f800fd0e33ac8be7f9644/Screen_Shot_2016-04-27_at_11.08.41.png)

cc. @jschatz1 

See merge request !3944
parents 4b4cda85 527d6446
...@@ -178,9 +178,6 @@ gem 'ruby-fogbugz', '~> 0.2.1' ...@@ -178,9 +178,6 @@ gem 'ruby-fogbugz', '~> 0.2.1'
# d3 # d3
gem 'd3_rails', '~> 3.5.0' gem 'd3_rails', '~> 3.5.0'
#cal-heatmap
gem 'cal-heatmap-rails', '~> 3.6.0'
# underscore-rails # underscore-rails
gem "underscore-rails", "~> 1.8.0" gem "underscore-rails", "~> 1.8.0"
......
...@@ -102,7 +102,6 @@ GEM ...@@ -102,7 +102,6 @@ GEM
bundler (~> 1.2) bundler (~> 1.2)
thor (~> 0.18) thor (~> 0.18)
byebug (8.2.1) byebug (8.2.1)
cal-heatmap-rails (3.6.0)
capybara (2.6.2) capybara (2.6.2)
addressable addressable
mime-types (>= 1.16) mime-types (>= 1.16)
...@@ -908,7 +907,6 @@ DEPENDENCIES ...@@ -908,7 +907,6 @@ DEPENDENCIES
bullet bullet
bundler-audit bundler-audit
byebug byebug
cal-heatmap-rails (~> 3.6.0)
capybara (~> 2.6.2) capybara (~> 2.6.2)
capybara-screenshot (~> 1.0.0) capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.10.0) carrierwave (~> 0.10.0)
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#= require jquery.scrollTo #= require jquery.scrollTo
#= require jquery.turbolinks #= require jquery.turbolinks
#= require d3 #= require d3
#= require cal-heatmap
#= require turbolinks #= require turbolinks
#= require autosave #= require autosave
#= require bootstrap/affix #= require bootstrap/affix
......
class @Calendar class @Calendar
constructor: (timestamps, starting_year, starting_month, calendar_activities_path) -> constructor: (timestamps, @calendar_activities_path) ->
cal = new CalHeatMap() @currentSelectedDate = ''
cal.init @daySpace = 1
itemName: ["contribution"] @daySize = 15
data: timestamps @daySizeWithSpace = @daySize + (@daySpace * 2)
start: new Date(starting_year, starting_month) @monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
domainLabelFormat: "%b" @months = []
id: "cal-heatmap" @highestValue = 0
domain: "month"
subDomain: "day"
range: 12
tooltip: true
label:
position: "top"
legend: [
0
10
20
30
]
legendCellPadding: 3
cellSize: $('.user-calendar').width() / 73
onClick: (date, count) ->
formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
$.ajax
url: calendar_activities_path
data:
date: formated_date
cache: false
dataType: "html"
success: (data) ->
$(".user-calendar-activities").html data
# Get the highest value from the timestampes
_.each timestamps, (count) =>
if count > @highestValue
@highestValue = count
# Loop through the timestamps to create a group of objects
# The group of objects will be grouped based on the day of the week they are
@timestampsTmp = []
i = 0
group = 0
_.each timestamps, (count, date) =>
newDate = new Date parseInt(date) * 1000
day = newDate.getDay()
# Create a new group array if this is the first day of the week
# or if is first object
if (day is 0 and i isnt 0) or i is 0
@timestampsTmp.push []
group++
innerArray = @timestampsTmp[group-1]
# Push to the inner array the values that will be used to render map
innerArray.push
count: count
date: newDate
day: day
i++
# Init color functions
@color = @initColor()
@colorKey = @initColorKey()
# Init the svg element
@renderSvg(group)
@renderDays()
@renderMonths()
@renderDayTitles()
@renderKey()
@initTooltips()
renderSvg: (group) ->
@svg = d3.select '.js-contrib-calendar'
.append 'svg'
.attr 'width', (group + 1) * @daySizeWithSpace
.attr 'height', 167
.attr 'class', 'contrib-calendar'
renderDays: ->
@svg.selectAll 'g'
.data @timestampsTmp
.enter()
.append 'g'
.attr 'transform', (group, i) =>
_.each group, (stamp, a) =>
if a is 0 and stamp.day is 0
month = stamp.date.getMonth()
x = (@daySizeWithSpace * i + 1) + @daySizeWithSpace
lastMonth = _.last(@months)
if lastMonth?
lastMonthX = lastMonth.x
if !lastMonth?
@months.push
month: month
x: x
else if month isnt lastMonth.month and x - @daySizeWithSpace isnt lastMonthX
@months.push
month: month
x: x
"translate(#{(@daySizeWithSpace * i + 1) + @daySizeWithSpace}, 18)"
.selectAll 'rect'
.data (stamp) ->
stamp
.enter()
.append 'rect'
.attr 'x', '0'
.attr 'y', (stamp, i) =>
(@daySizeWithSpace * stamp.day)
.attr 'width', @daySize
.attr 'height', @daySize
.attr 'title', (stamp) =>
contribText = 'No contributions'
if stamp.count > 0
contribText = "#{stamp.count} contribution#{if stamp.count > 1 then 's' else ''}"
date = dateFormat(stamp.date, 'mmm d, yyyy')
"#{contribText}<br />#{date}"
.attr 'class', 'user-contrib-cell js-tooltip'
.attr 'fill', (stamp) =>
if stamp.count isnt 0
@color(stamp.count)
else
'#ededed'
.attr 'data-container', 'body'
.on 'click', @clickDay
renderDayTitles: ->
days = [{
text: 'M'
y: 29 + (@daySizeWithSpace * 1)
}, {
text: 'W'
y: 29 + (@daySizeWithSpace * 3)
}, {
text: 'F'
y: 29 + (@daySizeWithSpace * 5)
}]
@svg.append 'g'
.selectAll 'text'
.data days
.enter()
.append 'text'
.attr 'text-anchor', 'middle'
.attr 'x', 8
.attr 'y', (day) ->
day.y
.text (day) ->
day.text
.attr 'class', 'user-contrib-text'
renderMonths: ->
@svg.append 'g'
.selectAll 'text'
.data @months
.enter()
.append 'text'
.attr 'x', (date) ->
date.x
.attr 'y', 10
.attr 'class', 'user-contrib-text'
.text (date) =>
@monthNames[date.month]
renderKey: ->
keyColors = ['#ededed', @colorKey(0), @colorKey(1), @colorKey(2), @colorKey(3)]
@svg.append 'g'
.attr 'transform', "translate(18, #{@daySizeWithSpace * 8 + 16})"
.selectAll 'rect'
.data keyColors
.enter()
.append 'rect'
.attr 'width', @daySize
.attr 'height', @daySize
.attr 'x', (color, i) =>
@daySizeWithSpace * i
.attr 'y', 0
.attr 'fill', (color) ->
color
initColor: ->
d3.scale
.linear()
.range(['#acd5f2', '#254e77'])
.domain([0, @highestValue])
initColorKey: ->
d3.scale
.linear()
.range(['#acd5f2', '#254e77'])
.domain([0, 3])
clickDay: (stamp) ->
if @currentSelectedDate isnt stamp.date
@currentSelectedDate = stamp.date
formatted_date = @currentSelectedDate.getFullYear() + "-" + (@currentSelectedDate.getMonth()+1) + "-" + @currentSelectedDate.getDate()
$.ajax
url: @calendar_activities_path
data:
date: formatted_date
cache: false
dataType: 'html'
beforeSend: ->
$('.user-calendar-activities').html '<div class="text-center"><i class="fa fa-spinner fa-spin user-calendar-activities-loading"></i></div>'
success: (data) ->
$('.user-calendar-activities').html data
else
$('.user-calendar-activities').html ''
initTooltips: ->
$('.js-contrib-calendar .js-tooltip').tooltip
html: true
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
*= require select2 *= require select2
*= require_self *= require_self
*= require dropzone/basic *= require dropzone/basic
*= require cal-heatmap
*= require cropper.css *= require cropper.css
*/ */
......
.calender-block { .calender-block {
padding-left: 0;
padding-right: 0;
@media (min-width: $screen-sm-min) and (max-width: $screen-lg-min) { @media (min-width: $screen-sm-min) and (max-width: $screen-lg-min) {
overflow-x: scroll; overflow-x: scroll;
} }
} }
.user-calendar-activities { .user-calendar-activities {
.calendar_onclick_hr {
padding: 0;
margin: 10px 0;
}
.str-truncated { .str-truncated {
max-width: 70%; max-width: 70%;
} }
.text-expander { .user-calendar-activities-loading {
background: #eee; font-size: 24px;
color: #555;
padding: 0 5px;
cursor: pointer;
margin-left: 4px;
&:hover {
background-color: #ddd;
}
} }
} }
/** .user-calendar {
* This overwrites the default values of the cal-heatmap gem text-align: center;
*/
.calendar {
.qi {
fill: #fff;
}
.q1 {
fill: #ededed !important;
}
.q2 { .calendar {
fill: #acd5f2 !important; display: inline-block;
}
.q3 {
fill: #7fa8d1 !important;
}
.q4 {
fill: #49729b !important;
}
.q5 {
fill: #254e77 !important;
} }
}
.future { .user-contrib-cell {
visibility: hidden; &:hover {
cursor: pointer;
stroke: #000;
} }
}
.domain-background { .user-contrib-text {
fill: none; font-size: 12px;
shape-rendering: crispedges; fill: #959494;
} }
.ch-tooltip { .calendar-hint {
padding: 3px; margin-top: -23px;
font-weight: 550; float: right;
} font-size: 12px;
} }
...@@ -66,12 +66,6 @@ ...@@ -66,12 +66,6 @@
} }
} }
.calendar-hint {
margin-top: -12px;
float: right;
font-size: 12px;
}
.profile-link-holder { .profile-link-holder {
display: inline; display: inline;
......
...@@ -74,8 +74,6 @@ class UsersController < ApplicationController ...@@ -74,8 +74,6 @@ class UsersController < ApplicationController
def calendar def calendar
calendar = contributions_calendar calendar = contributions_calendar
@timestamps = calendar.timestamps @timestamps = calendar.timestamps
@starting_year = calendar.starting_year
@starting_month = calendar.starting_month
render 'calendar', layout: false render 'calendar', layout: false
end end
......
#cal-heatmap.calendar .clearfix.calendar
:javascript .js-contrib-calendar
new Calendar( .calendar-hint
#{@timestamps.to_json}, Summary of issues, merge requests, and push events
#{@starting_year}, :javascript
#{@starting_month}, new Calendar(
'#{user_calendar_activities_path}' #{@timestamps.to_json},
); '#{user_calendar_activities_path}'
);
.calendar-hint Summary of issues, merge requests, and push events
%h4.prepend-top-20 %h4.prepend-top-20
%span.light Contributions for Contributions for
%strong #{@calendar_date.to_s(:short)} %strong #{@calendar_date.to_s(:short)}
%ul.bordered-list - if @events.any?
- @events.sort_by(&:created_at).each do |event| %ul.bordered-list
%li - @events.sort_by(&:created_at).each do |event|
%span.light %li
%i.fa.fa-clock-o %span.light
= event.created_at.to_s(:time) %i.fa.fa-clock-o
- if event.push? = event.created_at.to_s(:time)
#{event.action_name} #{event.ref_type} #{event.ref_name} - if event.push?
- else #{event.action_name} #{event.ref_type} #{event.ref_name}
= event_action_name(event)
- if event.target
%strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
at
%strong
- if event.project
= link_to_project event.project
- else - else
= event.project_name = event_action_name(event)
- if event.target
%strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
at
%strong
- if event.project
= link_to_project event.project
- else
= event.project_name
- else
%p
No contributions found for #{@calendar_date.to_s(:short)}
...@@ -89,10 +89,9 @@ ...@@ -89,10 +89,9 @@
.tab-content .tab-content
#activity.tab-pane #activity.tab-pane
.row-content-block.calender-block.white.second-block.hidden-xs .row-content-block.calender-block.white.second-block.hidden-xs
%div{ class: container_class } .user-calendar{data: {href: user_calendar_path}}
.user-calendar{data: {href: user_calendar_path}} %h4.center.light
%h4.center.light %i.fa.fa-spinner.fa-spin
%i.fa.fa-spinner.fa-spin
.user-calendar-activities .user-calendar-activities
.content_list{ data: {href: user_path} } .content_list{ data: {href: user_path} }
......
...@@ -34,7 +34,7 @@ class Spinach::Features::User < Spinach::FeatureSteps ...@@ -34,7 +34,7 @@ class Spinach::Features::User < Spinach::FeatureSteps
end end
step 'I should see contributions calendar' do step 'I should see contributions calendar' do
expect(page).to have_css('.cal-heatmap-container') expect(page).to have_css('.js-contrib-calendar')
end end
def contributed_project def contributed_project
......
...@@ -19,7 +19,7 @@ module Gitlab ...@@ -19,7 +19,7 @@ module Gitlab
select('date(created_at) as date, count(id) as total_amount'). select('date(created_at) as date, count(id) as total_amount').
map(&:attributes) map(&:attributes)
dates = (1.year.ago.to_date..(Date.today + 1.day)).to_a dates = (1.year.ago.to_date..Date.today).to_a
dates.each do |date| dates.each do |date|
date_id = date.to_time.to_i.to_s date_id = date.to_time.to_i.to_s
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment