From 477d975a6786c00b642fe273e36061a94c39225b Mon Sep 17 00:00:00 2001 From: Jeff Stubler Date: Sun, 30 Oct 2016 16:41:13 -0500 Subject: [PATCH] Add blame view age map --- app/assets/stylesheets/framework/files.scss | 50 ++++++++++++++++ .../stylesheets/framework/variables.scss | 7 +++ app/helpers/blame_helper.rb | 21 +++++++ .../projects/blame/_age_map_legend.html.haml | 12 ++++ app/views/projects/blame/show.html.haml | 8 ++- changelogs/unreleased/23998-blame-age-map.yml | 4 ++ spec/helpers/blame_helper_spec.rb | 59 +++++++++++++++++++ 7 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 app/helpers/blame_helper.rb create mode 100644 app/views/projects/blame/_age_map_legend.html.haml create mode 100644 changelogs/unreleased/23998-blame-age-map.yml create mode 100644 spec/helpers/blame_helper_spec.rb diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index d08df05fd6c..b26d8fbd5fe 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -59,6 +59,43 @@ } } + .file-blame-legend { + background-color: $gray-light; + text-align: right; + padding: 8px $gl-padding; + + @media (max-width: $screen-xs-max) { + text-align: left; + } + + .left-label { + padding-right: 5px; + } + + .right-label { + padding-left: 5px; + } + + .legend-box { + display: inline-block; + width: 10px; + height: 10px; + padding: 0 2px; + } + + @for $i from 0 through 5 { + .legend-box-#{$i} { + background-color: mix($blame-cyan, $blame-blue, $i / 5.0 * 100%); + } + } + + @for $i from 1 through 4 { + .legend-box-#{$i + 5} { + background-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%); + } + } + } + .file-content { background: $white-light; @@ -118,6 +155,19 @@ padding: 5px 10px; min-width: 400px; background: $gray-light; + border-left: 3px solid; + } + + @for $i from 0 through 5 { + td.blame-commit-age-#{$i} { + border-left-color: mix($blame-cyan, $blame-blue, $i / 5.0 * 100%); + } + } + + @for $i from 1 through 4 { + td.blame-commit-age-#{$i + 5} { + border-left-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%); + } } td.line-numbers { diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 4114a050d9a..49ba0108228 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -364,6 +364,13 @@ $avatar_radius: 50%; $avatar-border: rgba(0, 0, 0, .1); $gl-avatar-size: 40px; +/* +* Blame +*/ +$blame-gray: #ededed; +$blame-cyan: #acd5f2; +$blame-blue: #254e77; + /* * Builds */ diff --git a/app/helpers/blame_helper.rb b/app/helpers/blame_helper.rb new file mode 100644 index 00000000000..d1dc4d94560 --- /dev/null +++ b/app/helpers/blame_helper.rb @@ -0,0 +1,21 @@ +module BlameHelper + def age_map_duration(blame_groups, project) + now = Time.zone.now + start_date = blame_groups.map { |blame_group| blame_group[:commit].committed_date } + .append(project.created_at).min + + { + now: now, + started_days_ago: (now - start_date).to_i / 1.day + } + end + + def age_map_class(commit_date, duration) + commit_date_days_ago = (duration[:now] - commit_date).to_i / 1.day + # Numbers 0 to 10 come from this calculation, but only commits on the oldest + # day get number 10 (all other numbers can be multiple days), so the range + # is normalized to 0-9 + age_group = [(10 * commit_date_days_ago) / duration[:started_days_ago], 9].min + "blame-commit-age-#{age_group}" + end +end diff --git a/app/views/projects/blame/_age_map_legend.html.haml b/app/views/projects/blame/_age_map_legend.html.haml new file mode 100644 index 00000000000..533dc20ffb3 --- /dev/null +++ b/app/views/projects/blame/_age_map_legend.html.haml @@ -0,0 +1,12 @@ +%span.left-label Newer +%span.legend-box.legend-box-0 +%span.legend-box.legend-box-1 +%span.legend-box.legend-box-2 +%span.legend-box.legend-box-3 +%span.legend-box.legend-box-4 +%span.legend-box.legend-box-5 +%span.legend-box.legend-box-6 +%span.legend-box.legend-box-7 +%span.legend-box.legend-box-8 +%span.legend-box.legend-box-9 +%span.right-label Older diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml index a6ee2b2f7b8..ce937ee1842 100644 --- a/app/views/projects/blame/show.html.haml +++ b/app/views/projects/blame/show.html.haml @@ -1,4 +1,5 @@ - @no_container = true +- project_duration = age_map_duration(@blame_groups, @project) - page_title "Annotate", @blob.path, @ref = render "projects/commits/head" @@ -8,15 +9,16 @@ .file-holder = render "projects/blob/header", blob: @blob, blame: true - + .file-blame-legend + = render 'age_map_legend' .table-responsive.file-content.blame.code.js-syntax-highlight %table - current_line = 1 - @blame_groups.each do |blame_group| %tr - %td.blame-commit + - commit = blame_group[:commit] + %td.blame-commit{ class: age_map_class(commit.committed_date, project_duration) } .commit - - commit = blame_group[:commit] = author_avatar(commit, size: 36) .commit-row-title %strong diff --git a/changelogs/unreleased/23998-blame-age-map.yml b/changelogs/unreleased/23998-blame-age-map.yml new file mode 100644 index 00000000000..26a38f0939c --- /dev/null +++ b/changelogs/unreleased/23998-blame-age-map.yml @@ -0,0 +1,4 @@ +--- +title: Add blame view age mapping +merge_request: 7198 +author: Jeff Stubler diff --git a/spec/helpers/blame_helper_spec.rb b/spec/helpers/blame_helper_spec.rb new file mode 100644 index 00000000000..b4368516d83 --- /dev/null +++ b/spec/helpers/blame_helper_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe BlameHelper do + describe '#get_age_map_start_date' do + let(:dates) do + [Time.zone.local(2014, 3, 17, 0, 0, 0), + Time.zone.local(2011, 11, 2, 0, 0, 0), + Time.zone.local(2015, 7, 9, 0, 0, 0), + Time.zone.local(2013, 2, 24, 0, 0, 0), + Time.zone.local(2010, 9, 22, 0, 0, 0)] + end + let(:blame_groups) do + [ + { commit: double(committed_date: dates[0]) }, + { commit: double(committed_date: dates[1]) }, + { commit: double(committed_date: dates[2]) } + ] + end + + it 'returns the earliest date from a blame group' do + project = double(created_at: dates[3]) + + duration = helper.age_map_duration(blame_groups, project) + + expect(duration[:started_days_ago]).to eq((duration[:now] - dates[1]).to_i / 1.day) + end + + it 'returns the earliest date from a project' do + project = double(created_at: dates[4]) + + duration = helper.age_map_duration(blame_groups, project) + + expect(duration[:started_days_ago]).to eq((duration[:now] - dates[4]).to_i / 1.day) + end + end + + describe '#age_map_class' do + let(:dates) do + [Time.zone.local(2014, 3, 17, 0, 0, 0)] + end + let(:blame_groups) do + [ + { commit: double(committed_date: dates[0]) } + ] + end + let(:duration) do + project = double(created_at: dates[0]) + helper.age_map_duration(blame_groups, project) + end + + it 'returns blame-commit-age-9 when oldest' do + expect(helper.age_map_class(dates[0], duration)).to eq 'blame-commit-age-9' + end + + it 'returns blame-commit-age-0 class when newest' do + expect(helper.age_map_class(duration[:now], duration)).to eq 'blame-commit-age-0' + end + end +end