diff --git a/_layouts/learning-pathway.html b/_layouts/learning-pathway.html index e2079e7d3a2d93..aedb9208b4b301 100644 --- a/_layouts/learning-pathway.html +++ b/_layouts/learning-pathway.html @@ -44,6 +44,23 @@

{{ section.section }}

{% if section.tutorials %} {% assign material_list = site | convert_to_material_list: section.tutorials %} +

{% icon time aria=false %} {{ locale['time-estimation'] | default: "Time estimation"}}: {{ material_list | sum_duration }}

+
+ Learning Objectives + +
{% include _includes/tutorial_list.html sub=material_list %} {% endif %} {% endfor %} diff --git a/_plugins/jekyll-duration.rb b/_plugins/jekyll-duration.rb index a0a1f8b225d309..315229d916c3a9 100644 --- a/_plugins/jekyll-duration.rb +++ b/_plugins/jekyll-duration.rb @@ -14,14 +14,15 @@ module DurationFilter # {{ "T1H30M" | duration_to_human }} # => "1 hour 30 minutes" def duration_to_human(duration) - # Match the different parts of the string, must match entire string or it will fail. - match = /^(?:([0-9]*)[Hh])*(?:([0-9]*)[Mm])*(?:([0-9.]*)[Ss])*$/.match(duration) - - # If it doesn't match, pass through unedited so we don't cause unexpected issues. - if match.nil? - puts "Could not parse time: #{duration}" + seconds = parse_rfc3339(duration) + if seconds.nil? return duration end + return fmt_duration(seconds) + end + + def fmt_duration(seconds) + d = resolve_hms(seconds) # Otherwise append english terms for the various parts duration_parts = [] @@ -37,22 +38,85 @@ def duration_to_human(duration) end # Hours - if !match[1].nil? - if match[1] == '1' - duration_parts.push("#{match[1]} " + hour) + if d[:hours] > 0 + if d[:hours] == 1 + duration_parts.push("#{d[:hours]} " + hour) else - duration_parts.push("#{match[1]} " + hours) + duration_parts.push("#{d[:hours]} " + hours) end end # Minutes - assuming no one uses `1 minute` - duration_parts.push("#{match[2]} " + minutes) if !match[2].nil? + duration_parts.push("#{d[:minutes]} " + minutes) if d[:minutes] > 0 # Hopefully no one uses seconds - duration_parts.push("#{match[3]} seconds") if !match[3].nil? + duration_parts.push("#{d[:seconds]} seconds") if d[:seconds] > 0 duration_parts.join(' ') end + + ## + # Sum the durations correctly for multiple RFC3339 formatted durations. + # Params: + # +s+:: The RFC3339 formatted duration string + # Returns: + # +d+:: a number of seconds + def parse_rfc3339(s) + if s == 0 + return 0 + end + + # Match the different parts of the string, must match entire string or it + # will fail. + match = /^T?(?:([0-9]*)[Hh])*(?:([0-9]*)[Mm])*(?:([0-9.]*)[Ss])*$/.match(s) + + # If it doesn't match, pass through unedited so we don't cause unexpected + # issues. + if match.nil? + Jekyll.logger.debug "[GTN/Durations]:", "Could not parse time: #{s}" + return nil + end + + return match[1].to_i * 3600 + match[2].to_i * 60 + match[3].to_i + end + + ## + # Turn a count of seconds into hours/minutes/seconds. + # Params: + # +Int+:: A number of seconds + # Returns: + # +Hash+:: A hash with keys for hours, minutes, and seconds + # + # Example: + # resolve_hms(5400) + # => { hours: 1, minutes: 30, seconds: 0 } + def resolve_hms(seconds) + # Normalize the total + minutes = seconds / 60 + seconds = seconds % 60 + hours = minutes / 60 + minutes = minutes % 60 + + { hours: hours, minutes: minutes, seconds: seconds } + end + + ## + # Sum the durations correctly for multiple RFC3339 formatted durations. + # Params: + # +materials+:: The GTN material objects + # Returns: + # +String+:: The human total duration + def sum_duration(materials) + Jekyll.logger.debug "[GTN/Durations]: sum durations with #{materials.length} materials." + total = 0 + materials.each do |material| + if ! material['time_estimation'].nil? + Jekyll.logger.debug " [GTN/Durations]: #{material['time_estimation']} #{material['title']} -> #{parse_rfc3339(material['time_estimation'])}" + total += parse_rfc3339(material['time_estimation']) + end + end + fmt_duration(total) + end end end diff --git a/bin/schema-learning-pathway.yaml b/bin/schema-learning-pathway.yaml index 5c18932b46f7de..75616a9c192135 100644 --- a/bin/schema-learning-pathway.yaml +++ b/bin/schema-learning-pathway.yaml @@ -107,6 +107,23 @@ mapping: required: true description: type: str + learning_objectives: + type: seq + sequence: + - type: str + required: true + description: | + List of Specific, Measurable, Achievable, Relevant, and Time-bound (SMART) learning objectives for the tutorial + + A learning objective is a single sentence describing what a learner will be able to do once they have done the tutorial. Generally it is best to follow a 2C or 3C learning objective such as: + + - Compute (Skill) + - multiple whole genome assemblies (Objective) + - in such a way to develop big data processing skills (Result) + _examples: + - Understand the basic concepts behind phylogenetic trees, as applied to *Mycobacterium tuberculosis* + - Explore Biodiversity data with taxonomic, temporal and geographical informations + - Generate a DotPlot emulating the original paper using a different analysis tool tutorials: type: seq sequence: diff --git a/bin/schema-tutorial.yaml b/bin/schema-tutorial.yaml index 8c618393fa12bc..53e4ebfc5d8bb5 100644 --- a/bin/schema-tutorial.yaml +++ b/bin/schema-tutorial.yaml @@ -35,7 +35,7 @@ mapping: - type: str required: true description: | - list of learning objectives for the tutorial + List of Specific, Measurable, Achievable, Relevant, and Time-bound (SMART) learning objectives for the tutorial A learning objective is a single sentence describing what a learner will be able to do once they have done the tutorial. Generally it is best to follow a 2C or 3C learning objective such as: