diff options
Diffstat (limited to 'app')
44 files changed, 439 insertions, 180 deletions
diff --git a/app/assets/stylesheets/OpenLayers/custom.sass b/app/assets/stylesheets/OpenLayers/custom.sass index fa874d924..013c056d6 100644 --- a/app/assets/stylesheets/OpenLayers/custom.sass +++ b/app/assets/stylesheets/OpenLayers/custom.sass @@ -2,15 +2,20 @@ .list-group-item & margin-top: 15px - .routes-labels + .ol-routes-layers + position: absolute + right: 42px + top: .5em padding: 0 - display: flex - justify-content: space-between - flex-wrap: wrap margin: 5px -5px - li - list-style-type: none - flex: 1 0 25% + width: 30% + background-color: transparentize(white, 0.2) + border-radius: 3px + max-height: 90% + overflow-y: scroll + a + display: block + width: calc(100% - 10px) border: 1px solid $lightgrey padding: 5px margin: 5px @@ -18,11 +23,21 @@ cursor: pointer color: $blue white-space: nowrap - + text-overflow: ellipsis + overflow: hidden + font-size: 0.6em &:hover - background: $orange + text-decoration: none + + &.active + background: $blue color: white + .ol-routes-layers-button-wrapper + position: absolute + right: .5em + top: .5em + .ol-scale-line background-color: transparent bottom: 5px @@ -55,20 +70,20 @@ .ol-zoom background-color: transparent - .ol-zoom-in, .ol-zoom-out - background-color: $darkblue - color: #fff - border-radius: 3px - margin: 0 + .ol-zoom-in, .ol-zoom-out, .ol-routes-layers-button + background-color: $darkblue + color: #fff + border-radius: 3px + margin: 0 - .ol-zoom-in - border-bottom-left-radius: 0 - border-bottom-right-radius: 0 + .ol-zoom-in + border-bottom-left-radius: 0 + border-bottom-right-radius: 0 - .ol-zoom-out - margin-top: 1px - border-top-left-radius: 0 - border-top-right-radius: 0 + .ol-zoom-out + margin-top: 1px + border-top-left-radius: 0 + border-top-right-radius: 0 .ol-zoomslider margin: 2px diff --git a/app/assets/stylesheets/components/_modals.sass b/app/assets/stylesheets/components/_modals.sass index e52a2e125..14b783c51 100644 --- a/app/assets/stylesheets/components/_modals.sass +++ b/app/assets/stylesheets/components/_modals.sass @@ -50,3 +50,9 @@ $modalW: 600px .modal-footer border-color: rgba($blue, 0.25) padding: 15px 30px + + .has-error .form-group + margin-bottom: -10px + + .form-group + margin-bottom: 25px diff --git a/app/assets/stylesheets/components/_referential_overview.sass b/app/assets/stylesheets/components/_referential_overview.sass index 0beb8ab67..7a0cc98c5 100644 --- a/app/assets/stylesheets/components/_referential_overview.sass +++ b/app/assets/stylesheets/components/_referential_overview.sass @@ -22,7 +22,7 @@ box-shadow: 0 0 10px rgba(0,0,0,0.5) z-index: 1 .time-travel - padding-top: 4px + padding-top: 3px padding-bottom: 4px a.btn:first-child margin-right: 1px @@ -61,7 +61,7 @@ border-color: $grey width: auto flex: 1 1 - padding: 4px 11px 5px + padding: 6px 11px .input-group-btn right: 10px &.togglable @@ -117,6 +117,7 @@ padding: 7px 10px border-bottom: 1px solid $grey font-size: 0.8em + display: block &:last-child border-bottom: none .number @@ -135,10 +136,9 @@ overflow: hidden .name display: inline-block - width: $left-size - 50px() + width: $left-size - 10px white-space: nowrap line-height: 20px - margin-left: 5px text-overflow: ellipsis overflow: hidden vertical-align: bottom @@ -182,8 +182,8 @@ height: 100% transition: margin 0.5s background: white - &:last-child - box-shadow: 0 -10px 10px rgba(0,0,0,0.5) + // &:last-child + // box-shadow: 0 -10px 10px rgba(0,0,0,0.5) .week-span left: 15px top: 15px @@ -246,18 +246,17 @@ &.selected, &:hover color: $blue background-color: transparentize($blue, 0.7) + + &:hover + background-color: transparentize(white, 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 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 45b7f55f6..c4961123d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -28,7 +28,7 @@ class ApplicationController < ActionController::Base protected def user_not_authorized - redirect_to forbidden_path + render 'errors/forbidden', status: 403 end def current_organisation diff --git a/app/controllers/calendars_controller.rb b/app/controllers/calendars_controller.rb index 75d4cbd09..cc7570d65 100644 --- a/app/controllers/calendars_controller.rb +++ b/app/controllers/calendars_controller.rb @@ -31,10 +31,11 @@ class CalendarsController < ChouetteController end def create - create! do - if @calendar.valid? && has_feature?('application_days_on_calendars') - redirect_to([:edit, @calendar]) - return + create! do |success, failure| + if has_feature?('application_days_on_calendars') + success.html do + redirect_to([:edit, @workgroup, @calendar]) + end end end end @@ -125,4 +126,4 @@ class CalendarsController < ChouetteController scope end -end
\ No newline at end of file +end diff --git a/app/controllers/compliance_check_messages_controller.rb b/app/controllers/compliance_check_messages_controller.rb index 7c416584e..36745981e 100644 --- a/app/controllers/compliance_check_messages_controller.rb +++ b/app/controllers/compliance_check_messages_controller.rb @@ -7,7 +7,7 @@ class ComplianceCheckMessagesController < ChouetteController def index index! do |format| format.csv { - send_data ComplianceCheckMessageExport.new(compliance_check_messages: collection).to_csv(:col_sep => "\;", :quote_char=>'"', force_quotes: true, server_url: request.base_url) , :filename => "compliance_check_set_errors_#{line_code}_#{Time.now.to_i}.csv" + send_data ComplianceCheckMessageExport.new(compliance_check_messages: collection).to_csv(:col_sep => "\;", :quote_char=>'"', force_quotes: true, server_url: request.base_url) , :filename => "compliance_check_set_errors_#{line_code}_#{Date.today.to_s}.csv" } end end diff --git a/app/controllers/compliance_check_sets_controller.rb b/app/controllers/compliance_check_sets_controller.rb index 271598428..62b0e6ba3 100644 --- a/app/controllers/compliance_check_sets_controller.rb +++ b/app/controllers/compliance_check_sets_controller.rb @@ -12,7 +12,7 @@ class ComplianceCheckSetsController < ChouetteController @q_for_form = scope.ransack(params[:q]) format.html { @compliance_check_sets = ComplianceCheckSetDecorator.decorate( - @q_for_form.result.order(created_at: :desc) + @q_for_form.result.order(created_at: :desc).paginate(page: params[:page], per_page: 30) ) } end diff --git a/app/controllers/compliance_checks_controller.rb b/app/controllers/compliance_checks_controller.rb index 81749e292..ad32bc538 100644 --- a/app/controllers/compliance_checks_controller.rb +++ b/app/controllers/compliance_checks_controller.rb @@ -1,4 +1,5 @@ class ComplianceChecksController < InheritedResources::Base - - + belongs_to :workbench do + belongs_to :compliance_check_set + end end diff --git a/app/controllers/compliance_control_sets_controller.rb b/app/controllers/compliance_control_sets_controller.rb index 8f9251155..6461b38c8 100644 --- a/app/controllers/compliance_control_sets_controller.rb +++ b/app/controllers/compliance_control_sets_controller.rb @@ -36,11 +36,15 @@ class ComplianceControlSetsController < ChouetteController private def collection - scope = self.ransack_period_range(scope: ComplianceControlSet.all, error_message: t('imports.filters.error_period_filter'), query: :where_updated_at_between) - @q_for_form = scope.ransack(params[:q]) - compliance_control_sets = @q_for_form.result - compliance_control_sets = joins_with_associated_objects(compliance_control_sets).order(sort_column + ' ' + sort_direction) if sort_column && sort_direction - @compliance_control_sets = compliance_control_sets.paginate(page: params[:page], per_page: 30) + @compliance_control_sets ||= begin + scope = end_of_association_chain.all + scope = self.ransack_period_range(scope: scope, error_message: t('imports.filters.error_period_filter'), query: :where_updated_at_between) + @q_for_form = scope.ransack(params[:q]) + compliance_control_sets = @q_for_form.result + compliance_control_sets = joins_with_associated_objects(compliance_control_sets).order(sort_column + ' ' + sort_direction) if sort_column && sort_direction + compliance_control_sets = compliance_control_sets.paginate(page: params[:page], per_page: 30) + end + end def decorate_compliance_control_sets(compliance_control_sets) @@ -82,9 +86,9 @@ class ComplianceControlSetsController < ChouetteController case params[:sort] when 'owner_jdc' collection.joins("LEFT JOIN organisations ON compliance_control_sets.organisation_id = organisations.id") - when 'control_numbers' + when 'control_numbers' collection.joins("LEFT JOIN compliance_controls ON compliance_controls.compliance_control_set_id = compliance_control_sets.id").group(:id) - else + else collection end end diff --git a/app/controllers/import_messages_controller.rb b/app/controllers/import_messages_controller.rb index 286bb0ce8..4f8fe7a25 100644 --- a/app/controllers/import_messages_controller.rb +++ b/app/controllers/import_messages_controller.rb @@ -9,7 +9,7 @@ class ImportMessagesController < ChouetteController def index index! do |format| format.csv { - send_data ImportMessageExport.new(:import_messages => @import_messages).to_csv(:col_sep => "\;", :quote_char=>'"', force_quotes: true) , :filename => "import_errors_#{@import_resource.name.gsub('.xml', '')}_#{Time.now.to_i}.csv" + send_data ImportMessageExport.new(:import_messages => @import_messages).to_csv(:col_sep => "\;", :quote_char=>'"', force_quotes: true) , :filename => "import_errors_#{@import_resource.name.gsub('.xml', '')}_#{Date.today.to_s}.csv" } end end diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb index 5267c15d8..6e3694547 100644 --- a/app/controllers/referentials_controller.rb +++ b/app/controllers/referentials_controller.rb @@ -7,6 +7,8 @@ class ReferentialsController < ChouetteController respond_to :json, :only => :show respond_to :js, :only => :show + before_action :check_cloning_source_is_accessible, only: %i(new create) + def new new! do build_referential @@ -175,6 +177,12 @@ class ReferentialsController < ChouetteController ) end + def check_cloning_source_is_accessible + return unless params[:from] + source = Referential.find params[:from] + return user_not_authorized unless current_user.organisation.workgroups.include?(source.workbench.workgroup) + end + def load_workbench @workbench ||= Workbench.find(params[:workbench_id]) if params[:workbench_id] @workbench ||= resource&.workbench if params[:id] diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 0058c210d..356c7e69e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -19,7 +19,7 @@ module ApplicationHelper return object.full_name end - local = "#{object.model_name.name.underscore.pluralize}.#{params[:action]}.title" + local = "#{object.model_name.name.underscore.pluralize}.#{params[:action]}.title" if object.try(:name) t(local, name: object.name || object.id) else diff --git a/app/helpers/table_builder_helper.rb b/app/helpers/table_builder_helper.rb index 2068dd23c..d16858678 100644 --- a/app/helpers/table_builder_helper.rb +++ b/app/helpers/table_builder_helper.rb @@ -224,7 +224,7 @@ module TableBuilderHelper if column.linkable? path = column.link_to(item) - link = link_to(value, path) + link = value.present? && path.present? ? link_to(value, path) : "" if overhead.empty? bcont << content_tag(:td, link, title: 'Voir') diff --git a/app/helpers/table_builder_helper/column.rb b/app/helpers/table_builder_helper/column.rb index 05aa9f563..ff6f2f36f 100644 --- a/app/helpers/table_builder_helper/column.rb +++ b/app/helpers/table_builder_helper/column.rb @@ -2,19 +2,21 @@ module TableBuilderHelper class Column attr_reader :key, :name, :attribute, :sortable - def initialize(key: nil, name: '', attribute:, sortable: true, link_to: nil) + def initialize(key: nil, name: '', attribute:, sortable: true, link_to: nil, **opts) if key.nil? && name.empty? raise ColumnMustHaveKeyOrNameError end - + opts ||= {} @key = key @name = name @attribute = attribute @sortable = sortable @link_to = link_to + @condition = opts[:if] end def value(obj) + return unless check_condition(obj) if @attribute.is_a?(Proc) @attribute.call(obj) else @@ -36,8 +38,18 @@ module TableBuilderHelper end def link_to(obj) + return unless check_condition(obj) @link_to.call(obj) end + + def check_condition(obj) + condition_val = true + if @condition.present? + condition_val = @condition + condition_val = condition_val.call(obj) if condition_val.is_a?(Proc) + end + !!condition_val + end end diff --git a/app/javascript/helpers/routes_map.coffee b/app/javascript/helpers/routes_map.coffee index 6834406fc..42377cd6e 100644 --- a/app/javascript/helpers/routes_map.coffee +++ b/app/javascript/helpers/routes_map.coffee @@ -1,3 +1,65 @@ +RoutesLayersButton = (options) -> + menu = options.menu + + toggleMenu = (e)=> + $(menu.element).toggleClass 'hidden' + button.innerHTML = if button.innerHTML == "+" then "-" else "+" + + button = document.createElement("button") + button.innerHTML = "+" + button.addEventListener('click', toggleMenu, false) + button.addEventListener('touchstart', toggleMenu, false) + button.className = "ol-routes-layers-button" + + element = document.createElement('div'); + element.className = 'ol-control ol-routes-layers-button-wrapper'; + + element.appendChild(button) + + ol.control.Control.call(this, { + element + target: options.target + }) + +ol.inherits RoutesLayersButton, ol.control.Control + +RoutesLayersControl = (routes, routes_map) -> + + element = document.createElement('div') + element.className = 'ol-unselectable ol-routes-layers hidden' + Object.keys(routes).forEach (id)=> + route = routes[id] + route.active = true + label = document.createElement('a') + label.title = route.name + label.className = 'active' + label.innerHTML = route.name + element.appendChild label + label.addEventListener "click", => + route.active = !route.active + $(label).toggleClass "active" + route.active + route.vectorPtsLayer.setStyle routes_map.defaultStyles(route.active) + route.vectorEdgesLayer.setStyle routes_map.edgeStyles(route.active) + route.vectorLnsLayer.setStyle routes_map.lineStyle(route.active) + routes_map.fitZoom() + label.addEventListener "mouseenter", => + route.vectorPtsLayer.setStyle routes_map.defaultStyles(true) + route.vectorEdgesLayer.setStyle routes_map.edgeStyles(true) + route.vectorLnsLayer.setStyle routes_map.lineStyle(true) + + label.addEventListener "mouseleave", => + route.vectorPtsLayer.setStyle routes_map.defaultStyles(route.active) + route.vectorEdgesLayer.setStyle routes_map.edgeStyles(route.active) + route.vectorLnsLayer.setStyle routes_map.lineStyle(route.active) + + + ol.control.Control.call(this, { + element + }) + +ol.inherits RoutesLayersControl, ol.control.Control + class RoutesMap constructor: (@target)-> @initMap() @@ -20,6 +82,7 @@ class RoutesMap addRoute: (route)-> geoColPts = [] geoColLns = [] + route.active = true @routes[route.id] = route if route.id stops = route.stops || route geoColEdges = [ @@ -77,68 +140,49 @@ class RoutesMap @map.addLayer vectorEdgesLayer @map.addLayer vectorLnsLayer - lineStyle: (highlighted=false)-> + lineStyle: (active=true)-> new ol.style.Style stroke: new ol.style.Stroke - color: if highlighted then "#ed7f00" else '#007fbb' - width: 3 + color: '#007fbb' + width: if active then 3 else 0 - edgeStyles: (highlighted=false)-> + edgeStyles: (active=true)-> new ol.style.Style image: new ol.style.Circle radius: 5 stroke: new ol.style.Stroke - color: if highlighted then "#ed7f00" else '#007fbb' - width: 2 + color: '#007fbb' + width: if active then 3 else 0 fill: new ol.style.Fill - color: if highlighted then "#ed7f00" else '#007fbb' - width: 2 + color: '#007fbb' + width: if active then 3 else 0 - defaultStyles: (highlighted=false)-> + defaultStyles: (active=true)-> new ol.style.Style image: new ol.style.Circle radius: 4 stroke: new ol.style.Stroke - color: if highlighted then "#ed7f00" else '#007fbb' - width: 2 + color: '#007fbb' + width: if active then 3 else 0 fill: new ol.style.Fill color: '#ffffff' - width: 2 + width: if active then 3 else 0 addRoutesLabels: -> - labelsContainer = $("<ul class='routes-labels'></ul>") - labelsContainer.appendTo $("##{@target}") - @vectorPtsLayer = null - @vectorEdgesLayer = null - @vectorLnsLayer = null + menu = new RoutesLayersControl(@routes, this) + @map.addControl menu + @map.addControl new RoutesLayersButton(menu: menu) + + fitZoom: ()-> + area = [] + found = false Object.keys(@routes).forEach (id)=> route = @routes[id] - label = $("<li>#{route.name}</ul>") - label.appendTo labelsContainer - label.mouseleave => - route.vectorPtsLayer.setStyle @defaultStyles(false) - route.vectorEdgesLayer.setStyle @edgeStyles(false) - route.vectorLnsLayer.setStyle @lineStyle(false) - route.vectorPtsLayer.setZIndex 2 - route.vectorEdgesLayer.setZIndex 3 - route.vectorLnsLayer.setZIndex 1 - @fitZoom() - label.mouseenter => - route.vectorPtsLayer.setStyle @defaultStyles(true) - route.vectorEdgesLayer.setStyle @edgeStyles(true) - route.vectorLnsLayer.setStyle @lineStyle(true) - route.vectorPtsLayer.setZIndex 11 - route.vectorEdgesLayer.setZIndex 12 - route.vectorLnsLayer.setZIndex 10 - @fitZoom(route) - - fitZoom: (route)-> - if route - area = [] - route.stops.forEach (stop, i) => - area.push [parseFloat(stop.longitude), parseFloat(stop.latitude)] - else - area = @area + if route.active + found = true + route.stops.forEach (stop, i) => + area.push [parseFloat(stop.longitude), parseFloat(stop.latitude)] + area = @area unless found boundaries = ol.extent.applyTransform( ol.extent.boundingExtent(area), ol.proj.getTransform('EPSG:4326', 'EPSG:3857') ) diff --git a/app/javascript/packs/referential_lines/show.js b/app/javascript/packs/referential_lines/show.js index 542188018..99c5072ef 100644 --- a/app/javascript/packs/referential_lines/show.js +++ b/app/javascript/packs/referential_lines/show.js @@ -6,5 +6,5 @@ routes = JSON.parse(decodeURIComponent(routes)) var map = new RoutesMap('routes_map') map.addRoutes(routes) -// map.addRoutesLabels() +map.addRoutesLabels() map.fitZoom() diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js index e67753e4b..5fb88f024 100644 --- a/app/javascript/vehicle_journeys/actions/index.js +++ b/app/javascript/vehicle_journeys/actions/index.js @@ -203,11 +203,10 @@ const actions = { let field = fields[key] if(field.validity && !field.validity.valid){ valid = false - $(field).parent().addClass('has-error').children('.help-block').remove() + $(field).parent().parent().addClass('has-error').children('.help-block').remove() $(field).parent().append("<span class='small help-block'>" + field.validationMessage + "</span>") } }) - return valid }, toggleArrivals : () => ({ diff --git a/app/javascript/vehicle_journeys/components/tools/CreateModal.js b/app/javascript/vehicle_journeys/components/tools/CreateModal.js index 24d9a23c2..a60429765 100644 --- a/app/javascript/vehicle_journeys/components/tools/CreateModal.js +++ b/app/javascript/vehicle_journeys/components/tools/CreateModal.js @@ -12,7 +12,13 @@ export default class CreateModal extends Component { } handleSubmit() { - if (actions.validateFields(...this.refs, $('.vjCreateSelectJP')[0]) && this.props.modal.modalProps.selectedJPModal) { + if(!this.props.modal.modalProps.selectedJPModal){ + let field = $('#NewVehicleJourneyModal').find(".vjCreateSelectJP") + field.parent().parent().addClass('has-error').children('.help-block').remove() + field.parent().append("<span class='small help-block'>" + I18n.t("simple_form.required.text") + "</span>") + return + } + if (actions.validateFields(...this.refs, $('.vjCreateSelectJP')[0])) { this.props.onAddVehicleJourney(_.assign({}, this.refs, {custom_fields: this.custom_fields}), this.props.modal.modalProps.selectedJPModal, this.props.stopPointsList, this.props.modal.modalProps.vehicleJourney && this.props.modal.modalProps.vehicleJourney.company) this.props.onModalClose() $('#NewVehicleJourneyModal').modal('hide') diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb index 9b94f7f0e..c5a6901d7 100644 --- a/app/models/chouette/vehicle_journey.rb +++ b/app/models/chouette/vehicle_journey.rb @@ -3,6 +3,7 @@ module Chouette class VehicleJourney < Chouette::TridentActiveRecord has_paper_trail include ChecksumSupport + include CustomFieldsSupport include VehicleJourneyRestrictions include ObjectidSupport include StifTransportModeEnumerations @@ -340,21 +341,6 @@ module Chouette end end - def self.custom_fields - CustomField.where(resource_type: self.name.split("::").last) - end - - - def custom_fields - Hash[*self.class.custom_fields.map do |v| - [v.code, v.slice(:code, :name, :field_type, :options).update(value: custom_field_value(v.code))] - end.flatten] - end - - def custom_field_value key - (custom_field_values || {})[key.to_s] - end - def self.matrix(vehicle_journeys) Hash[*VehicleJourneyAtStop.where(vehicle_journey_id: vehicle_journeys.pluck(:id)).map do |vjas| [ "#{vjas.vehicle_journey_id}-#{vjas.stop_point_id}", vjas] diff --git a/app/models/compliance_check.rb b/app/models/compliance_check.rb index 55f2ae228..9d817e146 100644 --- a/app/models/compliance_check.rb +++ b/app/models/compliance_check.rb @@ -1,14 +1,23 @@ class ComplianceCheck < ActiveRecord::Base + include ComplianceItemSupport self.inheritance_column = nil extend Enumerize belongs_to :compliance_check_set belongs_to :compliance_check_block - + enumerize :criticity, in: %i(warning error), scope: true, default: :warning validates :criticity, presence: true validates :name, presence: true validates :code, presence: true validates :origin_code, presence: true + + def control_class + compliance_control_name.present? ? compliance_control_name.constantize : nil + end + + delegate :predicate, to: :control_class, allow_nil: true + delegate :prerequisite, to: :control_class, allow_nil: true + end diff --git a/app/models/compliance_check_message_export.rb b/app/models/compliance_check_message_export.rb index 04e1a9caa..bbaaa8e3f 100644 --- a/app/models/compliance_check_message_export.rb +++ b/app/models/compliance_check_message_export.rb @@ -26,12 +26,14 @@ class ComplianceCheckMessageExport end def to_csv(options = {}) - CSV.generate(options.slice(:col_sep, :quote_char, :force_quotes)) do |csv| + csv_string = CSV.generate(options.slice(:col_sep, :quote_char, :force_quotes)) do |csv| csv << column_names compliance_check_messages.each do |compliance_check_message| csv << [compliance_check_message.compliance_check.criticity, *compliance_check_message.message_attributes.values_at('test_id', 'source_objectid'), options[:server_url] + compliance_check_message.message_attributes['source_object_path'], I18n.t("compliance_check_messages.#{compliance_check_message.message_key}", compliance_check_message.message_attributes.deep_symbolize_keys)] end end + # We add a BOM to indicate we use UTF-8 + "\uFEFF" + csv_string end def to_zip(temp_file,options = {}) diff --git a/app/models/compliance_control.rb b/app/models/compliance_control.rb index 298a63ab9..537343005 100644 --- a/app/models/compliance_control.rb +++ b/app/models/compliance_control.rb @@ -1,18 +1,16 @@ class ComplianceControl < ActiveRecord::Base + include ComplianceItemSupport class << self def criticities; %i(warning error) end def default_code; "" end - def dynamic_attributes - stored_attributes[:control_attributes] || [] - end def policy_class ComplianceControlPolicy end def subclass_patterns - { + { generic: 'Generic', journey_pattern: 'JourneyPattern', line: 'Line', @@ -30,6 +28,9 @@ class ComplianceControl < ActiveRecord::Base end super end + + def predicate; I18n.t("compliance_controls.#{self.name.underscore}.description") end + def prerequisite; I18n.t("compliance_controls.#{self.name.underscore}.prerequisite") end end extend Enumerize @@ -45,26 +46,25 @@ class ComplianceControl < ActiveRecord::Base validates :compliance_control_set, presence: true validate def coherent_control_set - return true if compliance_control_block_id.nil? - ids = [compliance_control_block.compliance_control_set_id, compliance_control_set_id] - return true if ids.first == ids.last - names = ids.map{|id| ComplianceControlSet.find(id).name} - errors.add(:coherent_control_set, - I18n.t('compliance_controls.errors.incoherent_control_sets', - indirect_set_name: names.first, - direct_set_name: names.last)) -end - + return true if compliance_control_block_id.nil? + ids = [compliance_control_block.compliance_control_set_id, compliance_control_set_id] + return true if ids.first == ids.last + names = ids.map{|id| ComplianceControlSet.find(id).name} + errors.add(:coherent_control_set, + I18n.t('compliance_controls.errors.incoherent_control_sets', + indirect_set_name: names.first, + direct_set_name: names.last)) + end -def initialize(attributes = {}) - super - self.name ||= I18n.t("activerecord.models.#{self.class.name.underscore}.one") - self.code ||= self.class.default_code - self.origin_code ||= self.class.default_code -end + def initialize(attributes = {}) + super + self.name ||= I18n.t("activerecord.models.#{self.class.name.underscore}.one") + self.code ||= self.class.default_code + self.origin_code ||= self.class.default_code + end -def predicate; I18n.t("compliance_controls.#{self.class.name.underscore}.description") end -def prerequisite; I18n.t('compliance_controls.metas.no_prerequisite'); end + def predicate; self.class.predicate end + def prerequisite; self.class.prerequisite end end diff --git a/app/models/concerns/compliance_item_support.rb b/app/models/concerns/compliance_item_support.rb new file mode 100644 index 000000000..f44f5719f --- /dev/null +++ b/app/models/concerns/compliance_item_support.rb @@ -0,0 +1,13 @@ +module ComplianceItemSupport + extend ActiveSupport::Concern + included do + + end + + module ClassMethods + def dynamic_attributes + stored_attributes[:control_attributes] || [] + end + end + +end diff --git a/app/models/concerns/custom_fields_support.rb b/app/models/concerns/custom_fields_support.rb new file mode 100644 index 000000000..6c76bd653 --- /dev/null +++ b/app/models/concerns/custom_fields_support.rb @@ -0,0 +1,24 @@ +module CustomFieldsSupport + extend ActiveSupport::Concern + + included do + validate :custom_fields_values_are_valid + + def self.custom_fields + CustomField.where(resource_type: self.name.split("::").last) + end + + def custom_fields + CustomField::Collection.new self + end + + def custom_field_value key + (custom_field_values || {})[key.to_s] + end + + private + def custom_fields_values_are_valid + custom_fields.values.all?{|cf| cf.valid?} + end + end +end diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index 774c8b0f6..4a840744e 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -6,4 +6,80 @@ class CustomField < ActiveRecord::Base validates :name, uniqueness: {scope: [:resource_type, :workgroup_id]} validates :code, uniqueness: {scope: [:resource_type, :workgroup_id], case_sensitive: false} + + class Collection < HashWithIndifferentAccess + def initialize object + vals = object.class.custom_fields.map do |v| + [v.code, CustomField::Value.new(object, v, object.custom_field_value(v.code))] + end + super Hash[*vals.flatten] + end + + def to_hash + HashWithIndifferentAccess[*self.map{|k, v| [k, v.to_hash]}.flatten(1)] + end + end + + class Value + def self.new owner, custom_field, value + field_type = custom_field.options["field_type"] + klass_name = field_type && "CustomField::Value::#{field_type.classify}" + klass = klass_name && const_defined?(klass_name) ? klass_name.constantize : CustomField::Value::Base + klass.new owner, custom_field, value + end + + class Base + def initialize owner, custom_field, value + @custom_field = custom_field + @raw_value = value + @owner = owner + @errors = [] + @validated = false + @valid = false + end + + delegate :code, :name, :field_type, :options, to: :@custom_field + + def validate + @valid = true + end + + def valid? + validate unless @validated + @valid + end + + def value + @raw_value + end + + def errors_key + "custom_fields.#{code}" + end + + def to_hash + HashWithIndifferentAccess[*%w(code name field_type options value).map{|k| [k, send(k)]}.flatten(1)] + end + end + + class Integer < Base + def value + @raw_value.to_i + end + + def validate + @valid = true + unless @raw_value =~ /\A\d*\Z/ + @owner.errors.add errors_key, "'#{@raw_value}' is not a valid integer" + @valid = false + end + end + end + + class String < Base + def value + "#{@raw_value}" + end + end + end end diff --git a/app/models/dashboard.rb b/app/models/dashboard.rb index 46c621266..bcd92de5a 100644 --- a/app/models/dashboard.rb +++ b/app/models/dashboard.rb @@ -27,4 +27,16 @@ class Dashboard def current_organisation context.send(:current_organisation) end + + def workbench + @workbench ||= current_organisation.workbenches.default + end + + def workgroup + workbench.workgroup + end + + def calendars + workgroup.calendars.where('(organisation_id = ? OR shared = ?)', current_organisation.id, true) + end end diff --git a/app/models/import_message_export.rb b/app/models/import_message_export.rb index 05f8a2cc7..991eb0f61 100644 --- a/app/models/import_message_export.rb +++ b/app/models/import_message_export.rb @@ -26,12 +26,14 @@ class ImportMessageExport end def to_csv(options = {}) - CSV.generate(options) do |csv| + csv_string = CSV.generate(options) do |csv| csv << column_names import_messages.each do |import_message| csv << [import_message.criticity, import_message.message_key, I18n.t("import_messages.#{import_message.message_key}", import_message.message_attributes.deep_symbolize_keys), *import_message.resource_attributes.values_at("filename", "line_number", "column_number") ] end end + # We add a BOM to indicate we use UTF-8 + "\uFEFF" + csv_string end def to_zip(temp_file,options = {}) diff --git a/app/models/merge.rb b/app/models/merge.rb index 62bf581d6..d42d882ac 100644 --- a/app/models/merge.rb +++ b/app/models/merge.rb @@ -152,7 +152,7 @@ class Merge < ActiveRecord::Base route_stop_points = referential_stop_points_by_route[route.id] # Stop Points - route_stop_points.each do |stop_point| + route_stop_points.sort_by(&:position).each do |stop_point| objectid = Chouette::StopPoint.where(objectid: stop_point.objectid).exists? ? nil : stop_point.objectid attributes = stop_point.attributes.merge( id: nil, @@ -166,7 +166,7 @@ class Merge < ActiveRecord::Base new_route.save! if new_route.checksum != route.checksum - raise "Checksum has changed: #{route.inspect} #{new_route.inspect}" + raise "Checksum has changed: \"#{route.checksum}\", \"#{route.checksum_source}\" -> \"#{new_route.checksum}\", \"#{new_route.checksum_source}\"" end end end @@ -221,7 +221,7 @@ class Merge < ActiveRecord::Base new_journey_pattern = new.journey_patterns.create! attributes if new_journey_pattern.checksum != journey_pattern.checksum - raise "Checksum has changed for #{journey_pattern.inspect}: #{journey_pattern.checksum_source} #{new_journey_pattern.checksum_source} " + raise "Checksum has changed for #{journey_pattern.inspect}: \"#{journey_pattern.checksum_source}\" -> \"#{new_journey_pattern.checksum_source}\"" end end end diff --git a/app/models/organisation.rb b/app/models/organisation.rb index e8fb4e060..745bc0d22 100644 --- a/app/models/organisation.rb +++ b/app/models/organisation.rb @@ -13,6 +13,8 @@ class Organisation < ActiveRecord::Base has_many :line_referentials, through: :line_referential_memberships has_many :workbenches + has_many :workgroups, through: :workbenches + has_many :calendars has_many :api_keys, class_name: 'Api::V1::ApiKey' diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index c44937c9e..33d88660c 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -95,7 +95,6 @@ class ApplicationPolicy referential.try(:organisation_id) || record.try(:organisation_id) end - # # Helpers # ------- diff --git a/app/policies/compliance_control_set_policy.rb b/app/policies/compliance_control_set_policy.rb index 011f6c0c7..55507ffd9 100644 --- a/app/policies/compliance_control_set_policy.rb +++ b/app/policies/compliance_control_set_policy.rb @@ -5,6 +5,10 @@ class ComplianceControlSetPolicy < ApplicationPolicy end end + def show? + organisation_match? + end + def destroy? user.has_permission?('compliance_control_sets.destroy') end diff --git a/app/services/referential_overview.rb b/app/services/referential_overview.rb index ccfe0617a..7ef2909ad 100644 --- a/app/services/referential_overview.rb +++ b/app/services/referential_overview.rb @@ -208,7 +208,11 @@ class ReferentialOverview end def span - h.l(@start_date, format: "#{@start_date.day}-#{@end_date.day} %b") + if @start_date.month == @end_date.month + h.l(@start_date, format: "#{@start_date.day}-#{@end_date.day} %b %Y") + else + "#{h.l(@start_date, format: "%d %b")} - #{h.l(@end_date, format: "%d %b %Y")}" + end end def number diff --git a/app/views/calendars/_form_advanced.html.slim b/app/views/calendars/_form_advanced.html.slim index e796e2e36..aa4fd4e40 100644 --- a/app/views/calendars/_form_advanced.html.slim +++ b/app/views/calendars/_form_advanced.html.slim @@ -3,6 +3,6 @@ = javascript_tag do | window.actionType = "#{raw params[:action]}"; // | window.I18n = #{(I18n.backend.send(:translations)[I18n.locale].to_json).html_safe}; - | window.timetablesUrl = "#{calendar_url(@calendar).html_safe}"; + | window.timetablesUrl = "#{workgroup_calendar_url(@workgroup, @calendar).html_safe}"; = javascript_pack_tag 'calendars/edit.js' diff --git a/app/views/compliance_check_sets/index.html.slim b/app/views/compliance_check_sets/index.html.slim index 31ad31e5b..9abd95dd1 100644 --- a/app/views/compliance_check_sets/index.html.slim +++ b/app/views/compliance_check_sets/index.html.slim @@ -23,9 +23,10 @@ ), \ TableBuilderHelper::Column.new( \ key: :associated_object, \ - attribute: Proc.new{|n| n.referential.present? ? n.referential.name : ''}, \ + if: ->(compliance_check_set){ compliance_check_set.referential.present? }, \ + attribute: Proc.new{|n| n.referential.name}, \ link_to: lambda do |compliance_check_set| \ - compliance_check_set.referential.present? ? referential_path(compliance_check_set.referential_id) : '#' \ + referential_path(compliance_check_set.referential_id) \ end \ ), \ TableBuilderHelper::Column.new( \ @@ -42,6 +43,8 @@ ], sortable: true, cls: 'table has-filter has-search' + + = new_pagination @compliance_check_sets, 'pull-right' - unless @compliance_check_sets.any? .row.mt-xs .col-lg-12 diff --git a/app/views/compliance_checks/show.html.slim b/app/views/compliance_checks/show.html.slim new file mode 100644 index 000000000..8dd699c65 --- /dev/null +++ b/app/views/compliance_checks/show.html.slim @@ -0,0 +1,13 @@ +- breadcrumb :compliance_check, @workbench, resource +- page_header_content_for resource + + +.page_content + .container-fluid + .row + .col-lg-6.col-md-6.col-sm-12.col-xs-12 + = render partial: "shared/controls/metadatas" + - if resource.compliance_check_block + = definition_list t('compliance_controls.show.metadatas.compliance_check_block'), + I18n.t('activerecord.attributes.compliance_control_blocks.transport_mode') => I18n.t("enumerize.transport_mode.#{resource.compliance_check_block.transport_mode}"), + I18n.t('activerecord.attributes.compliance_control_blocks.transport_submode') => I18n.t("enumerize.transport_submode.#{resource.compliance_check_block.transport_submode}") diff --git a/app/views/compliance_controls/_filters.html.slim b/app/views/compliance_controls/_filters.html.slim index f6b9970f2..a16d2c33d 100644 --- a/app/views/compliance_controls/_filters.html.slim +++ b/app/views/compliance_controls/_filters.html.slim @@ -5,8 +5,8 @@ class: 'form form-filter' do |f| .ffg-row - .input-group.search_bar class=filter_item_class(params[:q], :name_cont) - = f.search_field :name_cont, + .input-group.search_bar class=filter_item_class(params[:q], :name_or_code_cont) + = f.search_field :name_or_code_cont, class: 'form-control', placeholder: t('compliance_controls.filters.name') span.input-group-btn diff --git a/app/views/compliance_controls/show.html.slim b/app/views/compliance_controls/show.html.slim index ab25747a9..6e7a45d12 100644 --- a/app/views/compliance_controls/show.html.slim +++ b/app/views/compliance_controls/show.html.slim @@ -6,22 +6,7 @@ .container-fluid .row .col-lg-6.col-md-6.col-sm-12.col-xs-12 - /- @compliance_control.control_attributes.each_with_index do |(key,value), index| - = definition_list t('metadatas'), - { \ - ComplianceControl.human_attribute_name(:name) => @compliance_control.name, - ComplianceControl.human_attribute_name(:code) => @compliance_control.code, - ComplianceControl.human_attribute_name(:criticity) => @compliance_control.criticity, - ComplianceControl.human_attribute_name(:comment) => @compliance_control.comment, - I18n.t('activerecord.attributes.compliance_control.predicate') => @compliance_control.predicate, - I18n.t('activerecord.attributes.compliance_control.prerequisite') => @compliance_control.prerequisite, - }.merge( \ - {}.tap do |hash| \ - @compliance_control.class.dynamic_attributes.each do |attribute| \ - hash[ComplianceControl.human_attribute_name(attribute)] = @compliance_control.send(attribute) \ - end \ - end \ - ) + = render partial: "shared/controls/metadatas" - if @compliance_control.compliance_control_block = definition_list t('compliance_controls.show.metadatas.compliance_control_block'), I18n.t('activerecord.attributes.compliance_control_blocks.transport_mode') => I18n.t("enumerize.transport_mode.#{@compliance_control.compliance_control_block.transport_mode}"), diff --git a/app/views/dashboards/_dashboard.html.slim b/app/views/dashboards/_dashboard.html.slim index 7f78934a6..8d0e723a6 100644 --- a/app/views/dashboards/_dashboard.html.slim +++ b/app/views/dashboards/_dashboard.html.slim @@ -22,12 +22,12 @@ .panel.panel-default .panel-heading h3.panel-title.with_actions - = link_to I18n.t("activerecord.models.calendar", count: @dashboard.current_organisation.calendars.size), workgroup_calendars_path(workbench.workgroup) + = link_to I18n.t("activerecord.models.calendar", count: @dashboard.calendars.size), workgroup_calendars_path(workbench.workgroup) div = link_to '', workgroup_calendars_path(workbench.workgroup), class: ' fa fa-chevron-right pull-right' - - if @dashboard.current_organisation.calendars.present? + - if @dashboard.calendars.present? .list-group - - @dashboard.current_organisation.calendars.order("updated_at desc").limit(5).each do |calendar| + - @dashboard.calendars.order("updated_at desc").limit(5).each do |calendar| = link_to calendar.name, workgroup_calendars_path(workbench.workgroup, calendar), class: 'list-group-item' - else .panel-body diff --git a/app/views/lines/show.html.slim b/app/views/lines/show.html.slim index 34b907bdd..96bb5bb0d 100644 --- a/app/views/lines/show.html.slim +++ b/app/views/lines/show.html.slim @@ -6,13 +6,13 @@ .row .col-lg-6.col-md-6.col-sm-12.col-xs-12 = definition_list t('metadatas'), - { 'ID Codif' => @line.get_objectid.short_id, - 'Activé' => (@line.deactivated? ? t('false') : t('true')), + { t('id_codif') => @line.get_objectid.short_id, + @line.human_attribute_name(:deactivated) => (@line.deactivated? ? t('false') : t('true')), @line.human_attribute_name(:network_id) => (@line.network.nil? ? t('lines.index.unset') : @line.network.name), @line.human_attribute_name(:company_id) => (@line.company.nil? ? t('lines.index.unset') : @line.company.name), - 'Transporteur(s) secondaire(s)' => (@line.secondary_companies.nil? ? t('lines.index.unset') : array_to_html_list(@line.secondary_companies.collect(&:name))), - 'Nom court' => @line.number, - 'Code public' => (@line.registration_number ? @line.registration_number : '-'), + @line.human_attribute_name(:secondary_companies) => (@line.secondary_companies.nil? ? t('lines.index.unset') : array_to_html_list(@line.secondary_companies.collect(&:name))), + @line.human_attribute_name(:number) => @line.number, + @line.human_attribute_name(:registration_number) => (@line.registration_number ? @line.registration_number : '-'), @line.human_attribute_name(:transport_mode) => (@line.transport_mode.present? ? t("enumerize.transport_mode.#{@line.transport_mode}") : '-'), @line.human_attribute_name(:transport_submode) => (@line.transport_submode.present? ? t("enumerize.transport_submode.#{@line.transport_submode}") : '-'), @line.human_attribute_name(:url) => (@line.url ? @line.url : '-'), diff --git a/app/views/referential_lines/show.html.slim b/app/views/referential_lines/show.html.slim index 5ea0e31bb..ef32ef6b0 100644 --- a/app/views/referential_lines/show.html.slim +++ b/app/views/referential_lines/show.html.slim @@ -82,6 +82,6 @@ = replacement_msg t('routes.search_no_results') = javascript_tag do - | window.routes = "#{URI.escape(@routes.map{|r| {name: r.name, id: r.id, stops: route_json_for_edit(r, serialize: false)}}.to_json)}" + | window.routes = "#{URI.escape(@routes.select{|r| r.wayback == :outbound}.map{|r| {name: r.name, id: r.id, stops: route_json_for_edit(r, serialize: false)}}.to_json)}" = javascript_pack_tag 'referential_lines/show.js' diff --git a/app/views/referentials/_form.html.slim b/app/views/referentials/_form.html.slim index 1e59ab566..96d847ec1 100644 --- a/app/views/referentials/_form.html.slim +++ b/app/views/referentials/_form.html.slim @@ -47,8 +47,13 @@ = link_to_add_association t('simple_form.labels.referential.actions.add_period'), subform, :periods, class: 'btn btn-outline-primary' .separator + .row + .col-lg-11 + = subform.input :lines, as: :select, collection: Chouette::Line.includes(:company).order(:name).where(objectid: current_functional_scope), selected: subform.object.line_ids, label_method: :display_name, input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': t('simple_form.labels.referential.placeholders.select_lines'), 'multiple': 'multiple', style: 'width: 100%' } + .col-lg-1 + a.clear-lines.btn.btn-default href='#' + .fa.fa-trash - = subform.input :lines, as: :select, collection: Chouette::Line.includes(:company).order(:name).where(objectid: current_functional_scope), selected: subform.object.line_ids, label_method: :display_name, input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': t('simple_form.labels.referential.placeholders.select_lines'), 'multiple': 'multiple', style: 'width: 100%' } .hidden = form.input :workbench_id, as: :hidden @@ -58,3 +63,10 @@ class: 'btn btn-default formSubmitr', data: { disable_with: t('actions.processing') }, form: 'referential_form' + + - content_for :javascript do + coffee: + $(".clear-lines").click (e)-> + e.preventDefault() + $(e.currentTarget).parents('.row').first().find('[name*=line]').val('').trigger('change') + false diff --git a/app/views/referentials/_overview.html.slim b/app/views/referentials/_overview.html.slim index 870f642d4..6bed5f282 100644 --- a/app/views/referentials/_overview.html.slim +++ b/app/views/referentials/_overview.html.slim @@ -35,9 +35,12 @@ .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 + a.line title=line.name + - if line.number.present? + .number style="background-color: #{line.color.present? ? "##{line.color}" : 'whitesmoke'}" + = line.number + - else + .name= line.name .company= line.company&.name .mode= line.transport_mode.present? ? t("enumerize.transport_mode.#{line.transport_mode}") : "" .right diff --git a/app/views/shared/controls/_metadatas.html.slim b/app/views/shared/controls/_metadatas.html.slim new file mode 100644 index 000000000..49df06166 --- /dev/null +++ b/app/views/shared/controls/_metadatas.html.slim @@ -0,0 +1,15 @@ += definition_list t('metadatas'), + { \ + ComplianceControl.human_attribute_name(:name) => resource.name, + ComplianceControl.human_attribute_name(:code) => resource.code, + ComplianceControl.human_attribute_name(:criticity) => resource.criticity, + ComplianceControl.human_attribute_name(:comment) => resource.comment, + I18n.t('activerecord.attributes.compliance_control.predicate') => resource.predicate, + I18n.t('activerecord.attributes.compliance_control.prerequisite') => resource.prerequisite, + }.merge( \ + {}.tap do |hash| \ + resource.class.dynamic_attributes.each do |attribute| \ + hash[ComplianceControl.human_attribute_name(attribute)] = resource.send(attribute) \ + end \ + end \ + ) diff --git a/app/views/stop_areas/show.html.slim b/app/views/stop_areas/show.html.slim index a4e14a272..34b872e91 100644 --- a/app/views/stop_areas/show.html.slim +++ b/app/views/stop_areas/show.html.slim @@ -20,7 +20,7 @@ @stop_area.human_attribute_name(:zip_code) => @stop_area.zip_code, @stop_area.human_attribute_name(:city_name) => @stop_area.city_name, @stop_area.human_attribute_name(:country_code) => @stop_area.country_code.presence || '-', - 'Etat' => (@stop_area.deleted_at ? 'Supprimé' : 'Actif'), + t('activerecord.attributes.stop_area.state') => (@stop_area.deleted_at ? t('stop_areas.show.state.deactivated') : t('stop_areas.show.state.active')), @stop_area.human_attribute_name(:comment) => @stop_area.try(:comment), }) = definition_list t('metadatas'), attributes |
