Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metrics Documentation and Statistics #388

Merged
merged 29 commits into from
Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1c9e222
Prototypes of metrics documentation and stats pages
colszowka Jan 16, 2019
2638ce0
Refactor numeric metric docs page into generic template, add a few more
colszowka Jan 16, 2019
7a8d769
Docs navigation prototype
colszowka Jan 17, 2019
1a1f3fa
Clean up metric chart into documented component
colszowka Jan 17, 2019
a7e2f7c
Break out docs title and hierarchy logic into a dedicated class
colszowka Jan 17, 2019
f829897
Incorporate remaining numeric metrics pages
colszowka Jan 17, 2019
daf6258
Add bar chart component and yearly grouped date stats helper
colszowka Jan 17, 2019
8a09b04
Add first release, latest release and average 50 commits docs pages w…
colszowka Jan 17, 2019
a6fde9c
Add basic docs pages rendering feature test and fail feature specs on…
colszowka Jan 17, 2019
d9b4aad
Clean up docs layout into common component
colszowka Jan 17, 2019
771f689
Rename numeric metric chart to line chart...
colszowka Jan 21, 2019
55dafd0
Drop obsolete method
colszowka Jan 21, 2019
71ea506
Break out component helpers into their own module
colszowka Jan 21, 2019
5696e1b
Break out stats helpers into their own method
colszowka Jan 21, 2019
f8c89b3
Break out (already kinda modular) project box into documented component
colszowka Jan 21, 2019
6a30569
Add navigation docs link and entry page
colszowka Jan 21, 2019
3475aff
Write up initial descriptions for all current metrics docs pages
colszowka Jan 21, 2019
a2400c1
position: sticky for docs sidebar
colszowka Jan 21, 2019
cb4726c
Trim date group stats to relevant years, there's some oddities in the…
colszowka Jan 21, 2019
b8f9bae
Crop leading zero value keys from percentile charts
colszowka Jan 22, 2019
997a998
Undo sticky sidebar, it's going to need scrolling soon...
colszowka Jan 22, 2019
7757b1c
Collapsible menu for docs on mobile
colszowka Jan 22, 2019
f2511b8
Add a little paragraph of text for docs intro
colszowka Jan 22, 2019
45a1fec
Begin a component for concise top project lists
colszowka Jan 22, 2019
5ed51b0
Clean up and adjust ranking lists for metrics docs pages
colszowka Jan 24, 2019
246cad2
Some minor docs UI tweaks
colszowka Jan 24, 2019
13bb18c
Introduce unified section heading component
colszowka Jan 24, 2019
eaacad4
Also link actual project metric values to corresponding docs pages
colszowka Jan 24, 2019
f78edac
Add hint regarding logarithmic scale, allow optional linear line char…
colszowka Jan 24, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Metrics/BlockLength:
- 'Guardfile'
- 'spec/**/*_examples.rb'
- 'spec/**/*_spec.rb'
- 'spec/rails_helper.rb'

# Big screens are common :)
Metrics/LineLength:
Expand Down
13 changes: 13 additions & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//
//= require rails-ujs
//= require turbolinks
//= require chart.js/dist/Chart.bundle.js
//= require headroom.js/dist/headroom
//= require_tree .

Expand Down Expand Up @@ -44,6 +45,18 @@ document.addEventListener("turbolinks:load", function () {
});
}

document.querySelectorAll('.documentation aside .toggle').forEach(function(toggle) {
toggle.addEventListener("click", function() {
this.parentNode.classList.toggle('is-active');
})
});

Chart.defaults.global.defaultFontFamily = 'Lato, "Helvetica Neue", Helvetica, Arial, sans-serif';
Chart.defaults.global.defaultFontSize = 12;
Chart.defaults.global.defaultFontStyle = "bold";
Chart.defaults.global.animation = 0;


