From f6f52147fcec3b9283dc2890cfb05b0fb19bff33 Mon Sep 17 00:00:00 2001 From: Zog Date: Fri, 26 Jan 2018 12:49:23 +0100 Subject: Refs #5741 @2h; Add a map of all routes on a line#show --- Gemfile.lock | 22 +-- app/assets/stylesheets/OpenLayers/custom.sass | 21 +++ app/helpers/routes_helper.rb | 8 +- app/javascript/helpers/routes_map.coffee | 157 ++++++++++++++++++++++ app/javascript/packs/referential_lines/show.js | 10 ++ app/javascript/packs/routes/show.js | 123 +---------------- app/javascript/routes/components/StopPointList.js | 4 +- app/views/referential_lines/show.html.slim | 8 +- config/webpack/environment.js | 2 + config/webpack/loaders/coffee.js | 6 + package.json | 3 +- yarn.lock | 12 +- 12 files changed, 238 insertions(+), 138 deletions(-) create mode 100644 app/javascript/helpers/routes_map.coffee create mode 100644 app/javascript/packs/referential_lines/show.js create mode 100644 config/webpack/loaders/coffee.js diff --git a/Gemfile.lock b/Gemfile.lock index 09ef00f94..f4dfe1bf7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -156,6 +156,7 @@ GEM sort_alphabetical (~> 1.0) crack (0.4.3) safe_yaml (~> 1.0.0) + crass (1.0.3) cucumber (2.4.0) builder (>= 2.1.2) cucumber-core (~> 1.5.0) @@ -265,7 +266,7 @@ GEM htmlbeautifier (1.3.1) httparty (0.14.0) multi_xml (>= 0.5.2) - i18n (0.9.0) + i18n (0.9.3) concurrent-ruby (~> 1.0) i18n-tasks (0.9.15) activesupport (>= 4.0.2) @@ -302,7 +303,8 @@ GEM thor with_env (> 1.0) xml-simple - loofah (2.0.3) + loofah (2.1.1) + crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.6.4) mime-types (>= 1.16, < 4) @@ -313,7 +315,7 @@ GEM mime-types-data (3.2016.0521) mimemagic (0.3.2) mini_portile2 (2.3.0) - minitest (5.10.3) + minitest (5.11.2) money (6.10.1) i18n (>= 0.6.4, < 1.0) multi_json (1.12.1) @@ -368,7 +370,7 @@ GEM rack rack-protection (1.5.3) rack - rack-proxy (0.6.2) + rack-proxy (0.6.3) rack rack-test (0.6.3) rack (>= 1.0) @@ -396,8 +398,8 @@ GEM rails-assets-jquery (>= 1.0.0) rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.8) - activesupport (>= 4.2.0.beta, < 5.0) + rails-dom-testing (1.0.9) + activesupport (>= 4.2.0, < 5.0) nokogiri (~> 1.6) rails-deprecated_sanitizer (>= 1.0.1) rails-erd (1.5.2) @@ -419,7 +421,7 @@ GEM thor (>= 0.18.1, < 2.0) rainbow (2.2.2) rake - rake (12.0.0) + rake (12.3.0) ransack (1.8.3) actionpack (>= 3.0) activerecord (>= 3.0) @@ -541,7 +543,7 @@ GEM therubyracer (0.12.3) libv8 (~> 3.16.14.15) ref - thor (0.19.4) + thor (0.20.0) thread (0.2.2) thread_safe (0.3.6) tilt (1.4.1) @@ -553,7 +555,7 @@ GEM json (>= 1.8, < 3.0) parser (>= 2.3.0.7) rainbow (>= 1.99.1, < 3.0) - tzinfo (1.2.3) + tzinfo (1.2.4) thread_safe (~> 0.1) uglifier (2.7.2) execjs (>= 0.3.0) @@ -566,7 +568,7 @@ GEM addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff - webpacker (3.0.2) + webpacker (3.2.1) activesupport (>= 4.2) rack-proxy (>= 0.6.1) railties (>= 4.2) diff --git a/app/assets/stylesheets/OpenLayers/custom.sass b/app/assets/stylesheets/OpenLayers/custom.sass index 7a5b4baf1..5a3612f99 100644 --- a/app/assets/stylesheets/OpenLayers/custom.sass +++ b/app/assets/stylesheets/OpenLayers/custom.sass @@ -2,6 +2,27 @@ .list-group-item & margin-top: 15px + .routes-labels + padding: 0 + display: flex + justify-content: space-between + flex-wrap: wrap + margin: 5px -5px + li + list-style-type: none + flex: 1 0 25% + border: 1px solid $lightgrey + padding: 5px + margin: 5px + border-radius: 5px + cursor: pointer + color: $blue + white-space: nowrap + max-width: 33% + + &:hover + background: $orange + color: white .ol-scale-line background-color: transparent diff --git a/app/helpers/routes_helper.rb b/app/helpers/routes_helper.rb index 4bffa99d4..61714a066 100644 --- a/app/helpers/routes_helper.rb +++ b/app/helpers/routes_helper.rb @@ -19,13 +19,15 @@ module RoutesHelper css end - def route_json_for_edit(route) - route.stop_points.includes(:stop_area).order(:position).map do |stop_point| + def route_json_for_edit(route, serialize: true) + data = route.stop_points.includes(:stop_area).order(:position).map do |stop_point| stop_area_attributes = stop_point.stop_area.attributes.slice("name","city_name", "zip_code", "registration_number", "longitude", "latitude", "area_type", "comment") stop_area_attributes["short_name"] = truncate(stop_area_attributes["name"], :length => 30) || "" stop_point_attributes = stop_point.attributes.slice("for_boarding","for_alighting") stop_area_attributes.merge(stop_point_attributes).merge(stoppoint_id: stop_point.id, stoparea_id: stop_point.stop_area.id).merge(user_objectid: stop_point.stop_area.user_objectid) - end.to_json + end + data = data.to_json if serialize + data end end diff --git a/app/javascript/helpers/routes_map.coffee b/app/javascript/helpers/routes_map.coffee new file mode 100644 index 000000000..85def1390 --- /dev/null +++ b/app/javascript/helpers/routes_map.coffee @@ -0,0 +1,157 @@ +class RoutesMap + constructor: (@target)-> + @initMap() + @area = [] + @seenStopIds = [] + @routes = {} + + initMap: -> + @map = new ol.Map + target: @target, + layers: [ new ol.layer.Tile(source: new ol.source.OSM()) ] + controls: [ new ol.control.ScaleLine(), new ol.control.Zoom(), new ol.control.ZoomSlider() ], + interactions: ol.interaction.defaults(zoom: true) + view: new ol.View() + + addRoutes: (routes)-> + for route in routes + @addRoute route + + addRoute: (route)-> + geoColPts = [] + geoColLns = [] + @routes[route.id] = route if route.id + stops = route.stops || route + geoColEdges = [ + new ol.Feature({ + geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stops[0].longitude), parseFloat(stops[0].latitude)])) + }), + new ol.Feature({ + geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stops[stops.length - 1].longitude), parseFloat(stops[stops.length - 1].latitude)])) + }) + ] + stops.forEach (stop, i) => + if i < stops.length - 1 + geoColLns.push new ol.Feature + geometry: new ol.geom.LineString([ + ol.proj.fromLonLat([parseFloat(stops[i].longitude), parseFloat(stops[i].latitude)]), + ol.proj.fromLonLat([parseFloat(stops[i + 1].longitude), parseFloat(stops[i + 1].latitude)]) + ]) + + geoColPts.push(new ol.Feature({ + geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stop.longitude), parseFloat(stop.latitude)])) + })) + unless @seenStopIds.indexOf(stop.stoparea_id) > 0 + @area.push [parseFloat(stop.longitude), parseFloat(stop.latitude)] + @seenStopIds.push stop.stoparea_id + + vectorPtsLayer = new ol.layer.Vector({ + source: new ol.source.Vector({ + features: geoColPts + }), + style: @defaultStyles(), + zIndex: 2 + }) + route.vectorPtsLayer = vectorPtsLayer if route.id + vectorEdgesLayer = new ol.layer.Vector({ + source: new ol.source.Vector({ + features: geoColEdges + }), + style: @edgeStyles(), + zIndex: 3 + }) + route.vectorEdgesLayer = vectorEdgesLayer if route.id + vectorLnsLayer = new ol.layer.Vector({ + source: new ol.source.Vector({ + features: geoColLns + }), + style: [@lineStyle()], + zIndex: 1 + }) + route.vectorLnsLayer = vectorLnsLayer if route.id + @map.addLayer vectorPtsLayer + @map.addLayer vectorEdgesLayer + @map.addLayer vectorLnsLayer + + lineStyle: (highlighted=false)-> + new ol.style.Style + stroke: new ol.style.Stroke + color: if highlighted then "#ed7f00" else '#007fbb' + width: 3 + + edgeStyles: (highlighted=false)-> + 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 + fill: new ol.style.Fill + color: if highlighted then "#ed7f00" else '#007fbb' + width: 2 + + defaultStyles: (highlighted=false)-> + 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 + fill: new ol.style.Fill + color: '#ffffff' + width: 2 + + addRoutesLabels: -> + labelsContainer = $("") + labelsContainer.appendTo $("##{@target}") + @vectorPtsLayer = null + @vectorEdgesLayer = null + @vectorLnsLayer = null + Object.keys(@routes).forEach (id)=> + route = @routes[id] + label = $("
  • #{route.name}") + 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 + boundaries = ol.extent.applyTransform( + ol.extent.boundingExtent(area), ol.proj.getTransform('EPSG:4326', 'EPSG:3857') + ) + @map.getView().fit boundaries, @map.getSize() + tooCloseToBounds = false + mapBoundaries = @map.getView().calculateExtent @map.getSize() + mapWidth = mapBoundaries[2] - mapBoundaries[0] + mapHeight = mapBoundaries[3] - mapBoundaries[1] + marginSize = 0.1 + heightMargin = marginSize * mapHeight + widthMargin = marginSize * mapWidth + tooCloseToBounds = tooCloseToBounds || (boundaries[0] - mapBoundaries[0]) < widthMargin + tooCloseToBounds = tooCloseToBounds || (mapBoundaries[2] - boundaries[2]) < widthMargin + tooCloseToBounds = tooCloseToBounds || (boundaries[1] - mapBoundaries[1]) < heightMargin + tooCloseToBounds = tooCloseToBounds || (mapBoundaries[3] - boundaries[3]) < heightMargin + if tooCloseToBounds + @map.getView().setZoom(@map.getView().getZoom() - 1) + + +export default RoutesMap diff --git a/app/javascript/packs/referential_lines/show.js b/app/javascript/packs/referential_lines/show.js new file mode 100644 index 000000000..99c5072ef --- /dev/null +++ b/app/javascript/packs/referential_lines/show.js @@ -0,0 +1,10 @@ +import clone from '../../helpers/clone' +import RoutesMap from '../../helpers/routes_map' + +let routes = clone(window, "routes", true) +routes = JSON.parse(decodeURIComponent(routes)) + +var map = new RoutesMap('routes_map') +map.addRoutes(routes) +map.addRoutesLabels() +map.fitZoom() diff --git a/app/javascript/packs/routes/show.js b/app/javascript/packs/routes/show.js index 71777c379..c20de0800 100644 --- a/app/javascript/packs/routes/show.js +++ b/app/javascript/packs/routes/show.js @@ -1,121 +1,8 @@ import clone from '../../helpers/clone' +import RoutesMap from '../../helpers/routes_map' + let route = clone(window, "route", true) route = JSON.parse(decodeURIComponent(route)) - -const geoColPts = [] -const geoColLns = [] -const area = [] -const geoColEdges = [ - new ol.Feature({ - geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(route[0].longitude), parseFloat(route[0].latitude)])) - }), - new ol.Feature({ - geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(route[route.length - 1].longitude), parseFloat(route[route.length - 1].latitude)])) - }) -] -route.forEach(function (stop, i) { - if (i < route.length - 1) { - geoColLns.push(new ol.Feature({ - geometry: new ol.geom.LineString([ - ol.proj.fromLonLat([parseFloat(route[i].longitude), parseFloat(route[i].latitude)]), - ol.proj.fromLonLat([parseFloat(route[i + 1].longitude), parseFloat(route[i + 1].latitude)]) - ]) - })) - } - geoColPts.push(new ol.Feature({ - geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stop.longitude), parseFloat(stop.latitude)])) - })) - area.push([parseFloat(stop.longitude), parseFloat(stop.latitude)]) -}) -var edgeStyles = new ol.style.Style({ - image: new ol.style.Circle(({ - radius: 5, - stroke: new ol.style.Stroke({ - color: '#007fbb', - width: 2 - }), - fill: new ol.style.Fill({ - color: '#007fbb', - width: 2 - }) - })) -}) -var defaultStyles = new ol.style.Style({ - image: new ol.style.Circle(({ - radius: 4, - stroke: new ol.style.Stroke({ - color: '#007fbb', - width: 2 - }), - fill: new ol.style.Fill({ - color: '#ffffff', - width: 2 - }) - })) -}) -var lineStyle = new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: '#007fbb', - width: 3 - }) -}) - -var vectorPtsLayer = new ol.layer.Vector({ - source: new ol.source.Vector({ - features: geoColPts - }), - style: defaultStyles, - zIndex: 2 -}) -var vectorEdgesLayer = new ol.layer.Vector({ - source: new ol.source.Vector({ - features: geoColEdges - }), - style: edgeStyles, - zIndex: 3 -}) -var vectorLnsLayer = new ol.layer.Vector({ - source: new ol.source.Vector({ - features: geoColLns - }), - style: [lineStyle], - zIndex: 1 -}) - -var map = new ol.Map({ - target: 'route_map', - layers: [ - new ol.layer.Tile({ - source: new ol.source.OSM() - }), - vectorPtsLayer, - vectorEdgesLayer, - vectorLnsLayer - ], - controls: [new ol.control.ScaleLine(), new ol.control.Zoom(), new ol.control.ZoomSlider()], - interactions: ol.interaction.defaults({ - zoom: true - }), - view: new ol.View({ - center: ol.proj.fromLonLat([parseFloat(route[0].longitude), parseFloat(route[0].latitude)]), - zoom: 13 - }) -}); -const boundaries = ol.extent.applyTransform( - ol.extent.boundingExtent(area), ol.proj.getTransform('EPSG:4326', 'EPSG:3857') -) -map.getView().fit(boundaries, map.getSize()); -let tooCloseToBounds = false -const mapBoundaries = map.getView().calculateExtent(map.getSize()) -const mapWidth = mapBoundaries[2] - mapBoundaries[0] -const mapHeight = mapBoundaries[3] - mapBoundaries[1] -const marginSize = 0.1 -const heightMargin = marginSize * mapHeight -const widthMargin = marginSize * mapWidth -tooCloseToBounds = tooCloseToBounds || (boundaries[0] - mapBoundaries[0]) < widthMargin -tooCloseToBounds = tooCloseToBounds || (mapBoundaries[2] - boundaries[2]) < widthMargin -tooCloseToBounds = tooCloseToBounds || (boundaries[1] - mapBoundaries[1]) < heightMargin -tooCloseToBounds = tooCloseToBounds || (mapBoundaries[3] - boundaries[3]) < heightMargin -if(tooCloseToBounds){ - map.getView().setZoom(map.getView().getZoom() - 1) -} +var map = new RoutesMap('route_map') +map.addRoute(route) +map.fitZoom() diff --git a/app/javascript/routes/components/StopPointList.js b/app/javascript/routes/components/StopPointList.js index 43a027084..b39fa0c9c 100644 --- a/app/javascript/routes/components/StopPointList.js +++ b/app/javascript/routes/components/StopPointList.js @@ -56,7 +56,7 @@ export default function StopPointList({ stopPoints, onDeleteClick, onMoveUpClick ) } -StopPointList.PropTypes = { +StopPointList.propTypes = { stopPoints: PropTypes.array.isRequired, onDeleteClick: PropTypes.func.isRequired, onMoveUpClick: PropTypes.func.isRequired, @@ -68,4 +68,4 @@ StopPointList.PropTypes = { StopPointList.contextTypes = { I18n: PropTypes.object -} \ No newline at end of file +} diff --git a/app/views/referential_lines/show.html.slim b/app/views/referential_lines/show.html.slim index 02d605d8c..5ea0e31bb 100644 --- a/app/views/referential_lines/show.html.slim +++ b/app/views/referential_lines/show.html.slim @@ -17,7 +17,8 @@ @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 : '-'), @line.human_attribute_name(:seasonal) => (@line.seasonal? ? t('true') : t('false')),} - + .col-lg-6.col-md-6.col-sm-12.col-xs-12 + #routes_map.map.mb-lg .row .col-lg-12 .h3 = t('lines.show.routes.title') @@ -79,3 +80,8 @@ .row.mt-xs .col-lg-12 = 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)}" + += javascript_pack_tag 'referential_lines/show.js' diff --git a/config/webpack/environment.js b/config/webpack/environment.js index e7c879fb9..688bcbe8e 100644 --- a/config/webpack/environment.js +++ b/config/webpack/environment.js @@ -1,4 +1,5 @@ const { environment } = require('@rails/webpacker') +const coffee = require('./loaders/coffee') const CleanWebpackPlugin = require('clean-webpack-plugin') let pathsToClean = [ @@ -24,4 +25,5 @@ environment.plugins.set( // jquery: "jquery/src/jquery", // } +environment.loaders.append('coffee', coffee) module.exports = environment diff --git a/config/webpack/loaders/coffee.js b/config/webpack/loaders/coffee.js new file mode 100644 index 000000000..4666716dc --- /dev/null +++ b/config/webpack/loaders/coffee.js @@ -0,0 +1,6 @@ +module.exports = { + test: /\.coffee(\.erb)?$/, + use: [{ + loader: 'coffee-loader' + }] +} diff --git a/package.json b/package.json index 80ca22f83..802a2eef7 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "babel-preset-react": "6.24.1", "babelify": "8.0.0", "bootstrap": "3", - "coffeescript": "2.1.0", + "coffee-loader": "^0.9.0", + "coffeescript": "1.12.7", "jquery": "3.2.1", "lodash": "4.17.4", "promise-polyfill": "7.0.0", diff --git a/yarn.lock b/yarn.lock index e95ee9a63..d17ae1d52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1404,13 +1404,19 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" +coffee-loader@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/coffee-loader/-/coffee-loader-0.9.0.tgz#6deabd336062ddc6d773da4dfd16367fc7107bd6" + dependencies: + loader-utils "^1.0.2" + coffee-script@~1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.10.0.tgz#12938bcf9be1948fa006f92e0c4c9e81705108c0" -coffeescript@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-2.1.0.tgz#8cb7ce12021ab9f84d8c524f54edbd6141374606" +coffeescript@1.12.7: + version "1.12.7" + resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-1.12.7.tgz#e57ee4c4867cf7f606bfc4a0f2d550c0981ddd27" color-convert@^1.3.0, color-convert@^1.8.2, color-convert@^1.9.0: version "1.9.0" -- cgit v1.2.3 From c1da45b2f561ab7ec8d2785bb53f25218e471ce2 Mon Sep 17 00:00:00 2001 From: Zog Date: Fri, 26 Jan 2018 10:34:51 +0100 Subject: Remove 'rspec-snaphost' to check if it causes segfaults on travis --- Gemfile | 1 - Gemfile.lock | 7 ------- 2 files changed, 8 deletions(-) diff --git a/Gemfile b/Gemfile index f22b718c3..c378820b3 100644 --- a/Gemfile +++ b/Gemfile @@ -174,7 +174,6 @@ group :test do gem 'simplecov-rcov', :require => false gem 'htmlbeautifier' gem 'timecop' - gem 'rspec-snapshot' end group :test, :development, :dev do diff --git a/Gemfile.lock b/Gemfile.lock index f4dfe1bf7..ba86a911f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -444,10 +444,6 @@ GEM roo (2.7.1) nokogiri (~> 1) rubyzip (~> 1.1, < 2.0.0) - rspec (3.5.0) - rspec-core (~> 3.5.0) - rspec-expectations (~> 3.5.0) - rspec-mocks (~> 3.5.0) rspec-core (3.5.4) rspec-support (~> 3.5.0) rspec-expectations (3.5.0) @@ -464,8 +460,6 @@ GEM rspec-expectations (~> 3.5.0) rspec-mocks (~> 3.5.0) rspec-support (~> 3.5.0) - rspec-snapshot (0.1.1) - rspec (> 3.0.0) rspec-support (3.5.0) ruby-graphviz (1.2.3) rubycas-client (2.3.9) @@ -682,7 +676,6 @@ DEPENDENCIES rgeo (~> 0.5.2) roo rspec-rails (~> 3.5.0) - rspec-snapshot rubyzip sass-rails (~> 4.0.3) sawyer (~> 0.6.0) -- cgit v1.2.3 From 22c38fb750843f0c74996175a6bd17a1f20a943c Mon Sep 17 00:00:00 2001 From: Zog Date: Fri, 26 Jan 2018 16:17:22 +0100 Subject: Refs #5750 @1h; Add a "kind" attribute to StopAreas This determines if the StopArea is commercial or not The useless fields are hidden in the form for the non-commercials ones --- app/assets/stylesheets/components/_forms.sass | 8 ++++++- app/javascript/helpers/master_slave.coffee | 18 ++++++++++++++++ app/javascript/packs/stop_areas/new.js | 3 +++ app/models/chouette/area_type.rb | 25 ++++++++++++++++------ app/models/chouette/stop_area.rb | 9 ++++++++ app/views/stop_areas/_form.html.slim | 10 +++++++-- app/views/stop_areas/show.html.slim | 8 +++---- config/locales/area_types.en.yml | 6 ++++++ config/locales/area_types.fr.yml | 6 ++++++ .../20180126134944_add_kind_to_stop_areas.rb | 5 +++++ db/schema.rb | 9 ++++++-- spec/models/chouette/area_type_spec.rb | 4 +++- 12 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 app/javascript/helpers/master_slave.coffee create mode 100644 app/javascript/packs/stop_areas/new.js create mode 100644 db/migrate/20180126134944_add_kind_to_stop_areas.rb diff --git a/app/assets/stylesheets/components/_forms.sass b/app/assets/stylesheets/components/_forms.sass index b7f720963..214795b8b 100644 --- a/app/assets/stylesheets/components/_forms.sass +++ b/app/assets/stylesheets/components/_forms.sass @@ -85,9 +85,15 @@ input // BS horizontal form label positionning fix .form-horizontal + input[type="radio"].form-control + height: auto + width: auto .form-group position: relative - + .radio-inline + padding-top: 4px + &:first-child + padding-left: 0 > .control-label &[class*='col-sm-'] float: none diff --git a/app/javascript/helpers/master_slave.coffee b/app/javascript/helpers/master_slave.coffee new file mode 100644 index 000000000..11f6bca7e --- /dev/null +++ b/app/javascript/helpers/master_slave.coffee @@ -0,0 +1,18 @@ +class MasterSlave + constructor: (selector)-> + $(selector).find('[data-master]').each (i, slave)-> + $slave = $(slave) + master = $($slave.data().master) + console.log $slave.data().master + console.log master + toggle = -> + val = master.filter(":checked").val() if master.filter("[type=radio]").length > 0 + val ||= master.val() + selected = val == $slave.data().value + $slave.toggle selected + $slave.find("input, select").attr "disabled", !selected + master.change toggle + toggle() + # $slave.toggle master.val() == $slave.data().value + +export default MasterSlave diff --git a/app/javascript/packs/stop_areas/new.js b/app/javascript/packs/stop_areas/new.js new file mode 100644 index 000000000..ffe702cdb --- /dev/null +++ b/app/javascript/packs/stop_areas/new.js @@ -0,0 +1,3 @@ +import MasterSlave from "../../helpers/master_slave" + +new MasterSlave("form") diff --git a/app/models/chouette/area_type.rb b/app/models/chouette/area_type.rb index 4703ea646..e17d2ee8d 100644 --- a/app/models/chouette/area_type.rb +++ b/app/models/chouette/area_type.rb @@ -1,13 +1,22 @@ class Chouette::AreaType include Comparable - ALL = %i(zdep zder zdlp zdlr lda gdl).freeze + COMMERCIAL = %i(zdep zder zdlp zdlr lda gdl).freeze + NON_COMMERCIAL = %i(deposit border service_area relief other).freeze + ALL = COMMERCIAL + NON_COMMERCIAL + @@commercial = COMMERCIAL + @@non_commercial = NON_COMMERCIAL @@all = ALL - mattr_accessor :all + mattr_accessor :all, :commercial, :non_commercial - def self.all=(values) - @@all = ALL & values + def self.commercial=(values) + @@commercial = COMMERCIAL & values + reset_caches! + end + + def self.non_commercial=(values) + @@non_commercial = NON_COMMERCIAL & values reset_caches! end @@ -20,12 +29,14 @@ class Chouette::AreaType end def self.reset_caches! + @@all = @@commercial + @@non_commercial @@instances = {} - @@options = nil + @@options = {} end - def self.options - @@options ||= all.map { |c| find(c) }.map { |t| [ t.label, t.code ] } + def self.options(kind=:all) + @@options ||= {} + @@options[kind] ||= self.send(kind).map { |c| find(c) }.map { |t| [ t.label, t.code ] } end attr_reader :code diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb index ea1855ea8..d270a8696 100644 --- a/app/models/chouette/stop_area.rb +++ b/app/models/chouette/stop_area.rb @@ -10,6 +10,7 @@ module Chouette extend Enumerize enumerize :area_type, in: Chouette::AreaType::ALL + enumerize :kind, in: %i(commercial non_commercial) with_options dependent: :destroy do |assoc| assoc.has_many :stop_points @@ -96,6 +97,10 @@ module Chouette end end + def local_id + id.to_s + end + def children_in_depth return [] if self.children.empty? @@ -374,5 +379,9 @@ module Chouette return nil unless time_zone.present? ActiveSupport::TimeZone[time_zone]&.formatted_offset end + + def commercial? + kind == "commercial" + end end end diff --git a/app/views/stop_areas/_form.html.slim b/app/views/stop_areas/_form.html.slim index b2322f73a..699381d50 100644 --- a/app/views/stop_areas/_form.html.slim +++ b/app/views/stop_areas/_form.html.slim @@ -7,9 +7,13 @@ = f.input :id, as: :hidden = f.input :name, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.name")} - = f.input :parent_id, as: :select, :collection => [f.object.parent_id], input_html: { data: { select2_ajax: 'true', url: autocomplete_stop_area_referential_stop_areas_path(@stop_area_referential), initvalue: {id: f.object.parent_id, text: f.object.parent.try(:full_name)}}} + = f.input :kind, as: :radio_buttons, :input_html => {:disabled => !@stop_area.new_record?}, :include_blank => false, item_wrapper_class: 'radio-inline', wrapper: :horizontal_form, item_class: "fooo" - = f.input :area_type, as: :select, :input_html => {:disabled => !@stop_area.new_record?}, :collection => Chouette::AreaType.options, :include_blank => false + .slave data-master="[name='stop_area[kind]']" data-value="commercial" + = f.input :parent_id, as: :select, :collection => [f.object.parent_id], input_html: { data: { select2_ajax: 'true', url: autocomplete_stop_area_referential_stop_areas_path(@stop_area_referential), initvalue: {id: f.object.parent_id, text: f.object.parent.try(:full_name)}}} + - %i(commercial non_commercial).each do |kind| + .slave data-master="[name='stop_area[kind]']" data-value=kind + = f.input :area_type, as: :select, :input_html => {:disabled => !@stop_area.new_record?}, :collection => Chouette::AreaType.options(kind), :include_blank => false .location_info h3 = t("stop_areas.stop_area.localisation") @@ -49,3 +53,5 @@ .separator = f.button :submit, t('actions.submit'), class: 'btn btn-default formSubmitr', form: 'stop_area_form' + += javascript_pack_tag "stop_areas/new" diff --git a/app/views/stop_areas/show.html.slim b/app/views/stop_areas/show.html.slim index b5ec8ac00..b0896c1e0 100644 --- a/app/views/stop_areas/show.html.slim +++ b/app/views/stop_areas/show.html.slim @@ -6,11 +6,11 @@ .container-fluid .row .col-lg-6.col-md-6.col-sm-12.col-xs-12 - - attributes = { t('id_reflex') => @stop_area.get_objectid.short_id, - @stop_area.human_attribute_name(:parent) => @stop_area.parent ? link_to(@stop_area.parent.name, stop_area_referential_stop_area_path(@stop_area_referential, @stop_area.parent)) : "-", - @stop_area.human_attribute_name(:stop_area_type) => Chouette::AreaType.find(@stop_area.area_type).try(:label), + - attributes = { t('id_reflex') => @stop_area.get_objectid.short_id } + - attributes.merge!({ @stop_area.human_attribute_name(:parent) => @stop_area.parent ? link_to(@stop_area.parent.name, stop_area_referential_stop_area_path(@stop_area_referential, @stop_area.parent)) : "-" }) if @stop_area.commercial? + - attributes.merge!({ @stop_area.human_attribute_name(:stop_area_type) => Chouette::AreaType.find(@stop_area.area_type).try(:label), @stop_area.human_attribute_name(:registration_number) => @stop_area.registration_number, - } + }) - attributes.merge!(@stop_area.human_attribute_name(:waiting_time) => @stop_area.waiting_time_text) if has_feature?(:stop_area_waiting_time) - attributes.merge!({ "Coordonnées" => geo_data(@stop_area, @stop_area_referential), @stop_area.human_attribute_name(:zip_code) => @stop_area.zip_code, diff --git a/config/locales/area_types.en.yml b/config/locales/area_types.en.yml index 34ec3243d..5d23a6665 100644 --- a/config/locales/area_types.en.yml +++ b/config/locales/area_types.en.yml @@ -6,3 +6,9 @@ en: zdlp: ZDLp zdlr: ZDLr lda: LDA + gdl: GDL + deposit: Deposit + border: Border + service_area: Service Area + relief: Relief point + other: Other diff --git a/config/locales/area_types.fr.yml b/config/locales/area_types.fr.yml index fd4e1e741..bb249c235 100644 --- a/config/locales/area_types.fr.yml +++ b/config/locales/area_types.fr.yml @@ -6,3 +6,9 @@ fr: zdlp: ZDLp zdlr: ZDLr lda: LDA + gdl: GDL + deposit: Dépôt + border: Frontière + service_area: Aire de service / Pause + relief: Point de releve + other: Autre diff --git a/db/migrate/20180126134944_add_kind_to_stop_areas.rb b/db/migrate/20180126134944_add_kind_to_stop_areas.rb new file mode 100644 index 000000000..3a4f0a0c8 --- /dev/null +++ b/db/migrate/20180126134944_add_kind_to_stop_areas.rb @@ -0,0 +1,5 @@ +class AddKindToStopAreas < ActiveRecord::Migration + def change + add_column :stop_areas, :kind, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 2c5520110..b2063539b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,13 +11,14 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180111200406) do +ActiveRecord::Schema.define(version: 20180126134944) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" - enable_extension "postgis" enable_extension "hstore" + enable_extension "postgis" enable_extension "unaccent" + enable_extension "objectid" create_table "access_links", id: :bigserial, force: :cascade do |t| t.integer "access_point_id", limit: 8 @@ -90,6 +91,8 @@ ActiveRecord::Schema.define(version: 20180111200406) do t.integer "organisation_id", limit: 8 t.datetime "created_at" t.datetime "updated_at" + t.integer "int_day_types" + t.date "excluded_dates", array: true end add_index "calendars", ["organisation_id"], name: "index_calendars_on_organisation_id", using: :btree @@ -115,6 +118,7 @@ ActiveRecord::Schema.define(version: 20180111200406) do t.datetime "updated_at" t.date "end_date" t.string "date_type" + t.string "mode" end add_index "clean_ups", ["referential_id"], name: "index_clean_ups_on_referential_id", using: :btree @@ -786,6 +790,7 @@ ActiveRecord::Schema.define(version: 20180111200406) do t.datetime "updated_at" t.string "stif_type" t.integer "waiting_time" + t.string "kind" end add_index "stop_areas", ["name"], name: "index_stop_areas_on_name", using: :btree diff --git a/spec/models/chouette/area_type_spec.rb b/spec/models/chouette/area_type_spec.rb index 67d218df8..28325dd0a 100644 --- a/spec/models/chouette/area_type_spec.rb +++ b/spec/models/chouette/area_type_spec.rb @@ -4,7 +4,9 @@ RSpec.describe Chouette::AreaType do describe "::ALL" do it "includes all supported types" do - expect(Chouette::AreaType::ALL).to match_array( %i(zdep zder zdlp zdlr lda gdl) ) + expect(Chouette::AreaType::ALL).to match_array( %i(zdep zder zdlp zdlr lda gdl deposit border service_area relief other) ) + expect(Chouette::AreaType::COMMERCIAL).to match_array( %i(zdep zder zdlp zdlr lda gdl) ) + expect(Chouette::AreaType::NON_COMMERCIAL).to match_array( %i( deposit border service_area relief other) ) end end -- cgit v1.2.3 From 05bc96db48a0a84fd2c50e457dc767f88950a9b4 Mon Sep 17 00:00:00 2001 From: Zog Date: Mon, 29 Jan 2018 08:45:02 +0100 Subject: Refs #5750 @1h; Manage non-commercial StopAreas - Add a `kind` attribute - Hide irrelevant fields in the form --- app/assets/stylesheets/modules/_vj_collection.sass | 3 +++ app/controllers/stop_areas_controller.rb | 1 + app/controllers/vehicle_journeys_controller.rb | 2 ++ app/javascript/helpers/master_slave.coffee | 8 ++++---- app/javascript/helpers/stop_area_header_manager.js | 4 +++- app/models/chouette/stop_area.rb | 8 ++++++++ app/policies/stop_area_policy.rb | 2 +- app/views/stop_areas/_form.html.slim | 6 +++--- config/locales/stop_areas.fr.yml | 2 ++ db/migrate/20180126134944_add_kind_to_stop_areas.rb | 1 + spec/models/chouette/stop_area_spec.rb | 10 ++++++++++ 11 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/assets/stylesheets/modules/_vj_collection.sass b/app/assets/stylesheets/modules/_vj_collection.sass index 56769e52b..81c1fe43e 100644 --- a/app/assets/stylesheets/modules/_vj_collection.sass +++ b/app/assets/stylesheets/modules/_vj_collection.sass @@ -9,6 +9,9 @@ position: relative padding-left: 25px + .fa + margin-left: 5px + > .headlined &:before margin-left: -25px diff --git a/app/controllers/stop_areas_controller.rb b/app/controllers/stop_areas_controller.rb index 79ffea72e..8e9df7157 100644 --- a/app/controllers/stop_areas_controller.rb +++ b/app/controllers/stop_areas_controller.rb @@ -203,6 +203,7 @@ class StopAreasController < ChouetteController :url, :waiting_time, :zip_code, + :kind, ) end diff --git a/app/controllers/vehicle_journeys_controller.rb b/app/controllers/vehicle_journeys_controller.rb index c1762c13e..ed6ba6ed1 100644 --- a/app/controllers/vehicle_journeys_controller.rb +++ b/app/controllers/vehicle_journeys_controller.rb @@ -66,6 +66,8 @@ class VehicleJourneysController < ChouetteController :city_name => sp.stop_area.try(:city_name), :comment => sp.stop_area.try(:comment), :area_type => sp.stop_area.try(:area_type), + :area_type_i18n => I18n.t(sp.stop_area.try(:area_type), scope: 'area_types.label'), + :area_kind => sp.stop_area.try(:kind), :stop_area_id => sp.stop_area_id, :registration_number => sp.stop_area.try(:registration_number), :nearest_topic_name => sp.stop_area.try(:nearest_topic_name), diff --git a/app/javascript/helpers/master_slave.coffee b/app/javascript/helpers/master_slave.coffee index 11f6bca7e..4866a55e3 100644 --- a/app/javascript/helpers/master_slave.coffee +++ b/app/javascript/helpers/master_slave.coffee @@ -3,16 +3,16 @@ class MasterSlave $(selector).find('[data-master]').each (i, slave)-> $slave = $(slave) master = $($slave.data().master) - console.log $slave.data().master - console.log master + console.log $slave + console.log $slave.find("input:disabled, select:disabled") + $slave.find("input:disabled, select:disabled").attr "data-slave-force-disabled", "true" toggle = -> val = master.filter(":checked").val() if master.filter("[type=radio]").length > 0 val ||= master.val() selected = val == $slave.data().value $slave.toggle selected - $slave.find("input, select").attr "disabled", !selected + $slave.find("input, select").filter(":not([data-slave-force-disabled])").attr "disabled", !selected master.change toggle toggle() - # $slave.toggle master.val() == $slave.data().value export default MasterSlave diff --git a/app/javascript/helpers/stop_area_header_manager.js b/app/javascript/helpers/stop_area_header_manager.js index c9f397dee..2c820caf9 100644 --- a/app/javascript/helpers/stop_area_header_manager.js +++ b/app/javascript/helpers/stop_area_header_manager.js @@ -19,7 +19,7 @@ export default class StopAreaHeaderManager {
    @@ -27,6 +27,8 @@ export default class StopAreaHeaderManager { {sp.time_zone_formatted_offset &&  ({sp.time_zone_formatted_offset}) } + {sp.area_kind == 'non_commercial' && + }
    diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb index d270a8696..75a4a34bb 100644 --- a/app/models/chouette/stop_area.rb +++ b/app/models/chouette/stop_area.rb @@ -32,6 +32,7 @@ module Chouette validates_format_of :registration_number, :with => %r{\A[\d\w_\-]+\Z}, :allow_blank => true validates_presence_of :name + validates_presence_of :kind validates_presence_of :latitude, :if => :longitude validates_presence_of :longitude, :if => :latitude validates_numericality_of :latitude, :less_than_or_equal_to => 90, :greater_than_or_equal_to => -90, :allow_nil => true @@ -42,6 +43,7 @@ module Chouette validates_numericality_of :waiting_time, greater_than_or_equal_to: 0, only_integer: true, if: :waiting_time validate :parent_area_type_must_be_greater + validate :area_type_of_right_kind def self.nullable_attributes [:registration_number, :street_name, :country_code, :fare_code, @@ -57,6 +59,12 @@ module Chouette end end + def area_type_of_right_kind + unless Chouette::AreaType.send(self.kind).include?(self.area_type) + errors.add(:area_type, I18n.t('stop_areas.errors.incorrect_kind_area_type')) + end + end + after_update :clean_invalid_access_links before_save :coordinates_to_lat_lng diff --git a/app/policies/stop_area_policy.rb b/app/policies/stop_area_policy.rb index 6db48b702..fd73b7092 100644 --- a/app/policies/stop_area_policy.rb +++ b/app/policies/stop_area_policy.rb @@ -3,7 +3,7 @@ class StopAreaPolicy < ApplicationPolicy def search_scope scope_name scope = resolve if scope_name&.to_s == "route_editor" - scope = scope.where(area_type: 'zdep') unless user.organisation.has_feature?("route_stop_areas_all_types") + scope = scope.where("kind = ? OR area_type = ?", :non_commercial, 'zdep') unless user.organisation.has_feature?("route_stop_areas_all_types") end scope end diff --git a/app/views/stop_areas/_form.html.slim b/app/views/stop_areas/_form.html.slim index 699381d50..6b75209b4 100644 --- a/app/views/stop_areas/_form.html.slim +++ b/app/views/stop_areas/_form.html.slim @@ -7,13 +7,13 @@ = f.input :id, as: :hidden = f.input :name, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.name")} - = f.input :kind, as: :radio_buttons, :input_html => {:disabled => !@stop_area.new_record?}, :include_blank => false, item_wrapper_class: 'radio-inline', wrapper: :horizontal_form, item_class: "fooo" + = f.input :kind, as: :radio_buttons, :input_html => {:disabled => !@stop_area.new_record?}, :include_blank => false, item_wrapper_class: 'radio-inline', wrapper: :horizontal_form, item_class: "fooo", disabled: !@stop_area.new_record? .slave data-master="[name='stop_area[kind]']" data-value="commercial" = f.input :parent_id, as: :select, :collection => [f.object.parent_id], input_html: { data: { select2_ajax: 'true', url: autocomplete_stop_area_referential_stop_areas_path(@stop_area_referential), initvalue: {id: f.object.parent_id, text: f.object.parent.try(:full_name)}}} - - %i(commercial non_commercial).each do |kind| + - %i(non_commercial commercial).each do |kind| .slave data-master="[name='stop_area[kind]']" data-value=kind - = f.input :area_type, as: :select, :input_html => {:disabled => !@stop_area.new_record?}, :collection => Chouette::AreaType.options(kind), :include_blank => false + = f.input :area_type, as: :select, :input_html => {id: kind, :disabled => !@stop_area.new_record?}, :collection => Chouette::AreaType.options(kind), :include_blank => false, disabled: !@stop_area.new_record? .location_info h3 = t("stop_areas.stop_area.localisation") diff --git a/config/locales/stop_areas.fr.yml b/config/locales/stop_areas.fr.yml index 0095bbe6d..283000960 100644 --- a/config/locales/stop_areas.fr.yml +++ b/config/locales/stop_areas.fr.yml @@ -5,6 +5,7 @@ fr: errors: empty: Aucun stop_area_id parent_area_type: ne peut être de type %{area_type} + incorrect_kind_area_type: Ce type d'arrêt est invalide pour cette catégorie default_geometry_success: "%{count} arrêts édités" stop_area: no_position: "Pas de position" @@ -97,6 +98,7 @@ fr: attributes: stop_area: name: "Nom" + kind: "Catégorie" registration_number: "Numéro d'enregistrement" published_name: "Nom public" deleted: "Supprimé" diff --git a/db/migrate/20180126134944_add_kind_to_stop_areas.rb b/db/migrate/20180126134944_add_kind_to_stop_areas.rb index 3a4f0a0c8..7da227cd9 100644 --- a/db/migrate/20180126134944_add_kind_to_stop_areas.rb +++ b/db/migrate/20180126134944_add_kind_to_stop_areas.rb @@ -1,5 +1,6 @@ class AddKindToStopAreas < ActiveRecord::Migration def change add_column :stop_areas, :kind, :string + Chouette::StopArea.update_all kind: :commmercial end end diff --git a/spec/models/chouette/stop_area_spec.rb b/spec/models/chouette/stop_area_spec.rb index a90e5d816..32ee5a3a6 100644 --- a/spec/models/chouette/stop_area_spec.rb +++ b/spec/models/chouette/stop_area_spec.rb @@ -10,10 +10,20 @@ describe Chouette::StopArea, :type => :model do it { should belong_to(:stop_area_referential) } it { should validate_presence_of :name } + it { should validate_presence_of :kind } it { should validate_numericality_of :latitude } it { should validate_numericality_of :longitude } it { is_expected.to be_versioned } + describe "#area_type" do + it "should validate the value is correct regarding to the kind" do + expect(build(:stop_area, kind: :commercial, area_type: :gdl)).to be_valid + expect(build(:stop_area, kind: :non_commercial, area_type: :relief)).to be_valid + expect(build(:stop_area, kind: :commercial, area_type: :relief)).to_not be_valid + expect(build(:stop_area, kind: :non_commercial, area_type: :gdl)).to_not be_valid + end + end + # describe ".latitude" do # it "should accept -90 value" do # subject = create :stop_area, :area_type => "BoardingPosition" -- cgit v1.2.3 From ddd83906ce4fab3d6dce0c404ec39c3b500ba96f Mon Sep 17 00:00:00 2001 From: Zog Date: Mon, 29 Jan 2018 10:32:05 +0100 Subject: Refs #5750; Add a validation on VehicleJourneys Ensure a time is set for all non-commercial stops --- app/assets/stylesheets/modules/_vj_collection.sass | 3 ++ app/javascript/vehicle_journeys/actions/index.js | 26 ++++++++++++++ .../components/SaveVehicleJourneys.js | 2 +- .../vehicle_journeys/components/VehicleJourney.js | 3 ++ .../vehicle_journeys/components/VehicleJourneys.js | 2 +- .../containers/SaveVehicleJourneys.js | 3 ++ .../vehicle_journeys/reducers/vehicleJourneys.js | 2 ++ app/views/vehicle_journeys/show.rabl | 1 + spec/javascript/vehicle_journeys/actions_spec.js | 41 ++++++++++++++++++++++ 9 files changed, 81 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/modules/_vj_collection.sass b/app/assets/stylesheets/modules/_vj_collection.sass index 81c1fe43e..d99c67bd7 100644 --- a/app/assets/stylesheets/modules/_vj_collection.sass +++ b/app/assets/stylesheets/modules/_vj_collection.sass @@ -116,6 +116,9 @@ margin-left: 5px &.has-error + .errors + color: $red + font-size: 0.8em &:before content: '' position: absolute diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js index 2675328e3..b01158212 100644 --- a/app/javascript/vehicle_journeys/actions/index.js +++ b/app/javascript/vehicle_journeys/actions/index.js @@ -380,6 +380,32 @@ const actions = { } }) }, + + validate : (dispatch, vehicleJourneys, next) => { + let valid = true + let vj, vjas + for (vj of vehicleJourneys){ + vj.errors = false + for(vjas of vj.vehicle_journey_at_stops){ + vjas.errors = null + if (vjas.area_kind == "non_commercial" && parseInt(vjas.departure_time.hour) == 0 && parseInt(vjas.departure_time.minute) == 0){ + vjas.errors = "Champ requis" + vj.errors = true + valid = false + } + } + } + dispatch(actions.didValidateVehicleJourneys(vehicleJourneys)) + if(valid){ + actions.submitVehicleJourneys(dispatch, vehicleJourneys, next) + } + }, + + didValidateVehicleJourneys : (vehicleJourneys) => ({ + type: 'DID_VALIDATE_VEHICLE_JOURNEYS', + vehicleJourneys + }), + submitVehicleJourneys : (dispatch, state, next) => { dispatch(actions.fetchingApi()) let urlJSON = window.location.pathname + "_collection.json" diff --git a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js index 6e94b04a3..fb921df9c 100644 --- a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js +++ b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js @@ -13,7 +13,7 @@ export default class SaveVehicleJourneys extends SaveButton{ } submitForm(){ - this.props.onSubmitVehicleJourneys(this.props.dispatch, this.props.vehicleJourneys) + this.props.validate(this.props.vehicleJourneys, this.props.dispatch) } } diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js index d240757a3..2b5783dda 100644 --- a/app/javascript/vehicle_journeys/components/VehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js @@ -153,6 +153,9 @@ export default class VehicleJourney extends Component { /> + {vj.errors &&
    + {vj.errors} +
    } )} diff --git a/app/javascript/vehicle_journeys/components/VehicleJourneys.js b/app/javascript/vehicle_journeys/components/VehicleJourneys.js index b188962c2..256ca81f9 100644 --- a/app/javascript/vehicle_journeys/components/VehicleJourneys.js +++ b/app/javascript/vehicle_journeys/components/VehicleJourneys.js @@ -89,7 +89,7 @@ export default class VehicleJourneys extends Component { )} - { _.some(this.props.vehicleJourneys, 'errors') && ( + { this.props.vehicleJourneys.errors && this.props.vehicleJourneys.errors.length && _.some(this.props.vehicleJourneys, 'errors') && (
    Erreur : {this.props.vehicleJourneys.map((vj, index) => diff --git a/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js index f5f879ed8..3daf831f8 100644 --- a/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js +++ b/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js @@ -23,6 +23,9 @@ const mapDispatchToProps = (dispatch) => { }, onSubmitVehicleJourneys: (next, state) => { actions.submitVehicleJourneys(dispatch, state, next) + }, + validate: (state) =>{ + actions.validate(dispatch, state) } } } diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js index ae45993a8..1a15ec46d 100644 --- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js +++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js @@ -273,6 +273,8 @@ export default function vehicleJourneys(state = [], action) { return vj } }) + case 'DID_VALIDATE_VEHICLE_JOURNEYS': + return [...action.vehicleJourneys] default: return state } diff --git a/app/views/vehicle_journeys/show.rabl b/app/views/vehicle_journeys/show.rabl index fc65e6cb6..dca0866b3 100644 --- a/app/views/vehicle_journeys/show.rabl +++ b/app/views/vehicle_journeys/show.rabl @@ -45,6 +45,7 @@ child(:vehicle_journey_at_stops_matrix, :object_root => false) do |vehicle_stops end node(:dummy) { vehicle_stop.dummy } + node(:area_kind) { vehicle_stop.stop_point.stop_area.kind } node(:stop_area_object_id) do vehicle_stop.stop_point.stop_area.objectid diff --git a/spec/javascript/vehicle_journeys/actions_spec.js b/spec/javascript/vehicle_journeys/actions_spec.js index 9515b57f2..d486c9af8 100644 --- a/spec/javascript/vehicle_journeys/actions_spec.js +++ b/spec/javascript/vehicle_journeys/actions_spec.js @@ -37,6 +37,47 @@ describe('when clicking on add button', () => { expect(actions.openCreateModal()).toEqual(expectedAction) }) }) +describe('when validating the form', () => { + it('should check that non-commercial stops have passing time', () => { + let state = [{ + vehicle_journey_at_stops: [{ + area_kind: "non_commercial", + departure_time: { + hour: "00", + minute: "00" + } + }] + }] + + expect(actions.validate(dispatch, state)).toEqual(false) + + state = [{ + vehicle_journey_at_stops: [{ + area_kind: "non_commercial", + departure_time: { + hour: "00", + minute: "01" + } + }] + }] + + expect(actions.validate(dispatch, state)).toEqual(true) + }) + + it('should not check that commercial stops', () => { + let state = [{ + vehicle_journey_at_stops: [{ + area_kind: "commercial", + departure_time: { + hour: "00", + minute: "00" + } + }] + }] + + expect(actions.validate(dispatch, state)).toEqual(true) + }) +}) describe('when using select2 to pick a journey pattern', () => { it('should create an action to select a journey pattern inside modal', () => { let selectedJP = { -- cgit v1.2.3 From 0101f0ca0a7354420118b0470532f804674edc34 Mon Sep 17 00:00:00 2001 From: Zog Date: Wed, 31 Jan 2018 10:46:02 +0100 Subject: Refs #5750; Fix validation --- app/controllers/stop_areas_controller.rb | 2 +- app/models/chouette/stop_area.rb | 3 ++- app/views/stop_areas/_form.html.slim | 3 +-- db/migrate/20180126134944_add_kind_to_stop_areas.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/stop_areas_controller.rb b/app/controllers/stop_areas_controller.rb index 8e9df7157..8d424b8d1 100644 --- a/app/controllers/stop_areas_controller.rb +++ b/app/controllers/stop_areas_controller.rb @@ -97,7 +97,7 @@ class StopAreasController < ChouetteController edit! do stop_area.position ||= stop_area.default_position map.editable = true - end + end end def destroy diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb index 75a4a34bb..ad42d54ae 100644 --- a/app/models/chouette/stop_area.rb +++ b/app/models/chouette/stop_area.rb @@ -60,7 +60,8 @@ module Chouette end def area_type_of_right_kind - unless Chouette::AreaType.send(self.kind).include?(self.area_type) + + unless Chouette::AreaType.send(self.kind).map(&:to_s).include?(self.area_type) errors.add(:area_type, I18n.t('stop_areas.errors.incorrect_kind_area_type')) end end diff --git a/app/views/stop_areas/_form.html.slim b/app/views/stop_areas/_form.html.slim index 6b75209b4..aa156f7bd 100644 --- a/app/views/stop_areas/_form.html.slim +++ b/app/views/stop_areas/_form.html.slim @@ -6,8 +6,7 @@ /= @map.to_html = f.input :id, as: :hidden = f.input :name, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.name")} - - = f.input :kind, as: :radio_buttons, :input_html => {:disabled => !@stop_area.new_record?}, :include_blank => false, item_wrapper_class: 'radio-inline', wrapper: :horizontal_form, item_class: "fooo", disabled: !@stop_area.new_record? + = f.input :kind, as: :radio_buttons, checked: @stop_area.kind, :input_html => {:disabled => !@stop_area.new_record?}, :include_blank => false, item_wrapper_class: 'radio-inline', wrapper: :horizontal_form, disabled: !@stop_area.new_record? .slave data-master="[name='stop_area[kind]']" data-value="commercial" = f.input :parent_id, as: :select, :collection => [f.object.parent_id], input_html: { data: { select2_ajax: 'true', url: autocomplete_stop_area_referential_stop_areas_path(@stop_area_referential), initvalue: {id: f.object.parent_id, text: f.object.parent.try(:full_name)}}} diff --git a/db/migrate/20180126134944_add_kind_to_stop_areas.rb b/db/migrate/20180126134944_add_kind_to_stop_areas.rb index 7da227cd9..08f54a6c5 100644 --- a/db/migrate/20180126134944_add_kind_to_stop_areas.rb +++ b/db/migrate/20180126134944_add_kind_to_stop_areas.rb @@ -1,6 +1,6 @@ class AddKindToStopAreas < ActiveRecord::Migration def change add_column :stop_areas, :kind, :string - Chouette::StopArea.update_all kind: :commmercial + Chouette::StopArea.where.not(kind: :non_commercial).update_all kind: :commercial end end -- cgit v1.2.3 From bb62bc2028f142e953035680b2483ee6029711ae Mon Sep 17 00:00:00 2001 From: Zog Date: Wed, 31 Jan 2018 11:14:23 +0100 Subject: Disable immature feature --- app/javascript/packs/referential_lines/show.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/packs/referential_lines/show.js b/app/javascript/packs/referential_lines/show.js index 99c5072ef..542188018 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() -- cgit v1.2.3 From c463c3a950246c4c2660ce7df1c1ea8f2acbe578 Mon Sep 17 00:00:00 2001 From: Zog Date: Wed, 31 Jan 2018 11:17:02 +0100 Subject: Refs #5750; Remove useless validation --- app/javascript/vehicle_journeys/actions/index.js | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js index b01158212..4a4ec371d 100644 --- a/app/javascript/vehicle_journeys/actions/index.js +++ b/app/javascript/vehicle_journeys/actions/index.js @@ -382,23 +382,8 @@ const actions = { }, validate : (dispatch, vehicleJourneys, next) => { - let valid = true - let vj, vjas - for (vj of vehicleJourneys){ - vj.errors = false - for(vjas of vj.vehicle_journey_at_stops){ - vjas.errors = null - if (vjas.area_kind == "non_commercial" && parseInt(vjas.departure_time.hour) == 0 && parseInt(vjas.departure_time.minute) == 0){ - vjas.errors = "Champ requis" - vj.errors = true - valid = false - } - } - } dispatch(actions.didValidateVehicleJourneys(vehicleJourneys)) - if(valid){ - actions.submitVehicleJourneys(dispatch, vehicleJourneys, next) - } + actions.submitVehicleJourneys(dispatch, vehicleJourneys, next) }, didValidateVehicleJourneys : (vehicleJourneys) => ({ -- cgit v1.2.3