diff options
| author | Luc Donnet | 2018-02-02 16:00:39 +0100 |
|---|---|---|
| committer | GitHub | 2018-02-02 16:00:39 +0100 |
| commit | 5f240b2ceea25c13b054baaea6aa5cdc982793cf (patch) | |
| tree | fdd66161ec12034b5d0eeed634a80d105e52c94b | |
| parent | 9f30b2debe7ece403d9e588df9763c119436d967 (diff) | |
| parent | c086dded51711e0bd1ec852196cf66ea35a7e2b8 (diff) | |
| download | chouette-core-5f240b2ceea25c13b054baaea6aa5cdc982793cf.tar.bz2 | |
Merge pull request #250 from af83/3542-referential-overview
3542 referential overview
| -rw-r--r-- | app/assets/stylesheets/base/_config.sass | 1 | ||||
| -rw-r--r-- | app/assets/stylesheets/base/_utilities.sass | 2 | ||||
| -rw-r--r-- | app/assets/stylesheets/components/_referential_overview.sass | 346 | ||||
| -rw-r--r-- | app/helpers/pagination_helper.rb | 2 | ||||
| -rw-r--r-- | app/helpers/referentials_helper.rb | 5 | ||||
| -rw-r--r-- | app/javascript/packs/referential_overview/overview.js | 1 | ||||
| -rw-r--r-- | app/javascript/referential_overview/index.coffee | 113 | ||||
| -rw-r--r-- | app/services/referential_overview.rb | 256 | ||||
| -rw-r--r-- | app/views/merges/show.html.slim | 3 | ||||
| -rw-r--r-- | app/views/referentials/_overview.html.slim | 75 | ||||
| -rw-r--r-- | app/views/referentials/show.html.slim | 2 | ||||
| -rw-r--r-- | config/locales/referentials.en.yml | 8 | ||||
| -rw-r--r-- | config/locales/referentials.fr.yml | 8 | ||||
| -rw-r--r-- | spec/services/referential_overview_spec.rb | 154 |
14 files changed, 974 insertions, 2 deletions
diff --git a/app/assets/stylesheets/base/_config.sass b/app/assets/stylesheets/base/_config.sass index 2c226357f..0fff1dd9c 100644 --- a/app/assets/stylesheets/base/_config.sass +++ b/app/assets/stylesheets/base/_config.sass @@ -17,6 +17,7 @@ $blue: #007fbb $darkgrey: #4b4b4b $grey: #a4a4a4 $lightgrey: lighten($grey, 25) +$lightergrey: lighten($lightgrey,5) $green: #70b12b $red: #da2f36 diff --git a/app/assets/stylesheets/base/_utilities.sass b/app/assets/stylesheets/base/_utilities.sass index 24f2038f0..fbda5630d 100644 --- a/app/assets/stylesheets/base/_utilities.sass +++ b/app/assets/stylesheets/base/_utilities.sass @@ -44,7 +44,7 @@ // Empty zones =emptyzone($col1, $col2) - background-image: linear-gradient(-45deg, $col1 25%, $col2 25%, $col2 50%, $col1 50%, $col1 75%, $col2 75%, transparent) + background-image: linear-gradient(-45deg, $col1 25%, $col2 25%, $col2 50%, $col1 50%, $col1 75%, $col2 75%, $col2) background-size: 40px 40px .cellwrap diff --git a/app/assets/stylesheets/components/_referential_overview.sass b/app/assets/stylesheets/components/_referential_overview.sass new file mode 100644 index 000000000..0beb8ab67 --- /dev/null +++ b/app/assets/stylesheets/components/_referential_overview.sass @@ -0,0 +1,346 @@ +.referential-overview + $left-size: 100px + $line-height: 60px + margin-top: 50px + overflow: hidden + .time-travel, .filters + background-color: $lightergrey + padding: 10px + float: right + border-top-left-radius: 4px + border-top-right-radius: 4px + border: 1px solid $lightgrey + border-bottom: none + position: relative + &:after + position: absolute + content: "" + left: 0 + top: 100% + right: 0 + height: 10px + box-shadow: 0 0 10px rgba(0,0,0,0.5) + z-index: 1 + .time-travel + padding-top: 4px + padding-bottom: 4px + a.btn:first-child + margin-right: 1px + a.btn:last-child + margin-right: 1px + + max-width: 33% + .btn-group, .form-group + position: relative + z-index: 2 + .form-group + margin-left: 10px + margin-bottom: 0 + display: inline-block + input + padding: 6px 5px + border: 1px solid $lightgrey + outline: none + height: 34px + border-radius: 4px + padding-right: 25px + a + padding: 4px + margin-top: 2px + margin-left: -25px + .filters + float: left + max-width: 66% + padding: 0 + form + background: transparent + display: flex + .ffg-row + border-color: $grey + .form-group + border-color: $grey + width: auto + flex: 1 1 + padding: 4px 11px 5px + .input-group-btn + right: 10px + &.togglable + padding-top: 6px + padding-bottom: 5px + &:before + top: 0px + + .overview-table + position: relative + z-index: 2 + border: 1px solid $grey + clear: both + display: flex + +emptyzone($lightgrey, $lightergrey) + .head + + height: $left-size + .line + height: $line-height + .left + flex: 0 0 + background: $lightergrey + min-width: $left-size + overflow: hidden + border-right: 1px solid white + .head + position: relative + border-bottom: 1px solid $grey + border-right: 1px solid $lightgrey + .dates, .lines + position: absolute + font-size: 0.8em + z-index: 2 + .dates + right: 20px + top: 20px + .lines + left: 20px + bottom: 20px + &:after + position: absolute + border-left: ($left-size - 2px)/2 solid transparent + border-bottom: ($left-size - 2px)/2 solid transparent + border-right: ($left-size - 2px)/2 solid white + border-top: ($left-size - 2px)/2 solid white + z-index: 1 + top: 0 + right: 0 + width: 0 + content: "" + .line + padding: 7px 10px + border-bottom: 1px solid $grey + font-size: 0.8em + &:last-child + border-bottom: none + .number + border-radius: 100px + display: inline-block + min-width: 20px + height: 20px + text-align: center + padding: 1px 4px + text-decoration: none + color: black + border: 1px solid $grey + max-width: 100% + white-space: nowrap + text-overflow: ellipsis + overflow: hidden + .name + display: inline-block + width: $left-size - 50px() + white-space: nowrap + line-height: 20px + margin-left: 5px + text-overflow: ellipsis + overflow: hidden + vertical-align: bottom + color: black + text-decoration: none + + .company, .mode + font-size: 0.9em + white-space: nowrap + text-overflow: ellipsis + overflow: hidden + margin-top: -2px + .mode + text-transform: uppercase + color: $grey + font-weight: bold + .right + flex: 1 1 + overflow: hidden + .inner .lines + transition: margin-left 0.5s + .head + white-space: nowrap + position: relative + z-index: 3 + &:after, &:before + opacity: 0 + // transition: opacity 0.5s + content: "" + position: absolute + left: -1000px + right: 100% + top: 0px + bottom: 0 + background: $darkblue + z-index: 11 + border-top: 1px solid white + .week + display: inline-block + position: relative + height: 100% + transition: margin 0.5s + background: white + &:last-child + box-shadow: 0 -10px 10px rgba(0,0,0,0.5) + .week-span + left: 15px + top: 15px + right: 30px + white-space: nowrap + overflow: hidden + text-overflow: ellipsis + position: absolute + + .week-number + background-color: $lightgrey + color: $grey + position: absolute + top: 0 + right: 0 + padding: 2px 4px + + &:after + position: absolute + right: 0 + top: 0 + bottom: 0 + background: $grey + width: 1px + content: "" + + &:last-child:after + display: none + + .days + position: relative + top: 50% + height: 50% + border-top: 1px solid $grey + border-bottom: 1px solid $grey + + .day + float: left + border-left: 1px solid $grey + box-sizing: border-box + padding-left: 5px + padding-top: 3px + position: relative + height: 100% + .name, .number + position: absolute + left: 10px + right: 10px + top: 50% + transform: translateY(-50%) + margin-top: 10px + .name + font-weight: bold + font-size: 0.8em + margin-top: -10px + &:first-child + border: none + &.weekend + background: $lightergrey + &.selected, &:hover + color: $blue + background-color: transparentize($blue, 0.7) + &:after + content: "" + left: -1px + right: -1px + top: 100% + height: 10000px + background-color: transparentize($blue, 0.7) + position: absolute + z-index: 4 + &:hover + background-color: transparentize(white, 0.7) + &:after + background-color: transparentize(white, 0.7) + + .line + border-bottom: 1px solid $grey + position: relative + overflow: hidden + box-shadow: 0 -10px 10px rgba(0,0,0,0.5) + + &:last-child + border-bottom: none + + .period + height: 100% + top: 0 + background: #aedd8a + position: absolute + box-shadow: 0 0 10px rgba(0,0,0,0.5) + z-index: 2 + .title + position: absolute + left: 12px + top: 50% + margin-top: -6px + transform: translateY(-50%) + background-color: transparentize(white, 0.25) + padding: 5px + font-size: 0.7em + border-radius: 5px + transition: margin-left 0.5s + max-width: calc(100% - 24px) + margin-right: 12px + &:after + content: "" + position: absolute + bottom: 1px + left: 0 + right: 0 + height: 10px + background: white + opacity: 0.25 + z-index: 3 + &.empty + z-index: 1 + background: rgb(244, 67, 67) + background: repeating-linear-gradient(-45deg, #f5e1cf,#f5e1cf 12px,#e49393 12px,#e49393 25px) + &.accepted + background: #f19039 + background: repeating-linear-gradient(-45deg, #f5e1cf,#f5e1cf 12px,#f19039 12px,#f19039 25px) + &:hover + z-index: 3 + &:after + opacity: 0.5 + .title + background-color: transparentize(white, 0.1) + + &.sticky + .time-travel + position: fixed + bottom: 0 + z-index: 15 + right: 35px + box-shadow: 0 0 10px rgba(0,0,0,0.5) + + .overview-table .right + .lines + margin-top: $left-size + .head + position: fixed + top: 80px + z-index: 10 + background: white + height: 50px + right: 51px + left: 51px + $left-size + // overflow-x: hidden + &:after, &:before + opacity: 1 + &:after + left: 100% + right: -1000px + .week-span, .week-number + display: none + .days + height: 100% + top: 0 + border-top: 1px solid white diff --git a/app/helpers/pagination_helper.rb b/app/helpers/pagination_helper.rb index 02eec39dc..9b6042377 100644 --- a/app/helpers/pagination_helper.rb +++ b/app/helpers/pagination_helper.rb @@ -25,7 +25,7 @@ module PaginationHelper if collection.total_pages > 1 links = content_tag :div, '', class: 'page_links' do - will_paginate collection, container: false, page_links: false, previous_label: '', next_label: '' + will_paginate collection, container: false, page_links: false, previous_label: '', next_label: '', param_name: collection.try(:pagination_param_name) end content_tag :div, pinfos.concat(links).html_safe, class: "pagination #{cls}" diff --git a/app/helpers/referentials_helper.rb b/app/helpers/referentials_helper.rb index 01e5a5879..8251377aa 100644 --- a/app/helpers/referentials_helper.rb +++ b/app/helpers/referentials_helper.rb @@ -10,4 +10,9 @@ module ReferentialsHelper t('true') end end + + def referential_overview referential + service = ReferentialOverview.new referential, self + render partial: "referentials/overview", locals: {referential: referential, overview: service} + end end diff --git a/app/javascript/packs/referential_overview/overview.js b/app/javascript/packs/referential_overview/overview.js new file mode 100644 index 000000000..59c326e9a --- /dev/null +++ b/app/javascript/packs/referential_overview/overview.js @@ -0,0 +1 @@ +import ReferentialOverview from '../../referential_overview' diff --git a/app/javascript/referential_overview/index.coffee b/app/javascript/referential_overview/index.coffee new file mode 100644 index 000000000..0e6541421 --- /dev/null +++ b/app/javascript/referential_overview/index.coffee @@ -0,0 +1,113 @@ +class TimeTravel + constructor: (@overview)-> + @container = @overview.container.find('.time-travel') + @todayBt = @container.find(".today") + @prevBt = @container.find(".prev-page") + @nextBt = @container.find(".next-page") + @searchDateBt = @container.find("a.search-date") + @searchDateInput = @container.find("input.date-search") + @initButtons() + + initButtons: -> + @prevBt.click (e)=> + @overview.prevPage() + e.preventDefault() + false + + @nextBt.click (e)=> + @overview.nextPage() + e.preventDefault() + false + + @todayBt.click (e)=> + today = new Date() + month = today.getMonth() + 1 + month = "0#{month}" if month < 10 + day = today.getDate() + day = "0#{month}" if day < 10 + @overview.showDay "#{today.getFullYear()}-#{month}-#{day}" + e.preventDefault() + false + + @searchDateBt.click (e)=> + @overview.showDay @searchDateInput.val() if @searchDateInput.val().length > 0 + e.preventDefault() + false + + scrolledTo: (progress)-> + @prevBt.removeClass 'disabled' + @nextBt.removeClass 'disabled' + @prevBt.addClass 'disabled' if progress == 0 + @nextBt.addClass 'disabled' if progress == 1 + +class window.ReferentialOverview + constructor: (selector)-> + @container = $(selector) + @timeTravel = new TimeTravel(this) + @currentOffset = 0 + $(document).scroll (e)=> + @documentScroll(e) + @documentScroll pageY: $(document).scrollTop() + + showDay: (date)-> + day = @container.find(".day.#{date}") + @container.find(".day.selected").removeClass('selected') + day.addClass "selected" + offset = day.offset().left + parentOffset = @currentOffset + @container.find(".right").offset().left + @scrollTo parentOffset - offset + + currentOffset: -> + @container.find(".right .inner").offset().left + + top: -> + @_top ||= @container.find('.days').offset().top - 80 + bottom: -> + @_bottom ||= @top() + @container.height() - 50 + + prevPage: -> + @scrollTo @currentOffset + @container.find(".right").width() + + nextPage: -> + @scrollTo @currentOffset - @container.find(".right").width() + + minOffset: -> + @_minOffset ||= @container.find(".right").width() - @container.find(".right .line").width() + @_minOffset + + scrollTo: (offset)-> + @currentOffset = offset + @currentOffset = Math.max(@currentOffset, @minOffset()) + @currentOffset = Math.min(@currentOffset, 0) + @container.find(".right .inner .lines").css "margin-left": "#{@currentOffset}px" + @container.find(".head .week:first-child").css "margin-left", "#{@currentOffset}px" + @timeTravel.scrolledTo 1 - (@minOffset() - @currentOffset) / @minOffset() + setTimeout => + @movePeriodTitles() + , 600 + + movePeriodTitles: -> + @_right_offset ||= @container.find('.right').offset().left + @container.find(".shifted").removeClass("shifted").css "margin-left", 0 + @container.find(".right .line").each (i, l) => + $(l).find(".period").each (i, _p) => + p = $(_p) + offset = parseInt(p.css("left")) + @currentOffset + if offset < 0 && - offset < p.width() + offset = Math.min(-offset, p.width() - 100) + p.find(".title").addClass("shifted").css "margin-left", offset + "px" + return + + documentScroll: (e)-> + if @sticky + if e.pageY < @top() || e.pageY > @bottom() + @container.removeClass "sticky" + @sticky = false + else + if e.pageY > @top() && e.pageY < @bottom() + @sticky = true + @container.addClass "sticky" + + + +export default ReferentialOverview diff --git a/app/services/referential_overview.rb b/app/services/referential_overview.rb new file mode 100644 index 000000000..ccfe0617a --- /dev/null +++ b/app/services/referential_overview.rb @@ -0,0 +1,256 @@ +class ReferentialOverview + attr_reader :h + attr_reader :referential + + PER_PAGE = 10 + + def initialize referential, h=nil + @referential = referential + @page = h && h.params[pagination_param_name]&.to_i || 1 + @h = h + end + + def lines + filtered_lines.includes(:company).map{|l| Line.new(l, @referential, period.first, h)} + end + + def period + @period ||= @referential.metadatas_period || [] + end + + def includes_today? + period.include? Time.now.to_date + end + + def weeks + @weeks = {} + period.map do |d| + @weeks[Week.key(d)] ||= Week.new(d, period.last, h) + end + @weeks.values + end + + def referential_lines + @referential.metadatas_lines + end + + def filtered_lines + search.result.page(@page).per_page(PER_PAGE) + end + + ### Pagination + + delegate :empty?, :first, :total_pages, :size, :total_entries, :offset, :length, to: :filtered_lines + def current_page + @page + end + + ### search + def search + lines = referential_lines + lines = lines.search h.params[search_param_name] + lines + end + + def pagination_param_name + "referential_#{@referential.slug}_overview" + end + + def search_param_name + "q_#{pagination_param_name}" + end + + class Line + attr_reader :h + attr_reader :referential_line + + delegate :name, :number, :company, :color, :transport_mode, to: :referential_line + + def initialize line, referential, start, h + @referential_line = line + @referential = referential + @start = start + @h = h + end + + def period + @period ||= @referential.metadatas_period || [] + end + + def referential_periods + @referential_periods ||= @referential.metadatas.include_lines([@referential_line.id]).map(&:periodes).flatten.sort{|p1, p2| p1.first <=> p2.first} + end + + def periods + @periods ||= begin + periods = referential_periods.flatten.map{|p| Period.new p, @start, h} + periods = fill_periods periods + periods = merge_periods periods + periods + end + end + + def fill_periods periods + [].tap do |out| + previous = OpenStruct.new(end: period.first - 1.day) + (periods + [OpenStruct.new(start: period.last + 1.day)]).each do |p| + if p.start > previous.end + 1.day + out << Period.new((previous.end+1.day..p.start-1.day), @start, h).tap{|p| p.empty = true} + end + out << p if p.respond_to?(:end) + previous = p + end + end + end + + def merge_periods periods + [].tap do |out| + current = periods.first + periods[1..-1].each do |p| + if p.start <= current.end + current.end = p.end + else + out << current + current = p + end + end + out << current + end + end + + def width + period.count * Day::WIDTH + end + + def html_style + { + width: "#{width}px" + }.map{|k, v| "#{k}: #{v}"}.join("; ") + end + + def html_class + out = [] + out + end + + class Period + attr_accessor :empty + attr_accessor :h + + def initialize period, start, h + @period = period + @start = start + @empty = false + @h = h + end + + def start + @period.first + end + + def end + @period.last + end + + def end= val + @period = (start..val) + end + + def width + @period.count * Day::WIDTH + end + + def left + (@period.first - @start).to_i * Day::WIDTH + end + + def html_style + { + width: "#{width}px", + left: "#{left}px", + }.map{|k, v| "#{k}: #{v}"}.join("; ") + end + + def empty? + @empty + end + + def accepted? + @period.count < 7 + end + + def title + h.l(self.start, format: :short) + " - " + h.l(self.end, format: :short) + end + + def html_class + out = [] + out << "empty" if empty? + out << "accepted" if accepted? + out + end + end + end + + class Week + attr_reader :h + attr_reader :start_date + attr_reader :end_date + + def initialize start_date, boundary, h + @start_date = start_date.to_date + @end_date = [start_date.end_of_week, boundary].min.to_date + @h = h + end + + def self.key date + date.beginning_of_week.to_s + end + + def span + h.l(@start_date, format: "#{@start_date.day}-#{@end_date.day} %b") + end + + def number + h.l(@start_date, format: "%W") + end + + def period + (@start_date..@end_date) + end + + def days + period.map {|d| Day.new d, h } + end + end + + class Day + attr_reader :h + + WIDTH=50 + + def initialize date, h + @date = date + @h = h + end + + def html_style + {width: "#{WIDTH}px"}.map{|k, v| "#{k}: #{v}"}.join("; ") + end + + def html_class + out = [h.l(@date, format: "%Y-%m-%d")] + out << "weekend" if [0, 6].include?(@date.wday) + out << "today" if @date == Time.now.to_date + out + end + + def short_name + h.l(@date, format: "%a") + end + + def number + @date.day + end + end +end diff --git a/app/views/merges/show.html.slim b/app/views/merges/show.html.slim index 47e5aa029..a94552c0d 100644 --- a/app/views/merges/show.html.slim +++ b/app/views/merges/show.html.slim @@ -12,3 +12,6 @@ @merge.class.human_attribute_name(:created_at) => @merge.created_at ? l(@merge.created_at) : '-', @merge.class.human_attribute_name(:started_at) => @merge.started_at ? l(@merge.started_at) : '-', @merge.class.human_attribute_name(:ended_at) => @merge.ended_at ? l(@merge.ended_at) : '-' } + + - if resource.output.current + = referential_overview resource.output.current diff --git a/app/views/referentials/_overview.html.slim b/app/views/referentials/_overview.html.slim new file mode 100644 index 000000000..143784800 --- /dev/null +++ b/app/views/referentials/_overview.html.slim @@ -0,0 +1,75 @@ +.referential-overview id=overview.pagination_param_name + .filters + = search_form_for overview.search, as: overview.search_param_name, url: "##{overview.pagination_param_name}", html: {method: :get}, class: 'form form-filter' do |f| + .ffg-row + .form-group.input-group.search_bar + = f.search_field :name_or_number_or_objectid_cont, placeholder: t('lines.index.name_or_number_or_objectid'), class: 'form-control' + span.input-group-btn + button.btn.btn-default#search-btn type='submit' + span.fa.fa-search + .form-group.togglable + = f.label Chouette::Line.human_attribute_name(:company_id), required: false, class: 'control-label' + = f.input :company_id_eq_any, collection: overview.referential_lines.map(&:company).uniq.sort_by(&:name), as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + l.name + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list'} + + .form-group.togglable + = f.label Chouette::Line.human_attribute_name(:transport_mode), required: false, class: 'control-label' + = f.input :transport_mode_eq_any, collection: overview.referential_lines.map(&:transport_mode).uniq.sort, as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + t("enumerize.transport_mode.#{l}") + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list'} + + .actions + = link_to 'Effacer', url_for() + "##{overview.pagination_param_name}", class: 'btn btn-link' + = f.submit 'Filtrer', class: 'btn btn-default' + + .time-travel + .btn-group + = link_to I18n.t("referentials.overview.head.prev_page"), '#', class: "prev-page btn btn-default disabled" + = link_to I18n.t("referentials.overview.head.today"), '#', class: "today btn btn-default #{overview.includes_today? ? '' : 'disabled'}" + = link_to I18n.t("referentials.overview.head.next_page"), '#', class: "next-page btn btn-default" + .form-group + input.date-search type="date" min=overview.period.first max=overview.period.last + a.search-date href='#' + span.fa.fa-search + .overview-table + .left + .head + .dates= I18n.t("referentials.overview.head.dates") + .lines= I18n.t("referentials.overview.head.lines") + .lines + - overview.lines.each do |line| + .line + a.number style="background-color: #{line.color.present? ? "##{line.color}" : 'whitesmoke'}" title=line.name + = line.number + .company= line.company&.name + .mode= t("enumerize.transport_mode.#{line.transport_mode}") + .right + .inner + .head + - overview.weeks.each do |week| + .week + .week-span= week.span + .week-number= week.number + .days + - week.days.each do |day| + .day style=day.html_style class=day.html_class + .name= day.short_name + .number= day.number + .lines + - if overview.lines.any? + - overview.lines.each do |line| + .line style=line.html_style class=line.html_class + - line.periods.each do |period| + .period style=period.html_style class=period.html_class + .title=period.title + - else + = replacement_msg t('referential_lines.search_no_results') + + = new_pagination overview, 'pull-right' + +- content_for :javascript do + = javascript_pack_tag 'referential_overview/overview.js' + + javascript: + overview_id = "#{overview.pagination_param_name}"; + + coffee: + $ => + new ReferentialOverview("##{overview_id}") diff --git a/app/views/referentials/show.html.slim b/app/views/referentials/show.html.slim index 6c88f5b81..289e802d7 100644 --- a/app/views/referentials/show.html.slim +++ b/app/views/referentials/show.html.slim @@ -67,6 +67,8 @@ = replacement_msg t('referential_lines.search_no_results') + = referential_overview resource + / Modal(s) = modalbox 'purgeModal' do = simple_form_for [@referential, CleanUp.new] do |f| diff --git a/config/locales/referentials.en.yml b/config/locales/referentials.en.yml index eb8eae98d..b7483c0aa 100644 --- a/config/locales/referentials.en.yml +++ b/config/locales/referentials.en.yml @@ -48,6 +48,14 @@ en: overlapped_referential: "%{referential} cover the same perimeter" overlapped_period: "Another period is on the same period" short_period: Min period length is two days + overview: + head: + dates: Dates + lines: Lignes + today: Today + prev_page: Prev. page + next_page: Next page + activerecord: models: referential: diff --git a/config/locales/referentials.fr.yml b/config/locales/referentials.fr.yml index 37af8a4eb..53183a4c2 100644 --- a/config/locales/referentials.fr.yml +++ b/config/locales/referentials.fr.yml @@ -48,6 +48,14 @@ fr: overlapped_referential: "%{referential} couvre le même périmètre d'offre" overlapped_period: "Une autre période chevauche cette période" short_period: "La durée minimum d'une période est de deux jours" + overview: + head: + dates: Dates + lines: Lignes + today: Aujourd'hui + prev_page: ← + next_page: → + activerecord: models: referential: diff --git a/spec/services/referential_overview_spec.rb b/spec/services/referential_overview_spec.rb new file mode 100644 index 000000000..0ce29643c --- /dev/null +++ b/spec/services/referential_overview_spec.rb @@ -0,0 +1,154 @@ +RSpec.describe ReferentialOverview do + + subject{ described_class } + +end + +RSpec.describe ReferentialOverview::Week do + + describe "#initialize" do + it "should respect the boundary" do + week = ReferentialOverview::Week.new(Time.now.beginning_of_week, 1.week.from_now, {}) + expect(week.start_date).to eq Time.now.beginning_of_week.to_date + expect(week.end_date).to eq Time.now.end_of_week.to_date + + week = ReferentialOverview::Week.new(Time.now.beginning_of_week, Time.now, {}) + expect(week.start_date).to eq Time.now.beginning_of_week.to_date + expect(week.end_date).to eq Time.now.to_date + end + end +end + +RSpec.describe ReferentialOverview::Line do + + let(:ref_line){create(:line)} + let(:referential){create(:referential)} + let(:start){2.days.ago} + let(:period_1){(10.days.ago..8.days.ago)} + let(:period_2){(5.days.ago..1.days.ago)} + + subject(:line){ReferentialOverview::Line.new ref_line, referential, start, {}} + + before(:each) do + create(:referential_metadata, referential: referential, line_ids: [ref_line.id], periodes: [period_1, period_2].compact) + end + + describe "#width" do + it "should have the right value" do + expect(line.width).to eq ReferentialOverview::Day::WIDTH * referential.metadatas_period.count + end + end + + describe "#periods" do + context "when the periodes are split into several metadatas" do + let(:period_2){nil} + before do + create(:referential_metadata, referential: referential, line_ids: [ref_line.id], periodes: [(17.days.ago..11.days.ago)]) + end + it "should find them all" do + expect(line.periods.count).to eq 2 + expect(line.periods[0].empty?).to be_falsy + expect(line.periods[1].empty?).to be_falsy + end + + context "when the periodes overlap" do + let(:period_2){nil} + before do + create(:referential_metadata, referential: referential, line_ids: [ref_line.id], periodes: [(17.days.ago..9.days.ago)]) + end + it "should merge them" do + expect(line.periods.count).to eq 1 + expect(line.periods[0].empty?).to be_falsy + expect(line.periods[0].start).to eq 17.days.ago.to_date + expect(line.periods[0].end).to eq 8.days.ago.to_date + end + end + end + end + + describe "#fill_periods" do + it "should fill the voids" do + expect(line.periods.count).to eq 3 + expect(line.periods[0].empty?).to be_falsy + expect(line.periods[1].empty?).to be_truthy + expect(line.periods[1].accepted?).to be_truthy + expect(line.periods[2].empty?).to be_falsy + end + + context "with no void" do + let(:period_1){(10.days.ago..8.days.ago)} + let(:period_2){(7.days.ago..1.days.ago)} + + it "should find no void" do + expect(line.periods.count).to eq 2 + expect(line.periods[0].empty?).to be_falsy + expect(line.periods[1].empty?).to be_falsy + end + end + + context "with a large void" do + let(:period_1){(20.days.ago..19.days.ago)} + let(:period_2){(2.days.ago..1.days.ago)} + + it "should fill the void" do + expect(line.periods.count).to eq 3 + expect(line.periods[0].empty?).to be_falsy + expect(line.periods[1].empty?).to be_truthy + expect(line.periods[1].accepted?).to be_falsy + expect(line.periods[2].empty?).to be_falsy + end + end + + context "with a void at the end" do + before do + create(:referential_metadata, referential: referential, periodes: [(2.days.ago..1.days.ago)]) + end + let(:period_1){(20.days.ago..19.days.ago)} + let(:period_2){nil} + + it "should fill the void" do + expect(line.periods.count).to eq 2 + expect(line.periods[0].empty?).to be_falsy + expect(line.periods[1].empty?).to be_truthy + expect(line.periods[1].accepted?).to be_falsy + expect(line.periods[1].end).to eq 1.days.ago.to_date + end + end + + context "with a void at the beginning" do + before do + create(:referential_metadata, referential: referential, periodes: [(200.days.ago..199.days.ago)]) + end + let(:period_1){(20.days.ago..19.days.ago)} + let(:period_2){nil} + + it "should fill the void" do + expect(line.periods.count).to eq 2 + expect(line.periods[0].start).to eq 200.days.ago.to_date + expect(line.periods[0].empty?).to be_truthy + expect(line.periods[0].accepted?).to be_falsy + expect(line.periods[1].empty?).to be_falsy + end + end + end +end + +RSpec.describe ReferentialOverview::Line::Period do + + let(:period){(1.day.ago.to_date..Time.now.to_date)} + let(:start){2.days.ago.to_date} + + subject(:line_period){ReferentialOverview::Line::Period.new period, start, nil} + + describe "#width" do + it "should have the right value" do + expect(line_period.width).to eq ReferentialOverview::Day::WIDTH * 2 + end + end + + describe "#left" do + it "should have the right value" do + expect(line_period.left).to eq ReferentialOverview::Day::WIDTH * 1 + end + end +end |