document.querySelectorAll("form.search-form").forEach(function(form) {
form.addEventListener("submit", function() {
document.querySelectorAll("form.search-form button[type=submit]").forEach(function(button) {
Expand Down
45 changes: 45 additions & 0 deletions app/assets/javascripts/charts/bar_chart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
var barChart = function(selector, labels, values) {
var ctx = document.querySelector(selector)
.getContext('2d');

new Chart(ctx, {
type: "bar",
data: {
labels: labels,
datasets: [
{
data: values,
fill: true,
borderWidth: 0,
backgroundColor: "rgba(166,20,20,1)"
}
]
},
options: {
legend: {
display: false
},
tooltips: {
mode: "index",
intersect: false,
axis: "x"
},
scales: {
xAxes: [
{
gridLines : {
display : false
}
}
],
yAxes: [
{
ticks: {
beginAtZero: true,
}
}
]
}
}
});
}
52 changes: 52 additions & 0 deletions app/assets/javascripts/charts/line_chart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
var lineChart = function(selector, labels, values, scale = "logarithmic") {
var ctx = document.querySelector(selector)
.getContext('2d');

new Chart(ctx, {
type: "line",
data: {
labels: labels,
datasets: [
{
data: values,
fill: true,
lineTension: 0.2,
borderWidth: 5,
pointRadius: 1,
backgroundColor: "rgba(200,200,200,0.2)",
borderColor: "rgba(166,20,20,1)"
}
]
},
options: {
legend: {
display: false
},
tooltips: {
mode: "index",
intersect: false,
axis: "x"
},
scales: {
xAxes: [
{
gridLines : {
display : false
}
}
],
yAxes: [
{
type: scale,
ticks: {
beginAtZero: true,
callback: function(value, index) {
if (index % 8 == 0) { return value; }
}
}
}
]
}
}
});
}
30 changes: 3 additions & 27 deletions app/assets/stylesheets/application.css.sass
Original file line number Diff line number Diff line change
Expand Up @@ -148,36 +148,12 @@ footer.footer
@extend .is-size-4
padding: 0.75rem 0

.project
header
.score
@extend .is-size-5, .has-text-right

.description
@extend .has-text-grey
padding: 0.75rem

.metrics
@extend .columns, .is-multiline
display: flex
strong
@extend .is-size-5

.label
@extend .column, .is-2-tablet, .is-12-mobile
align-self: flex-end
margin-bottom: 0

.metric
@extend .column, .is-3-tablet, .is-6-mobile
// Align content to bottom
align-self: flex-end
strong
// Compensate for default icon padding in heading above
margin-left: 5px
.narrow-column
@extend .column, .content, .is-three-fifths-desktop, .is-offset-one-fifth-desktop

article.blog-post
@extend .column, .content, .is-three-fifths-desktop, .is-offset-one-fifth-desktop
@extend .narrow-column
font-size: 110%
line-height: 1.7
table, blockquote
Expand Down
15 changes: 15 additions & 0 deletions app/assets/stylesheets/components/documentation_page.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.documentation
@extend .columns, .is-multiline
aside
@extend .column, .is-one-quarter-desktop, .is-full
.toggle
@extend .is-hidden-desktop, .button, .is-fullwidth
margin-bottom: 20px
.menu
@extend .is-hidden-touch

&.is-active
.menu
@extend .is-block-touch
.toggle
@extend .is-outlined, .is-primary
40 changes: 40 additions & 0 deletions app/assets/stylesheets/components/project.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.project
header
.score
@extend .is-size-5, .has-text-right

.description
@extend .has-text-grey
padding: 0.75rem

.metrics
@extend .columns, .is-multiline
display: flex
strong
@extend .is-size-5

.label
@extend .column, .is-2-tablet, .is-12-mobile
align-self: flex-end
margin-bottom: 0

.metric
@extend .column, .is-3-tablet, .is-6-mobile
// Align content to bottom
align-self: flex-end
strong
// Compensate for default icon padding in heading above
margin-left: 5px
a
color: $black-ter

.heading
a
color: $grey-darker

.project-links
a.button
transition: color 100ms linear

&:hover
color: $primary
9 changes: 9 additions & 0 deletions app/assets/stylesheets/components/project_list.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.project-list
section
> .level
padding: 0.5rem 0
margin: 0
border-bottom: 1px solid $white-ter

&:last-child
border: none
12 changes: 12 additions & 0 deletions app/assets/stylesheets/components/section_heading.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.section-heading
margin-bottom: 1.5rem

.level
margin: 0

.content, .content strong
color: $grey-dark

.level-right
.button
@extend .is-primary, .is-outlined
120 changes: 57 additions & 63 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# frozen_string_literal: true

module ApplicationHelper
include ComponentHelpers
include StatsHelpers

def metric_icon(metric)
"fa-" + t(:icon, scope: "metrics.#{metric}")
end
Expand All @@ -9,18 +12,62 @@ def metric_label(metric)
t(:label, scope: "metrics.#{metric}")
end

def project_metrics(project, *metrics)
metrics.map do |metric|
render partial: "projects/metric", locals: {
label: metric_label(metric),
value: project.public_send(metric),
icon: metric_icon(metric),
}
end.inject(&:+)
# This should be refactored...
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def pretty_metric_value(value)
if value.is_a?(Float) || value.is_a?(BigDecimal)
number_with_delimiter(value.floor) + "%"
elsif value.is_a? Integer
number_with_delimiter value
elsif value.is_a?(Date) || value.is_a?(Time)
content_tag "time", "#{time_ago_in_words(value)} ago", datetime: value.iso8601, title: l(value)
elsif value.is_a? Array
value.to_sentence
else
value
end
end
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

def project_link(label, url, icon:)
render partial: "projects/link", locals: { label: label, url: url, icon: icon }
#
# A little utility method for displaying project rankings like most downloaded gems
# in metrics docs pages without too much repetition of in-view logic
#
# rubocop:disable Metrics/ParameterLists It's not great but I'm ok with it here
def project_ranking(title, scope: Project.for_display, table:, column:, direction: "DESC", description: nil)
projects = scope.order("#{table}.#{column} #{direction} NULLS LAST").limit(100)
metrics = if table == :github_repos
["github_repo_stargazers_count", "github_repo_#{column}"].uniq
else
["rubygem_downloads", "rubygem_#{column}"].uniq
end

project_list projects, title: title, metrics: metrics, description: description
end
# rubocop:enable Metrics/ParameterLists

def docs
@docs ||= Docs.new
end

def link_to_docs_if_exists(page, &block)
content = capture(&block)

if docs.find page
link_to content, page_path(page)
else
content
end
end

# Render given text as markdown. Do not use this with unsafe
# inputs as it does not use any blacklisting or sanitization!
def markdown(text)
Redcarpet::Markdown.new(
Redcarpet::Render::HTML,
autolink: true,
tables: true
).render(text).html_safe # rubocop:disable Rails/OutputSafety
end

# why
Expand Down Expand Up @@ -60,60 +107,7 @@ def description
content_for(:description).presence || t(:description)
end

DISTANCES = {
1.week => "within last week",
2.weeks => "within last two weeks",
1.month => "within last month",
3.months => "within last 3 months",
1.year => "within last year",
2.years => "within last 2 years",
}.freeze

def recent_distance_in_words(time)
return if time.blank?

matching_distance = DISTANCES.find do |distance, _label|
time >= distance.ago
end

matching_distance&.last || "more than 2 years ago"
end

def active_when(controller:)
"is-active" if controller_name == controller.to_s
end

def category_card(category, compact: false, inline: false)
extra_classes = inline ? %w[inline] : []
locals = {
category: category,
compact: compact,
extra_classes: extra_classes,
}
render partial: "components/category_card", locals: locals
end

def project_health_tags(project)
render "components/project_health_tags", project: project
end

def project_health_tag(health_status)
render "components/project_health_tag", status: health_status
end

def project_order_dropdown(order)
render "components/project_order_dropdown", order: order
end

def landing_hero(title:, image:, &block)
render "components/landing_hero", title: title, image: image, &block
end

def landing_feature(title:, image:, &block)
render "components/landing_feature", title: title, image: image, &block
end

def component_example(heading, &block)
render "components/component_example", heading: heading, &block
end
end
Loading