aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorZog2018-05-04 16:39:51 +0200
committerZog2018-05-04 16:39:51 +0200
commit08aa082e941db7e23d91edb8e48bead2b72e9fe3 (patch)
treeaf79f7f469fdce46b4b48e87fd5e25b4ace756f0 /app
parentdb65c0ffc7ccc76a144689ec3db43fbc2e61ee82 (diff)
downloadchouette-core-08aa082e941db7e23d91edb8e48bead2b72e9fe3.tar.bz2
Refs #6923; Implement a consolidated view
Diffstat (limited to 'app')
-rw-r--r--app/assets/stylesheets/components/_forms.sass8
-rw-r--r--app/assets/stylesheets/modules/_vj_collection.sass61
-rw-r--r--app/controllers/referential_vehicle_journeys_controller.rb4
-rw-r--r--app/helpers/vehicle_journeys_helper.rb12
-rw-r--r--app/models/chouette/route.rb3
-rw-r--r--app/services/referential_consolidated.rb124
-rw-r--r--app/views/referential_vehicle_journeys/_consolidated.html.slim21
-rw-r--r--app/views/referential_vehicle_journeys/_consolidated_line.html.slim118
-rw-r--r--app/views/referential_vehicle_journeys/_filters.html.slim13
-rw-r--r--app/views/referential_vehicle_journeys/_list.html.slim49
-rw-r--r--app/views/referential_vehicle_journeys/index.html.slim52
11 files changed, 410 insertions, 55 deletions
diff --git a/app/assets/stylesheets/components/_forms.sass b/app/assets/stylesheets/components/_forms.sass
index b13c5fc23..e7aa31fab 100644
--- a/app/assets/stylesheets/components/_forms.sass
+++ b/app/assets/stylesheets/components/_forms.sass
@@ -507,10 +507,10 @@ table, .table
right: 15px
top: 50%
padding: 0
- margin-top: -13px
z-index: 1
+ transform: translateY(-50%)
- .btn
+ *:not(.btn-group) > .btn
color: $blue
font-weight: 700
background-color: transparent
@@ -718,6 +718,10 @@ table, .table
> .form-group:last-child
border-right: none
+ @for $i from 1 through 99
+ &.w#{$i}
+ display: inline-block
+
// Form group date
.form-group.date
.form-inline
diff --git a/app/assets/stylesheets/modules/_vj_collection.sass b/app/assets/stylesheets/modules/_vj_collection.sass
index 3ff0828ea..3a252bfc0 100644
--- a/app/assets/stylesheets/modules/_vj_collection.sass
+++ b/app/assets/stylesheets/modules/_vj_collection.sass
@@ -2,7 +2,7 @@
// VJ Collection //
//-----------------//
-#vehicle_journeys_wip
+#vehicle_journeys_wip, .consolidated-view
.table-2entries
.t2e-head
> .td
@@ -218,3 +218,62 @@
// Reset default behaviour
.form-control
border-color: #ccc
+
+
+.consolidated-view
+ $highlighted: #d4ba32
+ .line
+ & > .head
+ font-size: 2em
+ text-transform: capitalize
+ border-top: 3px solid black
+ border-bottom: 3px solid black
+ padding-left: 10px
+ margin-top: 10px
+ .routes
+ .route
+ background: #F9F9F9
+ & > .head
+ padding: 15px
+ &.highlighted
+ .pull-right, span.fa
+ color: $highlighted !important
+ a
+ color: black
+ font-size: 1.2em
+ text-transform: capitalize
+ .fa
+ color: $red
+ transition: transform 0.1s
+ &.active .fa
+ transform: rotate(180deg)
+ .pull-right
+ font-size: 0.9em
+ text-transform: lowercase
+ .vehicle-journeys
+ margin-bottom: 40px
+
+ .highlighted
+ background-color: lighten($highlighted, 20%) !important
+ .disabled
+ background-color: #ccc
+ color: #777
+ .t2e-item-list .t2e-item
+ .th
+ max-width: 100px
+ & > div
+ text-overflow: ellipsis
+ overflow: hidden
+ white-space: nowrap
+ .td
+ text-align: center
+
+
+ .table-2entries > .t2e-head > .td > div > span::after
+ bottom: -6px !important
+
+ .table.table-2entries .t2e-item-list .t2e-item
+ background-color: #F9F9F9
+
+ .table.table-2entries .td > div.headlined::before
+ border-right-color: #F9F9F9
diff --git a/app/controllers/referential_vehicle_journeys_controller.rb b/app/controllers/referential_vehicle_journeys_controller.rb
index 14f7909b9..111d39c2b 100644
--- a/app/controllers/referential_vehicle_journeys_controller.rb
+++ b/app/controllers/referential_vehicle_journeys_controller.rb
@@ -42,9 +42,9 @@ class ReferentialVehicleJourneysController < ChouetteController
@q = @q.ransack(params[:q])
@vehicle_journeys ||= @q.result
@vehicle_journeys = parse_order @vehicle_journeys
- @vehicle_journeys = @vehicle_journeys.paginate page: params[:page], per_page: params[:per_page] || 10
@all_companies = Chouette::Company.where("id IN (#{@referential.vehicle_journeys.select(:company_id).to_sql})").distinct
-
+ @consolidated = ReferentialConsolidated.new @vehicle_journeys, params
+ @vehicle_journeys = @vehicle_journeys.paginate page: params[:page], per_page: params[:per_page] || 10
end
def parse_order scope
diff --git a/app/helpers/vehicle_journeys_helper.rb b/app/helpers/vehicle_journeys_helper.rb
index 1cc865c62..4d7eb7002 100644
--- a/app/helpers/vehicle_journeys_helper.rb
+++ b/app/helpers/vehicle_journeys_helper.rb
@@ -69,4 +69,16 @@ module VehicleJourneysHelper
)
end
+ def vehicle_journey_stop_headline prev_sp, sp
+ if has_feature?(:long_distance_routes)
+ headline = prev_sp && prev_sp.stop_area.country_code
+ headline = sp.stop_area.country_code != headline
+ headline && sp.stop_area.country_name
+ else
+ headline = prev_sp && prev_sp.stop_area.city_name
+ headline = sp.stop_area.city_name != headline
+ headline && sp.stop_area.city_name
+ end
+ end
+
end
diff --git a/app/models/chouette/route.rb b/app/models/chouette/route.rb
index 7a8d043e0..949b18d6f 100644
--- a/app/models/chouette/route.rb
+++ b/app/models/chouette/route.rb
@@ -72,6 +72,9 @@ module Chouette
end
end
+ has_many :time_tables, :through => :vehicle_journeys
+ has_many :purchase_windows, :through => :vehicle_journeys
+
accepts_nested_attributes_for :stop_points, :allow_destroy => :true
validates_presence_of :name
diff --git a/app/services/referential_consolidated.rb b/app/services/referential_consolidated.rb
new file mode 100644
index 000000000..abfb7532b
--- /dev/null
+++ b/app/services/referential_consolidated.rb
@@ -0,0 +1,124 @@
+class ReferentialConsolidated
+ attr_reader :params
+
+ def initialize vehicle_journeys, params
+ @vehicle_journeys = vehicle_journeys
+ @params = params
+ end
+
+ def paginated_lines
+ @paginated_lines ||= begin
+ line_ids = @vehicle_journeys.joins(route: :line).pluck('lines.id')
+ lines = Chouette::Line.where(id: line_ids).order(:name)
+ lines.paginate page: params[:page], per_page: params[:per_page] || 10
+ end
+ end
+
+ def lines
+ @lines ||= paginated_lines.to_a.map {|l| Line.new(self, l, @vehicle_journeys, params) }
+ end
+
+ def _should_highlight?
+ return false unless params[:q].present?
+ keys = params[:q].keys - ["stop_areas"]
+ params[:q].values_at(*keys).each do |value|
+ if value.is_a?(Hash)
+ return true if value.values.any?(&:present?)
+ elsif value.is_a?(Array)
+ return true if value.any?(&:present?)
+ else
+ if value.present?
+ return true
+ end
+ end
+ end
+ false
+ end
+
+ def should_highlight?
+ if @should_highlight.nil?
+ @should_highlight = _should_highlight?
+ end
+ @should_highlight
+ end
+
+ class Base
+ extend Forwardable
+ attr_reader :params
+ attr_reader :parent
+ attr_reader :ar_model
+
+ def initialize parent, ar_model, vehicle_journeys, params
+ @parent = parent
+ @ar_model = ar_model
+ @all_vehicle_journeys = vehicle_journeys
+ @params = params
+ end
+
+ def should_highlight?
+ parent.should_highlight?
+ end
+ end
+
+ class Line < Base
+ delegate name: :ar_model
+ delegate id: :ar_model
+
+ def routes
+ @routes ||= begin
+ ar_model.routes.order(:name).map {|r| Route.new(self, r, @all_vehicle_journeys, params) }
+ end
+ end
+ end
+
+ class Route < Base
+ def_delegators :ar_model, :name, :id, :time_tables, :purchase_windows, :stop_area_ids
+
+ def vehicle_journeys
+ @vehicle_journeys ||= begin
+ ar_model.vehicle_journeys.map {|vj| VehicleJourney.new(self, vj, @all_vehicle_journeys, params) }
+ end
+ end
+
+ def highlighted_journeys
+ @all_vehicle_journeys.joins(:journey_pattern).where(route_id: self.id)
+ end
+
+ def highlighted_count
+ highlighted_journeys.count
+ end
+
+ def highlighted?
+ matching_stop_areas = params[:q]["stop_areas"] && (params[:q]["stop_areas"].values & self.stop_area_ids.map(&:to_s)).present?
+ (should_highlight? || matching_stop_areas) && highlighted_journeys.exists?
+ end
+
+ def stop_points
+ @stop_points ||= ar_model.stop_points.map {|sp| StopPoint.new(self, sp, @all_vehicle_journeys, params) }
+ end
+ end
+
+ class VehicleJourney < Base
+ def_delegators :ar_model, :id, :published_journey_name, :journey_pattern, :time_tables, :purchase_windows, :vehicle_journey_at_stops, :time_table_ids, :purchase_window_ids, :route
+
+ def highlighted?
+ should_highlight? && @all_vehicle_journeys.where(id: self.id).exists?
+ end
+
+ def has_purchase_window? purchase_window
+ purchase_window_ids.include?(purchase_window.id)
+ end
+
+ def has_time_table? time_table
+ time_table_ids.include?(time_table.id)
+ end
+ end
+
+ class StopPoint < Base
+ def_delegators :ar_model, :id, :arrival_time, :departure_time, :name, :stop_area, :stop_area_id
+
+ def highlighted?
+ params[:q]["stop_areas"] && params[:q]["stop_areas"].values.any?{|v| v.to_s == stop_area_id.to_s}
+ end
+ end
+end
diff --git a/app/views/referential_vehicle_journeys/_consolidated.html.slim b/app/views/referential_vehicle_journeys/_consolidated.html.slim
new file mode 100644
index 000000000..b79a61dfb
--- /dev/null
+++ b/app/views/referential_vehicle_journeys/_consolidated.html.slim
@@ -0,0 +1,21 @@
+.row.consolidated-view
+ - @consolidated.lines.each do |line|
+ = render partial: "consolidated_line", object: line
+ .col-md-12
+ = new_pagination @consolidated.paginated_lines, 'pull-right'
+
+coffee:
+ $('a.toggle-timetables').click (e)->
+ e.preventDefault()
+ $(e.target).toggleClass 'active'
+ $(e.target).parents('.table').find('.detailed-timetables').toggleClass 'hidden'
+
+ $('a.toggle-purchase-windows').click (e)->
+ e.preventDefault()
+ $(e.target).toggleClass 'active'
+ $(e.target).parents('.table').find('.detailed-purchase-windows').toggleClass 'hidden'
+
+ $('a.toggle-route').click (e)->
+ e.preventDefault()
+ $(e.currentTarget).toggleClass 'active'
+ $(e.currentTarget).parents('.route').find('.vehicle-journeys').toggleClass 'hidden'
diff --git a/app/views/referential_vehicle_journeys/_consolidated_line.html.slim b/app/views/referential_vehicle_journeys/_consolidated_line.html.slim
new file mode 100644
index 000000000..b72a17ccd
--- /dev/null
+++ b/app/views/referential_vehicle_journeys/_consolidated_line.html.slim
@@ -0,0 +1,118 @@
+.line.col-md-12
+ .head
+ span
+ = Chouette::Line.ts
+ | &nbsp;
+ strong= consolidated_line.name
+ .routes
+ - consolidated_line.routes.each do |route|
+ .route
+ .head class="#{route.highlighted? ? 'highlighted' : ''}"
+ = link_to '#', class: 'toggle-route' do
+ span.sb.sb-route
+ | &nbsp;
+ = Chouette::Route.ts
+ | &nbsp;
+ strong= route.name
+ .pull-right
+ = route.highlighted_count
+ | &nbsp;
+ = Chouette::VehicleJourney.t
+ | &nbsp;
+ span.fa.fa-angle-up
+ .table.table-2entries.vehicle-journeys.hidden
+ .t2e-head.w20
+ .th
+ div
+ strong= Chouette::VehicleJourney.tmf(:id)
+ div= Chouette::VehicleJourney.tmf(:name)
+ div= Chouette::VehicleJourney.tmf(:journey_pattern_id)
+ div
+ = link_to '#', class: 'toggle-purchase-windows detailed-timetables-bt' do
+ span.fa.fa-angle-up
+ = Chouette::PurchaseWindow.t
+ .detailed-purchase-windows.hidden
+ - route.purchase_windows.uniq.each do |tt|
+ div
+ p
+ = link_to [@referential, tt] do
+ span.fa.fa-calendar style={color: (tt.color ? tt.color : '#4B4B4B')}
+ | &nbsp;
+ = tt.name
+
+ p= tt.bounding_dates.split(' ').join(' > ')
+ div
+ = link_to '#', class: 'toggle-timetables detailed-timetables-bt' do
+ span.fa.fa-angle-up
+ = Chouette::TimeTable.t
+
+ .detailed-timetables.hidden
+ - route.time_tables.uniq.each do |tt|
+ div
+ p
+ = link_to [@referential, tt] do
+ span.fa.fa-calendar style={color: (tt.color ? tt.color : '#4B4B4B')}
+ | &nbsp;
+ = tt.display_day_types
+
+ p= tt.bounding_dates.split(' ').join(' > ')
+ - prev_sp = nil
+ - route.stop_points.each do |sp|
+ ruby:
+ headline = vehicle_journey_stop_headline prev_sp, sp
+ prev_sp = sp
+ .td class="#{sp.highlighted? ? 'highlighted' : ''}"
+ div title="#{sp.stop_area.city_name ? "#{sp.stop_area.city_name} (#{sp.stop_area.zip_code})" : ''}" data-headline=headline class=(headline.present? ? 'headlined' : '')
+ span
+ = sp.name
+ - if sp.stop_area.time_zone_formatted_offset
+ span.small
+ | &nbsp;
+ = "(#{sp.stop_area.time_zone_formatted_offset})"
+ .t2e-item-list.w80
+ div
+ - route.vehicle_journeys.each do |journey|
+ .t2e-item class="#{journey.highlighted? ? 'highlighted' : ''}"
+ .th
+ div
+ strong= link_to journey.id, [@referential, journey.route.line, journey.route]
+ div= journey.published_journey_name
+ div= journey.journey_pattern.get_objectid.short_id
+ div
+ - journey.purchase_windows[0..3].each do |tt|
+ span.vj_tt
+ = link_to [@referential, tt], target: :blank do
+ span.fa.fa-calendar style="color: #{tt.color ? tt.color : '#4B4B4B'}"
+ - if journey.purchase_windows.size > 3
+ span.vj_tt = "+ #{journey.purchase_windows.size - 3}"
+ .detailed-purchase-windows.hidden
+ - route.purchase_windows.uniq.each do |tt|
+ div class=(journey.has_purchase_window?(tt) ? 'active' : 'inactive')
+ div
+ - journey.time_tables[0..3].each do |tt|
+ span.vj_tt
+ = link_to [@referential, tt], target: :blank do
+ span.fa.fa-calendar style="color: #{tt.color ? tt.color : '#4B4B4B'}"
+ - if journey.time_tables.size > 3
+ span.vj_tt = "+ #{journey.time_tables.size - 3}"
+ .detailed-timetables.hidden
+ - route.time_tables.uniq.each do |tt|
+ div class=(journey.has_time_table?(tt) ? 'active' : 'inactive')
+
+ - prev_sp = nil
+ - route.stop_points.each do |sp|
+ ruby:
+ headline = vehicle_journey_stop_headline prev_sp, sp
+ prev_sp = sp
+ vjas = journey.vehicle_journey_at_stops.where(stop_point_id: sp.id).last
+ .td class="#{vjas && sp.highlighted? ? 'highlighted' : ''} #{vjas.nil? ? 'disabled' : ''}"
+ div title="#{sp.stop_area.city_name ? "#{sp.stop_area.city_name} (#{sp.stop_area.zip_code})" : ''}" data-headline=headline class=(headline.present? ? 'headlined' : '')
+ - if vjas.present?
+ - if vjas.departure_time == vjas.arrival_time
+ = vjas.departure_time.l(format: "%H:%M")
+ - else
+ = vjas.arrival_time.l(format: "%H:%M")
+ | &nbsp;-&nbsp;
+ = vjas.departure_time.l(format: "%H:%M")
+ - else
+ | 00:00
diff --git a/app/views/referential_vehicle_journeys/_filters.html.slim b/app/views/referential_vehicle_journeys/_filters.html.slim
index a6e289b97..b12766df1 100644
--- a/app/views/referential_vehicle_journeys/_filters.html.slim
+++ b/app/views/referential_vehicle_journeys/_filters.html.slim
@@ -1,14 +1,23 @@
= search_form_for @q, url: referential_vehicle_journeys_path(@referential), html: {method: :get}, class: 'form form-filter' do |f|
- .ffg-row
+ input type="hidden" name="display" value=params[:display]
+ .ffg-row.w73
.input-group.search_bar
= f.search_field :published_journey_name_or_objectid_cont, placeholder: t('.published_journey_name_or_objectid'), class: 'form-control'
span.input-group-btn
button.btn.btn-default#search-btn type='submit'
span.fa.fa-search
- .ffg-row
+ .ffg-row.w27
.form-group.per-page-select
= I18n.t("simple_form.per_page")
= %w(10 50 100).each_with_index.map{ |v, i| (params[:per_page] == v || params[:per_page].nil? && i == 0) ? "<span class='selected'>#{v}</span>" : link_to(v, referential_vehicle_journeys_path(@referential, q: params[:q], per_page: v)) }.join(' - ').html_safe
+ .form-group
+ .btn-group
+ = link_to referential_vehicle_journeys_path(@referential, q: params[:q], display: :list), class: 'btn btn-default ' + (params[:display] != "consolidated" ? 'active' : '') do
+ span.fa.fa-align-justify
+ = link_to referential_vehicle_journeys_path(@referential, q: params[:q], display: :consolidated), class: 'btn btn-default ' + (params[:display] == "consolidated" ? 'active' : '') do
+ span.fa.fa-th-large
+
+ .ffg-row
.form-group.togglable class=filter_item_class(params[:q], :company_id_eq_any)
= f.label Chouette::VehicleJourney.human_attribute_name(:company), required: false, class: 'control-label'
- if @all_companies.present?
diff --git a/app/views/referential_vehicle_journeys/_list.html.slim b/app/views/referential_vehicle_journeys/_list.html.slim
new file mode 100644
index 000000000..74f8238f8
--- /dev/null
+++ b/app/views/referential_vehicle_journeys/_list.html.slim
@@ -0,0 +1,49 @@
+.row
+ .col-lg-12
+ .select_table
+ = table_builder_2 @vehicle_journeys,
+ [ \
+ TableBuilderHelper::Column.new( \
+ name: t('objectid'), \
+ attribute: Proc.new { |n| n.get_objectid.short_id }, \
+ sortable: false \
+ ), \
+ TableBuilderHelper::Column.new( \
+ key: :published_journey_name, \
+ attribute: 'published_journey_name', \
+ link_to: lambda do |vehicle_journey| \
+ vehicle_journey.published_journey_name ? referential_line_route_vehicle_journeys_path(@referential, vehicle_journey.route.line, vehicle_journey.route) : '' \
+ end, \
+ sortable: true \
+ ), \
+ TableBuilderHelper::Column.new( \
+ key: :line, \
+ attribute: Proc.new {|v| v.route.line.name}, \
+ sortable: true \
+ ), \
+ TableBuilderHelper::Column.new( \
+ key: :route, \
+ attribute: Proc.new {|v| v.route.name}, \
+ sortable: true \
+ ), \
+ TableBuilderHelper::Column.new( \
+ key: :departure_time, \
+ attribute: Proc.new {|v| v.vehicle_journey_at_stops.first&.departure_local }, \
+ sortable: true \
+ ), \
+ [@starting_stop, @ending_stop].compact.map{|stop| \
+ TableBuilderHelper::Column.new( \
+ attribute: Proc.new {|v| v.vehicle_journey_at_stops.where("stop_points.stop_area_id" => stop.id).last&.arrival_local }, \
+ sortable: false, \
+ name: stop.name \
+ )\
+ }, \
+ TableBuilderHelper::Column.new( \
+ key: :arrival_time, \
+ attribute: Proc.new {|v| v.vehicle_journey_at_stops.last&.arrival_local }, \
+ sortable: true, \
+ ), \
+ ].flatten.compact,
+ cls: 'table has-filter has-search'
+
+ = new_pagination @vehicle_journeys, 'pull-right'
diff --git a/app/views/referential_vehicle_journeys/index.html.slim b/app/views/referential_vehicle_journeys/index.html.slim
index 00f63cb65..178a88568 100644
--- a/app/views/referential_vehicle_journeys/index.html.slim
+++ b/app/views/referential_vehicle_journeys/index.html.slim
@@ -9,55 +9,11 @@
= render 'filters'
- if @vehicle_journeys.present?
- .row
- .col-lg-12
- .select_table
- = table_builder_2 @vehicle_journeys,
- [ \
- TableBuilderHelper::Column.new( \
- name: t('objectid'), \
- attribute: Proc.new { |n| n.get_objectid.short_id }, \
- sortable: false \
- ), \
- TableBuilderHelper::Column.new( \
- key: :published_journey_name, \
- attribute: 'published_journey_name', \
- link_to: lambda do |vehicle_journey| \
- vehicle_journey.published_journey_name ? referential_line_route_vehicle_journeys_path(@referential, vehicle_journey.route.line, vehicle_journey.route) : '' \
- end, \
- sortable: true \
- ), \
- TableBuilderHelper::Column.new( \
- key: :line, \
- attribute: Proc.new {|v| v.route.line.name}, \
- sortable: true \
- ), \
- TableBuilderHelper::Column.new( \
- key: :route, \
- attribute: Proc.new {|v| v.route.name}, \
- sortable: true \
- ), \
- TableBuilderHelper::Column.new( \
- key: :departure_time, \
- attribute: Proc.new {|v| v.vehicle_journey_at_stops.first&.departure_local }, \
- sortable: true \
- ), \
- [@starting_stop, @ending_stop].compact.map{|stop| \
- TableBuilderHelper::Column.new( \
- attribute: Proc.new {|v| v.vehicle_journey_at_stops.where("stop_points.stop_area_id" => stop.id).last&.arrival_local }, \
- sortable: false, \
- name: stop.name \
- )\
- }, \
- TableBuilderHelper::Column.new( \
- key: :arrival_time, \
- attribute: Proc.new {|v| v.vehicle_journey_at_stops.last&.arrival_local }, \
- sortable: true, \
- ), \
- ].flatten.compact,
- cls: 'table has-filter has-search'
+ - if params[:display] == "consolidated"
+ = render partial: "consolidated"
+ - else
+ = render partial: "list"
- = new_pagination @vehicle_journeys, 'pull-right'
- unless @vehicle_journeys.any?
.row.mt-xs