aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorRobert2017-04-24 14:16:52 +0200
committerRobert2017-04-24 14:16:52 +0200
commit2d19e65fa8d8ac037c7f00a638111788b7ee002c (patch)
tree830fe41ac13743f75f2c16f41dfd1ff399b99a9b /app
parent5003acfc533baa824fed11cf6f82f86393b3a0f6 (diff)
parent1cbed80c913420c76ac7d3716b9d8c4bf4e14278 (diff)
downloadchouette-core-2d19e65fa8d8ac037c7f00a638111788b7ee002c.tar.bz2
conflict resolution and asset recompilation
Diffstat (limited to 'app')
-rw-r--r--app/assets/fonts/sBoiv/sboiv.svg6
-rw-r--r--app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js6
-rw-r--r--app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js2
-rw-r--r--app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js23
-rw-r--r--app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js1
-rw-r--r--app/assets/javascripts/es6_browserified/journey_patterns/components/Navigate.js4
-rw-r--r--app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js2
-rw-r--r--app/assets/javascripts/es6_browserified/journey_patterns/index.js1
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/actions/index.js195
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js65
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/Metas.js139
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/Navigate.js96
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js90
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js65
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js78
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js73
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js35
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js103
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/containers/App.js38
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/containers/Metas.js33
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/containers/Navigate.js18
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/containers/PeriodForm.js28
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js32
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/index.js69
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/index.js16
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js33
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/modal.js42
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js30
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/status.js17
-rw-r--r--app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js63
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js85
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/Filters.js2
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/Navigate.js4
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js5
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js18
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CalendarsEditVehicleJourney.js8
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js8
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DeleteVehicleJourneys.js8
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js10
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js55
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js8
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js10
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js3
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/containers/SaveVehicleJourneys.js3
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/index.js4
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/filters.js9
-rw-r--r--app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/vehicleJourneys.js44
-rw-r--r--app/assets/javascripts/forms.coffee18
-rw-r--r--app/assets/javascripts/main_menu.coffee5
-rw-r--r--app/assets/javascripts/nav_panels.coffee2
-rw-r--r--app/assets/javascripts/routing_constraint_zones.coffee27
-rw-r--r--app/assets/javascripts/select2.coffee10
-rw-r--r--app/assets/javascripts/selectable_table.coffee2
-rw-r--r--app/assets/stylesheets/application.sass1
-rw-r--r--app/assets/stylesheets/base/_config.sass1
-rw-r--r--app/assets/stylesheets/components/_buttons.sass40
-rw-r--r--app/assets/stylesheets/components/_calendar.sass73
-rw-r--r--app/assets/stylesheets/components/_dropdown.sass18
-rw-r--r--app/assets/stylesheets/components/_forms.sass106
-rw-r--r--app/assets/stylesheets/components/_labels.sass12
-rw-r--r--app/assets/stylesheets/components/_select2.sass16
-rw-r--r--app/assets/stylesheets/components/_tables.sass14
-rw-r--r--app/assets/stylesheets/main/time_tables.sass6
-rw-r--r--app/assets/stylesheets/modules/_jp_collection.sass4
-rw-r--r--app/assets/stylesheets/modules/_timetables.sass195
-rw-r--r--app/assets/stylesheets/typography/_fonts.sass2
-rw-r--r--app/assets/stylesheets/typography/_sboiv.sass6
-rw-r--r--app/controllers/application_controller.rb4
-rw-r--r--app/controllers/errors_controller.rb11
-rw-r--r--app/controllers/journey_patterns_collections_controller.rb9
-rw-r--r--app/controllers/line_footnotes_controller.rb2
-rw-r--r--app/controllers/referential_companies_controller.rb7
-rw-r--r--app/controllers/referentials_controller.rb2
-rw-r--r--app/controllers/route_stop_points_controller.rb18
-rw-r--r--app/controllers/routing_constraint_zones_controller.rb7
-rw-r--r--app/controllers/time_tables_controller.rb55
-rw-r--r--app/controllers/vehicle_journeys_controller.rb53
-rw-r--r--app/controllers/workbenches_controller.rb7
-rw-r--r--app/helpers/access_links_helper.rb7
-rw-r--r--app/helpers/access_points_helper.rb30
-rw-r--r--app/helpers/common_helpers.rb26
-rw-r--r--app/helpers/connection_links_helper.rb8
-rw-r--r--app/helpers/core_helper.rb7
-rw-r--r--app/helpers/networks_helper.rb7
-rw-r--r--app/helpers/newapplication_helper.rb17
-rw-r--r--app/helpers/rule_parameter_sets_helper.rb5
-rw-r--r--app/helpers/stop_area_copies_helper.rb8
-rw-r--r--app/helpers/stop_areas_helper.rb21
-rw-r--r--app/helpers/time_tables_helper.rb177
-rw-r--r--app/helpers/vehicle_journeys_helper.rb6
-rw-r--r--app/inputs/tags_input.rb31
-rw-r--r--app/models/chouette/line.rb8
-rw-r--r--app/models/chouette/route.rb3
-rw-r--r--app/models/chouette/routing_constraint_zone.rb25
-rw-r--r--app/models/chouette/stop_point.rb8
-rw-r--r--app/models/chouette/time_table.rb14
-rw-r--r--app/models/chouette/vehicle_journey.rb79
-rw-r--r--app/models/import.rb3
-rw-r--r--app/models/netex_import.rb10
-rw-r--r--app/models/referential.rb14
-rw-r--r--app/models/referential_metadata.rb19
-rw-r--r--app/models/user.rb18
-rw-r--r--app/models/user_context.rb8
-rw-r--r--app/policies/acces_point_policy.rb4
-rw-r--r--app/policies/access_link_policy.rb4
-rw-r--r--app/policies/application_policy.rb24
-rw-r--r--app/policies/connection_link_policy.rb4
-rw-r--r--app/policies/journey_pattern_policy.rb7
-rw-r--r--app/policies/referential_policy.rb18
-rw-r--r--app/policies/route_policy.rb4
-rw-r--r--app/policies/routing_constraint_zone_policy.rb4
-rw-r--r--app/policies/time_table_policy.rb4
-rw-r--r--app/policies/vehicle_journey_policy.rb4
-rw-r--r--app/views/access_links/_form.html.slim4
-rw-r--r--app/views/access_points/_form.html.slim7
-rw-r--r--app/views/connection_links/_form.html.slim6
-rw-r--r--app/views/errors/not_allowed.html.slim21
-rw-r--r--app/views/journey_patterns_collections/show.html.slim5
-rw-r--r--app/views/lines/index.html.slim1
-rw-r--r--app/views/networks/_form.html.slim4
-rw-r--r--app/views/referential_networks/_form.html.slim10
-rw-r--r--app/views/referentials/index.html.slim3
-rw-r--r--app/views/referentials/show.html.slim6
-rw-r--r--app/views/routes/show.html.slim1
-rw-r--r--app/views/routing_constraint_zones/_form.html.slim10
-rw-r--r--app/views/routing_constraint_zones/index.html.slim4
-rw-r--r--app/views/routing_constraint_zones/show.html.slim11
-rw-r--r--app/views/rule_parameter_sets/_transport_mode_parameter_set_fields.html.slim4
-rw-r--r--app/views/stop_area_copies/new.html.slim18
-rw-r--r--app/views/stop_areas/index.html.slim2
-rw-r--r--app/views/stop_areas/show.html.slim2
-rw-r--r--app/views/time_tables/_date_fields.html.slim19
-rw-r--r--app/views/time_tables/_excluded_date_fields.html.slim20
-rw-r--r--app/views/time_tables/_form.html.slim175
-rw-r--r--app/views/time_tables/_period_fields.html.slim23
-rw-r--r--app/views/time_tables/_periods.html.slim5
-rw-r--r--app/views/time_tables/_show_time_table.html.slim119
-rw-r--r--app/views/time_tables/edit.html.slim13
-rw-r--r--app/views/time_tables/index.html.slim88
-rw-r--r--app/views/time_tables/index.js.slim1
-rw-r--r--app/views/time_tables/index.json.rabl9
-rw-r--r--app/views/time_tables/index.rabl2
-rw-r--r--app/views/time_tables/month.rabl9
-rw-r--r--app/views/time_tables/new.html.slim13
-rw-r--r--app/views/time_tables/show.html.slim62
-rw-r--r--app/views/time_tables/show.rabl26
-rw-r--r--app/views/vehicle_journeys/_form.html.slim2
-rw-r--r--app/views/vehicle_journeys/show.rabl9
-rw-r--r--app/views/workbenches/show.html.slim4
-rw-r--r--app/workers/referential_cloning_worker.rb39
150 files changed, 3178 insertions, 635 deletions
diff --git a/app/assets/fonts/sBoiv/sboiv.svg b/app/assets/fonts/sBoiv/sboiv.svg
index 76f038bd7..be313bfcc 100644
--- a/app/assets/fonts/sBoiv/sboiv.svg
+++ b/app/assets/fonts/sBoiv/sboiv.svg
@@ -8,6 +8,12 @@
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe900;" glyph-name="update-vj" d="M1017.856 448c0 266.935-216.393 483.328-483.328 483.328v-99.84c211.677-0.291 383.197-171.81 383.488-383.46zM918.016 448c0-0.071 0-0.154 0-0.238 0-211.795-171.693-383.488-383.488-383.488-187.627 0-343.782 134.745-376.977 312.746l-102.767 2.371c29.828-240.928 233.283-425.583 479.866-425.583 266.935 0 483.328 216.393 483.328 483.328 0 3.82-0.044 7.629-0.132 11.427zM534.528 755.2c169.662 0 307.2-137.538 307.2-307.2h-307.2zM460.8 669.184c-0.283-17.134-14.098-30.949-31.205-31.232h-136.731v-136.192c0.003-0.152 0.004-0.332 0.004-0.512 0-17.249-13.983-31.232-31.232-31.232-0.001 0-0.003 0-0.004 0h-62.976c-17.31 0.288-31.232 14.388-31.232 31.74 0 0.001 0 0.003 0 0.004v136.192h-136.192c-17.249 0-31.232 13.983-31.232 31.232v62.976c0 17.249 13.983 31.232 31.232 31.232h136.192v136.704c0.283 17.134 14.098 30.949 31.205 31.232h63.003c17.249 0 31.232-13.983 31.232-31.232v-136.704h136.192c0.001 0 0.003 0 0.004 0 17.352 0 31.452-13.922 31.74-31.205z" />
+<<<<<<< HEAD
<glyph unicode="&#xe901;" glyph-name="preparing" d="M1011.2 614.4l-80.384 80.384c-7.765 8.206-18.732 13.313-30.891 13.313-0.12 0-0.239 0-0.359-0.001-0.129 0.002-0.303 0.003-0.478 0.003-11.952 0-22.709-5.119-30.196-13.285l-56.859-56.35 142.336-142.848 56.832 54.784c7.9 7.644 12.803 18.342 12.803 30.185 0 0.188-0.001 0.376-0.004 0.563 0.035 0.625 0.055 1.389 0.055 2.159 0 12.138-4.911 23.129-12.855 31.094zM504.32 330.752v-142.848h142.848l285.184 285.696-142.336 142.336zM805.888 544.256l-185.856-185.856c-0.834-0.338-1.802-0.535-2.816-0.535s-1.982 0.196-2.868 0.553c-0.285-0.079-0.672-0.113-1.067-0.113-3.676 0-6.656 2.98-6.656 6.656 0 0.395 0.034 0.782 0.1 1.159-0.322 0.797-0.505 1.765-0.505 2.776s0.183 1.979 0.518 2.873l188.397 183.751c0.834 0.338 1.802 0.535 2.816 0.535s1.982-0.196 2.868-0.553c0.285 0.079 0.672 0.113 1.067 0.113 3.676 0 6.656-2.98 6.656-6.656 0-0.395-0.034-0.782-0.1-1.159-0.528-1.405-1.409-2.616-2.539-3.532zM592.384 231.936v44.032h-44.032v36.864l31.232 31.232 80.384-80.384-31.232-31.232zM0 239.616h416.256v-51.2h-416.256v51.2z" />
<glyph unicode="&#xe902;" glyph-name="current-ref" d="M530.944 258.048l-70.144 71.68c-18.016 18.227-43.018 29.516-70.656 29.516s-52.64-11.288-70.647-29.506l-30.217 30.198c18.443 18.335 29.94 43.639 30.208 71.629-0.796 26.612-12.010 50.408-29.674 67.614l-70.677 71.701c-17.884 17.891-42.593 28.957-69.888 28.957s-52.004-11.066-69.888-28.957l-51.2-51.2c-17.891-17.884-28.957-42.593-28.957-69.888s11.066-52.004 28.957-69.888l74.24-69.632c18.016-18.227 43.018-29.516 70.656-29.516s52.64 11.288 70.647 29.506l30.217-30.198c-18.443-18.335-29.94-43.639-30.208-71.629-0.004-0.365-0.006-0.735-0.006-1.106 0-25.725 9.933-49.13 26.173-66.589l70.601-71.62c17.858-17.739 42.465-28.702 69.632-28.702s51.774 10.963 69.638 28.707l51.194 51.195c18.015 17.826 29.171 42.554 29.171 69.888s-11.156 52.062-29.163 69.88zM241.152 404.992c-11.264 11.264-20.992 24.576-38.4 24.576-18.097 0-32.768-14.671-32.768-32.768 0-17.408 13.312-27.136 24.576-38.4-5.932-6.614-14.505-10.756-24.046-10.756-0.186 0-0.372 0.002-0.558 0.005-0.198-0.006-0.465-0.009-0.732-0.009-8.862 0-16.902 3.518-22.8 9.233l-71.159 71.672c-5.852 5.917-9.468 14.056-9.468 23.040s3.615 17.123 9.471 23.043l51.197 51.197c6.111 5.71 14.344 9.216 23.396 9.216 0.055 0 0.11 0 0.164 0 0.003 0 0.017 0 0.031 0 9.18 0 17.492-3.717 23.513-9.728l69.632-72.192c6.346-6.071 10.291-14.607 10.291-24.064s-3.945-17.993-10.279-24.052zM493.568 188.416c-0.074-9.019-3.78-17.157-9.725-23.037l-51.203-51.203c-5.968-5.407-13.923-8.716-22.652-8.716-0.317 0-0.632 0.004-0.947 0.013-0.18-0.007-0.447-0.010-0.714-0.010-8.862 0-16.902 3.518-22.8 9.233l-69.111 72.184c-6.346 6.071-10.291 14.607-10.291 24.064s3.945 17.993 10.279 24.052c11.276-11.252 21.004-24.564 38.412-24.564 0.612-0.041 1.328-0.064 2.048-0.064 18.097 0 32.768 14.671 32.768 32.768 0 0.023 0 0.045 0 0.068 0 17.404-13.312 27.132-24.576 38.396 5.719 7.519 14.538 12.425 24.517 12.798 0.070 0.002 0.084 0.002 0.098 0.002 9.18 0 17.492-3.717 23.513-9.728l71.168-71.168c6.006-5.864 9.731-14.041 9.731-23.089 0-0.163-0.001-0.325-0.004-0.488zM1013.76 794.624l-51.2 51.2c-6.51 6.641-15.574 10.757-25.6 10.757s-19.090-4.116-25.594-10.751l-245.766-244.23-108.032 108.544c-6.51 6.641-15.574 10.757-25.6 10.757s-19.090-4.116-25.594-10.751l-51.206-51.206c-6.641-6.51-10.757-15.574-10.757-25.6s4.116-19.090 10.751-25.594l135.686-134.15 51.2-51.2c6.51-6.641 15.574-10.757 25.6-10.757s19.090 4.116 25.594 10.751l51.206 51.206 269.312 270.336c6.641 6.51 10.757 15.574 10.757 25.6s-4.116 19.090-10.751 25.594z" />
+=======
+<glyph unicode="&#xe901;" glyph-name="preparing" d="M1011.173 614.391l-80.38 80.38c-7.765 8.206-18.731 13.312-30.889 13.312-0.12 0-0.239 0-0.359-0.001-0.129 0.002-0.303 0.003-0.478 0.003-11.951 0-22.708-5.119-30.194-13.284l-56.856-56.347 142.328-142.84 56.829 54.781c7.9 7.644 12.802 18.341 12.802 30.183 0 0.188-0.001 0.376-0.004 0.563 0.035 0.625 0.055 1.389 0.055 2.159 0 12.137-4.911 23.128-12.854 31.092zM504.32 330.758v-142.84h142.84l285.17 285.681-142.328 142.328zM805.872 544.251l-185.847-185.847c-0.834-0.338-1.802-0.535-2.816-0.535s-1.982 0.196-2.868 0.553c-0.285-0.079-0.672-0.113-1.067-0.113-3.676 0-6.656 2.98-6.656 6.656 0 0.395 0.034 0.782 0.1 1.159-0.322 0.797-0.505 1.765-0.505 2.776s0.183 1.979 0.518 2.873l188.387 183.741c0.834 0.338 1.802 0.535 2.816 0.535s1.982-0.196 2.868-0.553c0.285 0.079 0.672 0.113 1.067 0.113 3.676 0 6.656-2.98 6.656-6.656 0-0.395-0.034-0.782-0.1-1.159-0.528-1.405-1.409-2.616-2.539-3.532zM592.38 231.948v44.030h-44.030v36.862l31.23 31.23 80.38-80.38-31.23-31.23zM0.028 239.627h416.234v-51.197h-416.234v51.197z" />
+<glyph unicode="&#xe902;" glyph-name="current-ref" d="M530.92 258.291l-70.054 71.588c-17.993 18.204-42.963 29.478-70.566 29.478s-52.573-11.274-70.557-29.468l-30.178 30.159c18.419 18.312 29.902 43.583 30.169 71.537-0.795 26.578-11.995 50.343-29.636 67.527l-70.586 71.609c-17.861 17.868-42.538 28.92-69.798 28.92s-51.937-11.052-69.798-28.92l-51.134-51.134c-17.868-17.861-28.92-42.538-28.92-69.798s11.052-51.937 28.92-69.798l74.145-69.543c17.993-18.204 42.963-29.478 70.566-29.478s52.573 11.274 70.557 29.468l30.178-30.159c-18.419-18.312-29.902-43.583-30.169-71.537-0.004-0.365-0.006-0.734-0.006-1.105 0-25.692 9.92-49.067 26.139-66.504l70.511-71.528c17.835-17.716 42.411-28.665 69.543-28.665s51.708 10.949 69.549 28.67l51.128 51.129c17.992 17.803 29.134 42.5 29.134 69.798s-11.142 51.995-29.126 69.791zM241.499 405.047c-11.25 11.25-20.965 24.545-38.351 24.545-18.074 0-32.726-14.652-32.726-32.726 0-17.386 13.295-27.101 24.545-38.351-5.924-6.606-14.486-10.742-24.015-10.742-0.186 0-0.372 0.002-0.557 0.005-0.198-0.006-0.464-0.009-0.731-0.009-8.851 0-16.88 3.513-22.771 9.221l-71.068 71.58c-5.845 5.909-9.456 14.038-9.456 23.010s3.61 17.101 9.459 23.013l51.131 51.131c6.103 5.703 14.326 9.204 23.366 9.204 0.055 0 0.11 0 0.164 0 0.003 0 0.017 0 0.031 0 9.168 0 17.47-3.712 23.483-9.716l69.543-72.1c6.338-6.063 10.278-14.588 10.278-24.033s-3.94-17.97-10.266-24.021zM493.592 188.748c-0.074-9.007-3.775-17.135-9.713-23.007l-51.137-51.137c-5.96-5.4-13.905-8.705-22.623-8.705-0.317 0-0.631 0.004-0.946 0.013-0.18-0.007-0.446-0.010-0.713-0.010-8.851 0-16.88 3.513-22.771 9.221l-69.022 72.092c-6.338 6.063-10.278 14.588-10.278 24.033s3.94 17.97 10.266 24.021c11.262-11.238 20.977-24.533 38.363-24.533 0.611-0.041 1.326-0.064 2.045-0.064 18.074 0 32.726 14.652 32.726 32.726 0 0.023 0 0.045 0 0.068 0 17.382-13.295 27.097-24.545 38.347 5.712 7.509 14.519 12.409 24.486 12.782 0.070 0.002 0.084 0.002 0.098 0.002 9.168 0 17.47-3.712 23.483-9.716l71.077-71.077c5.998-5.856 9.719-14.023 9.719-23.059 0-0.163-0.001-0.325-0.004-0.487zM1013.117 794.18l-51.134 51.134c-6.502 6.632-15.554 10.743-25.567 10.743s-19.066-4.111-25.561-10.737l-245.451-243.917-107.894 108.405c-6.502 6.632-15.554 10.743-25.567 10.743s-19.066-4.111-25.561-10.737l-51.14-51.14c-6.632-6.502-10.743-15.554-10.743-25.567s4.111-19.066 10.737-25.561l135.512-133.978 51.134-51.134c6.502-6.632 15.554-10.743 25.567-10.743s19.066 4.111 25.561 10.737l51.14 51.14 268.967 269.99c6.632 6.502 10.743 15.554 10.743 25.567s-4.111 19.066-10.737 25.561z" />
+<glyph unicode="&#xe903;" glyph-name="chrono" horiz-adv-x="931" d="M440.957-64c243.751 0 440.957 196.267 440.957 438.857 0 225.524-171.483 412.038-391.962 436.419v51.2h73.493v97.524h-244.976v-97.524h73.493v-51.2c-220.478-24.381-391.962-209.676-391.962-436.419 0-242.59 197.206-438.857 440.957-438.857zM756.974 864.917l-71.043-70.705c71.043-41.448 131.062-101.181 172.708-171.886l71.055 70.705c-44.108 69.486-104.115 128-172.72 171.886z" />
+>>>>>>> master
</font></defs></svg> \ No newline at end of file
diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js b/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js
index 709686f21..54d62f999 100644
--- a/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js
+++ b/app/assets/javascripts/es6_browserified/journey_patterns/actions/index.js
@@ -130,9 +130,10 @@ const actions = {
if(next) {
dispatch(next)
} else {
- if(json.length != window.journeyPatternsPerPage){
- dispatch(actions.updateTotalCount(window.journeyPatternsPerPage - json.length))
+ if(json.length != window.currentItemsLength){
+ dispatch(actions.updateTotalCount(window.currentItemsLength - json.length))
}
+ window.currentItemsLength = json.length
dispatch(actions.receiveJourneyPatterns(json))
}
}
@@ -196,6 +197,7 @@ const actions = {
})
}
}
+ window.currentItemsLength = journeyPatterns.length
dispatch(actions.receiveJourneyPatterns(journeyPatterns))
}
})
diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js
index 573ebf228..aa2d208df 100644
--- a/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js
+++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/CreateModal.js
@@ -17,7 +17,7 @@ class CreateModal extends Component {
}
render() {
- if(this.props.status.isFetching == true) {
+ if(this.props.status.isFetching == true || this.props.status.policy['journey_patterns.edit'] == false) {
return false
}
if(this.props.status.fetchSuccess == true) {
diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js
index 3dae38d74..d9f6d5550 100644
--- a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js
+++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js
@@ -14,7 +14,7 @@ class JourneyPattern extends Component{
let vjURL = routeURL + '/vehicle_journeys?jp=' + jpOid
return (
- <a href={vjURL}>Horaires des courses</a>
+ <a data-no-turbolink="true" href={vjURL}>Horaires des courses</a>
)
}
@@ -34,7 +34,7 @@ class JourneyPattern extends Component{
type='checkbox'
id={sp.id}
checked={sp.checked}
- disabled={this.props.value.deletable ? 'disabled' : ''}
+ disabled={(this.props.value.deletable || this.props.status.policy['journey_patterns.edit'] == false) ? 'disabled' : ''}
>
</input>
<span className='radio-label'></span>
@@ -74,29 +74,30 @@ class JourneyPattern extends Component{
<span className='fa fa-cog'></span>
</div>
<ul className='dropdown-menu'>
- <li className={this.props.value.deletable ? 'disabled' : ''}>
- <a
- href='#'
+ <li className={(this.props.value.deletable || this.props.status.policy['journey_patterns.edit'] == false) ? 'disabled' : ''}>
+ <button
+ type='button'
onClick={this.props.onOpenEditModal}
data-toggle='modal'
data-target='#JourneyPatternModal'
>
Editer
- </a>
+ </button>
</li>
<li className={this.props.value.object_id ? '' : 'disabled'}>
{this.vehicleJourneyURL(this.props.value.object_id)}
</li>
- <li className='delete-action'>
- <a
- href='#'
+ <li className={'delete-action' + ((this.props.status.policy['journey_patterns.edit'] == false)? ' disabled' : '')}>
+ <button
+ type='button'
+ disabled={(this.props.status.policy['journey_patterns.edit'] == false)? 'disabled' : ''}
onClick={(e) => {
e.preventDefault()
this.props.onDeleteJourneyPattern(this.props.index)}
}
>
- <span className='fa fa-trash'></span>Supprimer
- </a>
+ <span className='fa fa-trash'></span>Supprimer
+ </button>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js
index 37a0a5126..e0557d651 100644
--- a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js
+++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPatterns.js
@@ -116,6 +116,7 @@ class JourneyPatterns extends Component{
onCheckboxChange= {(e) => this.props.onCheckboxChange(e, index)}
onOpenEditModal= {() => this.props.onOpenEditModal(index, journeyPattern)}
onDeleteJourneyPattern={() => this.props.onDeleteJourneyPattern(index)}
+ status= {this.props.status}
/>
)}
</div>
diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/Navigate.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/Navigate.js
index 3ca860e2e..5747aa5ce 100644
--- a/app/assets/javascripts/es6_browserified/journey_patterns/components/Navigate.js
+++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/Navigate.js
@@ -31,7 +31,7 @@ let Navigate = ({ dispatch, journeyPatterns, pagination, status }) => {
data-toggle=''
data-target='#ConfirmModal'
className={'previous_page' + (pagination.page == firstPage ? ' disabled' : '')}
- disabled={'previous_page' + (pagination.page == firstPage ? ' disabled' : '')}
+ disabled={(pagination.page == firstPage ? ' disabled' : '')}
>
</button>
<button
@@ -43,7 +43,7 @@ let Navigate = ({ dispatch, journeyPatterns, pagination, status }) => {
data-toggle=''
data-target='#ConfirmModal'
className={'next_page' + (pagination.page == lastPage ? ' disabled' : '')}
- disabled={'next_page' + (pagination.page == lastPage ? ' disabled' : '')}
+ disabled={(pagination.page == lastPage ? 'disabled' : '')}
>
</button>
</form>
diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js
index 6e09430a0..93dfa8c6b 100644
--- a/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js
+++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/SaveJourneyPattern.js
@@ -15,7 +15,7 @@ class SaveJourneyPattern extends Component{
}
render() {
- if(this.props.status.isFetching == true) {
+ if(this.props.status.isFetching == true || (this.props.status.policy['journey_patterns.edit'] == false)) {
return false
}
if(this.props.status.fetchSuccess == true) {
diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/index.js b/app/assets/javascripts/es6_browserified/journey_patterns/index.js
index a2e1c2fb6..b06957e0f 100644
--- a/app/assets/javascripts/es6_browserified/journey_patterns/index.js
+++ b/app/assets/javascripts/es6_browserified/journey_patterns/index.js
@@ -13,6 +13,7 @@ var App = require('./components/App')
var initialState = {
status: {
+ policy: window.perms,
fetchSuccess: true,
isFetching: false
},
diff --git a/app/assets/javascripts/es6_browserified/time_tables/actions/index.js b/app/assets/javascripts/es6_browserified/time_tables/actions/index.js
new file mode 100644
index 000000000..a9fbb94cf
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/actions/index.js
@@ -0,0 +1,195 @@
+const _ = require('lodash')
+
+const actions = {
+ strToArrayDayTypes: (str) =>{
+ let weekDays = ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa']
+ return weekDays.map((day, i) => str.indexOf(day) !== -1)
+ },
+
+ fetchingApi: () =>({
+ type: 'FETCH_API'
+ }),
+ unavailableServer: () => ({
+ type: 'UNAVAILABLE_SERVER'
+ }),
+ receiveMonth: (json) => ({
+ type: 'RECEIVE_MONTH',
+ json
+ }),
+ receiveTimeTables: (json) => ({
+ type: 'RECEIVE_TIME_TABLES',
+ json
+ }),
+ goToPreviousPage : (dispatch, pagination) => ({
+ type: 'GO_TO_PREVIOUS_PAGE',
+ dispatch,
+ pagination,
+ nextPage : false
+ }),
+ goToNextPage : (dispatch, pagination) => ({
+ type: 'GO_TO_NEXT_PAGE',
+ dispatch,
+ pagination,
+ nextPage : true
+ }),
+ changePage : (dispatch, pagination, val) => ({
+ type: 'CHANGE_PAGE',
+ dispatch,
+ page: val
+ }),
+ updateDayTypes: (index) => ({
+ type: 'UPDATE_DAY_TYPES',
+ index
+ }),
+ updateComment: (comment) => ({
+ type: 'UPDATE_COMMENT',
+ comment
+ }),
+ updateColor: (color) => ({
+ type: 'UPDATE_COLOR',
+ color
+ }),
+ select2Tags: (selectedTag) => ({
+ type: 'UPDATE_SELECT_TAG',
+ selectedItem: {
+ id: selectedTag.id,
+ name: selectedTag.name
+ }
+ }),
+ unselect2Tags: (selectedTag) => ({
+ type: 'UPDATE_UNSELECT_TAG',
+ selectedItem: {
+ id: selectedTag.id,
+ name: selectedTag.name
+ }
+ }),
+ deletePeriod: (index, dayTypes) => ({
+ type: 'DELETE_PERIOD',
+ index,
+ dayTypes
+ }),
+ openAddPeriodForm: () => ({
+ type: 'OPEN_ADD_PERIOD_FORM'
+ }),
+ openEditPeriodForm: (period, index) => ({
+ type: 'OPEN_EDIT_PERIOD_FORM',
+ period,
+ index
+ }),
+ closePeriodForm: () => ({
+ type: 'CLOSE_PERIOD_FORM'
+ }),
+ updatePeriodForm: (val, group, selectType) => ({
+ type: 'UPDATE_PERIOD_FORM',
+ val,
+ group,
+ selectType
+ }),
+ includeDateInPeriod: (index, day, dayTypes) => ({
+ type: 'INCLUDE_DATE_IN_PERIOD',
+ index,
+ day,
+ dayTypes
+ }),
+ excludeDateFromPeriod: (index, day, dayTypes) => ({
+ type: 'EXCLUDE_DATE_FROM_PERIOD',
+ index,
+ day,
+ dayTypes
+ }),
+
+ monthName(strDate) {
+ let monthList = ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"]
+ var date = new Date(strDate)
+ return monthList[date.getMonth()]
+ },
+ getHumanDate(strDate, mLimit) {
+ let origin = strDate.split('-')
+ let D = origin[2]
+ let M = actions.monthName(strDate).toLowerCase()
+ let Y = origin[0]
+
+ if(mLimit && M.length > mLimit) {
+ M = M.substr(0, mLimit) + '.'
+ }
+
+ return (D + ' ' + M + ' ' + Y)
+ },
+
+ updateSynthesis: (state, daytypes) => {
+ let periods = state.time_table_periods
+
+ let isInPeriod = function(d){
+ let currentMonth = state.current_periode_range.split('-')
+ let twodigitsDay = d.mday < 10 ? ('0' + d.mday) : d.mday
+ let currentDate = new Date(currentMonth[0] + '-' + currentMonth[1] + '-' + twodigitsDay)
+
+ // We compare periods & currentDate, to determine if it is included or not
+ let testDate = false
+ periods.map((p, i) => {
+ if(p.deleted){
+ return false
+ }
+ let begin = new Date(p.period_start)
+ let end = new Date(p.period_end)
+
+ if(testDate === false){
+ if(currentDate >= begin && currentDate <= end) {
+ if(daytypes[d.wday] === false) {
+ testDate = false
+ } else {
+ testDate = true
+ }
+ }
+ }
+ })
+ return testDate
+ }
+
+ let improvedCM = state.current_month.map((d, i) => {
+ return _.assign({}, state.current_month[i], {
+ in_periods: isInPeriod(state.current_month[i])
+ })
+ })
+ return improvedCM
+ },
+
+ checkConfirmModal: (event, callback, stateChanged,dispatch) => {
+ if(stateChanged === true){
+ return actions.openConfirmModal(callback)
+ }else{
+ dispatch(actions.fetchingApi())
+ return callback
+ }
+ },
+ fetchTimeTables: (dispatch, nextPage) => {
+ let urlJSON = window.location.pathname.split('/', 5).join('/')
+ // console.log(nextPage)
+ if(nextPage) {
+ urlJSON += "/month.json?date=" + nextPage
+ }else{
+ urlJSON += ".json"
+ }
+ let hasError = false
+ fetch(urlJSON, {
+ credentials: 'same-origin',
+ }).then(response => {
+ if(response.status == 500) {
+ hasError = true
+ }
+ return response.json()
+ }).then((json) => {
+ if(hasError == true) {
+ dispatch(actions.unavailableServer())
+ } else {
+ if(nextPage){
+ dispatch(actions.receiveMonth(json))
+ }else{
+ dispatch(actions.receiveTimeTables(json))
+ }
+ }
+ })
+ },
+}
+
+module.exports = actions
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js
new file mode 100644
index 000000000..13615a6ef
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/ExceptionsInDay.js
@@ -0,0 +1,65 @@
+var React = require('react')
+var Component = require('react').Component
+var PropTypes = require('react').PropTypes
+var actions = require('../actions')
+
+class ExceptionsInDay extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render() {
+ {/* display add or remove link, only if true in daytypes */}
+ if(this.props.outFromDaytypes == true) {
+ {/* display add or remove link, according to context (presence in period, or not) */}
+ if(this.props.value.current_month[this.props.index].in_periods == true) {
+ return (
+ <div className='td'>
+ <button
+ type='button'
+ className='btn btn-circle'
+ data-actiontype='remove'
+ onClick={(e) => {
+ $(e.currentTarget).toggleClass('active')
+ this.props.onExcludeDateFromPeriod(this.props.index, this.props.value.current_month[this.props.index], this.props.metas.day_types)
+ }}
+ >
+ <span className='fa fa-times'></span>
+ </button>
+ </div>
+ )
+ } else {
+ return (
+ <div className='td'>
+ <button
+ type='button'
+ className='btn btn-circle'
+ data-actiontype='add'
+ onClick={(e) => {
+ $(e.currentTarget).toggleClass('active')
+ this.props.onIncludeDateInPeriod(this.props.index, this.props.value.current_month[this.props.index], this.props.metas.day_types)
+ }}
+ >
+ <span className='fa fa-plus'></span>
+ </button>
+ </div>
+ )
+ }
+ } else {
+ return (
+ <div className='td'></div>
+ )
+ }
+ }
+}
+
+ExceptionsInDay.propTypes = {
+ value: PropTypes.object.isRequired,
+ metas: PropTypes.object.isRequired,
+ outFromDaytypes: PropTypes.bool.isRequired,
+ onExcludeDateFromPeriod: PropTypes.func.isRequired,
+ onIncludeDateInPeriod: PropTypes.func.isRequired,
+ index: PropTypes.number.isRequired
+}
+
+module.exports = ExceptionsInDay
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/Metas.js b/app/assets/javascripts/es6_browserified/time_tables/components/Metas.js
new file mode 100644
index 000000000..943b781f5
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/Metas.js
@@ -0,0 +1,139 @@
+var React = require('react')
+var PropTypes = require('react').PropTypes
+let weekDays = ['D', 'L', 'Ma', 'Me', 'J', 'V', 'S']
+var TagsSelect2 = require('./TagsSelect2')
+
+const Metas = ({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelect2Tags, onUnselect2Tags}) => {
+ let colorList = ["", "#9B9B9B", "#FFA070", "#C67300", "#7F551B", "#41CCE3", "#09B09C", "#3655D7", "#6321A0", "#E796C6", "#DD2DAA"]
+ return (
+ <div className="row">
+ <div className="col-lg-6 col-lg-offset-3 col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1">
+ <div className='form-horizontal'>
+ <div className="row">
+ <div className="col-lg-12">
+ {/* comment (name) */}
+ <div className="form-group">
+ <label htmlFor="" className="control-label col-sm-4 required">
+ Nom <abbr title="Champ requis">*</abbr>
+ </label>
+ <div className="col-sm-8">
+ <input
+ type='text'
+ className='form-control'
+ value={metas.comment}
+ onChange={(e) => (onUpdateComment(e.currentTarget.value))}
+ />
+ </div>
+ </div>
+
+ {/* color */}
+ <div className="form-group">
+ <label htmlFor="" className="control-label col-sm-4">Couleur associée</label>
+ <div className="col-sm-8">
+ <div className="dropdown color_selector">
+ <button
+ type='button'
+ className="btn btn-default dropdown-toggle"
+ id='dpdwn_color'
+ data-toggle='dropdown'
+ aria-haspopup='true'
+ aria-expanded='true'
+ >
+ <span
+ className='fa fa-circle mr-xs'
+ style={{color: (metas.color == '') ? 'transparent' : metas.color}}
+ ></span>
+ <span className='caret'></span>
+ </button>
+
+ <div className="form-group dropdown-menu" aria-labelledby='dpdwn_color'>
+ {colorList.map((c, i) =>
+ <span
+ className="radio"
+ key={i}
+ onClick={() => {onUpdateColor(c)}}
+ >
+ <label htmlFor="">
+ <input
+ type='radio'
+ className='color_selector'
+ value={c}
+ />
+ <span
+ className='fa fa-circle'
+ style={{color: ((c == '') ? 'transparent' : c)}}
+ ></span>
+ </label>
+ </span>
+ )}
+ </div>
+ </div>
+ </div>
+ </div>
+
+ {/* tags */}
+ {/* <div className="form-group">
+ <label htmlFor="" className="control-label col-sm-4">Etiquettes</label>
+ <div className="col-sm-8">
+ <TagsSelect2
+ tags={metas.tags}
+ onSelect2Tags={(e) => onSelect2Tags(e)}
+ onUnselect2Tags={(e) => onUnselect2Tags(e)}
+ />
+ <input type="text" value='ton papa' className='form-control'/>
+ </div>
+ </div>
+ */}
+
+ {/* calendar */}
+ <div className="form-group">
+ <label htmlFor="" className="control-label col-sm-4">Modèle de calendrier associé</label>
+ <div className="col-sm-8">
+ <span>{metas.calendar.name}</span>
+ </div>
+ </div>
+ {/* day_types */}
+ <div className="form-group">
+ <label htmlFor="" className="control-label col-sm-4">
+ Journées d'applications pour les périodes ci-dessous
+ </label>
+ <div className="col-sm-8">
+ <div className="form-group labelled-checkbox-group">
+ {metas.day_types.map((day, i) =>
+ <div className="lcbx-group-item"
+ key={i}
+ >
+ <div className="checkbox">
+ <label>
+ <input
+ onChange={(e) => {onUpdateDayTypes(i)}}
+ id={i}
+ type="checkbox"
+ checked={day ? 'checked' : ''}
+ />
+ <span className='lcbx-group-item-label'>{weekDays[i]}</span>
+ </label>
+ </div>
+ </div>
+ )}
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+}
+
+Metas.propTypes = {
+ metas: PropTypes.object.isRequired,
+ onUpdateDayTypes: PropTypes.func.isRequired,
+ onUpdateColor: PropTypes.func.isRequired,
+ onUpdateColor: PropTypes.func.isRequired,
+ onSelect2Tags: PropTypes.func.isRequired,
+ onUnselect2Tags: PropTypes.func.isRequired
+}
+
+module.exports = Metas
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/Navigate.js b/app/assets/javascripts/es6_browserified/time_tables/components/Navigate.js
new file mode 100644
index 000000000..5db373f9c
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/Navigate.js
@@ -0,0 +1,96 @@
+var React = require('react')
+var Component = require('react').Component
+var PropTypes = require('react').PropTypes
+var actions = require('../actions')
+var _ = require('lodash')
+
+let Navigate = ({ dispatch, metas, timetable, pagination, status, filters}) => {
+ if(status.isFetching == true) {
+ return false
+ }
+ if(status.fetchSuccess == true) {
+ let pageIndex = pagination.periode_range.indexOf(pagination.currentPage)
+ let firstPage = pageIndex == 0
+ let lastPage = pageIndex == pagination.periode_range.length - 1
+ return (
+ <div className="row mt-md">
+ <div className="col-lg-8 col-lg-offset-2 col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1 text-right">
+ <div className="pagination">
+ <form className='form-inline' onSubmit={e => {e.preventDefault()}}>
+ {/* date selector */}
+ <div className="form-group">
+ <div className="dropdown month_selector" style={{display: 'inline-block'}}>
+ <div
+ className='btn btn-default dropdown-toggle'
+ id='date_selector'
+ data-toggle='dropdown'
+ aria-haspopup='true'
+ aria-expanded='true'
+ >
+ {pagination.currentPage ? (actions.monthName(pagination.currentPage) + ' ' + new Date(pagination.currentPage).getFullYear()) : ''}
+ <span className='caret'></span>
+ </div>
+ <ul
+ className='dropdown-menu'
+ aria-labelledby='date_selector'
+ >
+ {_.map(pagination.periode_range, (month, i) => (
+ <li key={i}>
+ <button
+ type='button'
+ value={month}
+ onClick={e => {
+ e.preventDefault()
+ dispatch(actions.checkConfirmModal(e, actions.changePage(dispatch, pagination, e.currentTarget.value), pagination.stateChanged, dispatch))
+ }}
+ >
+ {actions.monthName(month) + ' ' + new Date(month).getFullYear()}
+ </button>
+ </li>
+ ))}
+ </ul>
+ </div>
+ </div>
+
+ {/* prev/next */}
+ <div className="form-group">
+ <div className="page_links">
+ <button
+ onClick={e => {
+ e.preventDefault()
+ dispatch(actions.checkConfirmModal(e, actions.goToPreviousPage(dispatch, pagination), pagination.stateChanged, dispatch))
+ }}
+ type='button'
+ data-target='#ConfirmModal'
+ className={(firstPage ? 'disabled ' : '') + 'previous_page'}
+ disabled={(firstPage ? 'disabled' : '')}
+ ></button>
+ <button
+ onClick={e => {
+ e.preventDefault()
+ dispatch(actions.checkConfirmModal(e, actions.goToNextPage(dispatch, pagination), pagination.stateChanged, dispatch))
+ }}
+ type='button'
+ data-target='#ConfirmModal'
+ className={(lastPage ? 'disabled ' : '') + 'next_page'}
+ disabled={(lastPage ? 'disabled' : '')}
+ ></button>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ )
+ } else {
+ return false
+ }
+}
+
+Navigate.propTypes = {
+ status: PropTypes.object.isRequired,
+ pagination: PropTypes.object.isRequired,
+ dispatch: PropTypes.func.isRequired
+}
+
+module.exports = Navigate
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js
new file mode 100644
index 000000000..274429af8
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js
@@ -0,0 +1,90 @@
+var React = require('react')
+var PropTypes = require('react').PropTypes
+let monthsArray = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
+
+const formatNumber = (val) => {
+ return ("0" + val).slice(-2)
+}
+
+const makeDaysOptions = (daySelected) => {
+ let arr = []
+ for(let i = 1; i < 32; i++) {
+ arr.push(<option value={formatNumber(i)} key={i}>{formatNumber(i)}</option>)
+ }
+ return arr
+}
+
+const makeMonthsOptions = (monthSelected) => {
+ let arr = []
+ for(let i = 1; i < 13; i++) {
+ arr.push(<option value={formatNumber(i)} key={i}>{monthsArray[i - 1]}</option>)
+ }
+ return arr
+}
+
+const makeYearsOptions = (yearSelected) => {
+ let arr = []
+ let startYear = new Date().getFullYear() - 3
+ for(let i = startYear; i <= startYear + 6; i++) {
+ arr.push(<option key={i}>{i}</option>)
+ }
+ return arr
+}
+
+const PeriodForm = ({modal, timetable, onOpenAddPeriodForm, onClosePeriodForm, onUpdatePeriodForm}) => (
+ <div>
+ {modal.modalProps.active &&
+ <div className="form-group date filter_menu-item">
+ <label className="date required control-label" >Du <abbr title="Champ requis">*</abbr></label>
+ <div className="form-inline">
+ <select value={formatNumber(modal.modalProps.begin.day)} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'begin', 'day')} id="q_validity_period_begin_gteq_3i" className="date required form-control">
+ {makeDaysOptions(modal.modalProps.begin.day)}
+ </select>
+ <select value={formatNumber(modal.modalProps.begin.month)} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'begin', 'month')} id="q_validity_period_begin_gteq_2i" className="date required form-control">
+ {makeMonthsOptions(modal.modalProps.begin.month)}
+ </select>
+ <select value={modal.modalProps.begin.year} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'begin', 'year')} id="q_validity_period_begin_gteq_1i" className="date required form-control">
+ {makeYearsOptions(modal.modalProps.begin.year)}
+ </select>
+ </div>
+ <label className="date required control-label" >Au <abbr title="Champ requis">*</abbr></label>
+ <div className="form-inline">
+ <select value={formatNumber(modal.modalProps.end.day)} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'end', 'day')} id="q_validity_period_end_gteq_3i" className="date required form-control">
+ {makeDaysOptions(modal.modalProps.end.day)}
+ </select>
+ <select value={formatNumber(modal.modalProps.end.month)} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'end', 'month')} id="q_validity_period_end_gteq_2i" className="date required form-control">
+ {makeMonthsOptions(modal.modalProps.end.month)}
+ </select>
+ <select value={modal.modalProps.end.year} onChange={(e) => onUpdatePeriodForm(e.currentTarget.value, 'end', 'year')} id="q_validity_period_end_gteq_1i" className="date required form-control">
+ {makeYearsOptions(modal.modalProps.end.year)}
+ </select>
+ </div>
+ <div>
+ <button
+ onClick={onClosePeriodForm}
+ >
+ Annuler
+ </button>
+ <button>Valider</button>
+ </div>
+ </div>
+ }
+ {!modal.modalProps.active &&
+ <button
+ onClick={onOpenAddPeriodForm}
+ >
+ Ajouter une période
+ </button>
+ }
+ </div>
+)
+
+PeriodForm.propTypes = {
+ modal: PropTypes.object.isRequired,
+ onOpenAddPeriodForm: PropTypes.func.isRequired,
+ onClosePeriodForm: PropTypes.func.isRequired,
+ onUpdatePeriodForm: PropTypes.func.isRequired,
+ timetable: PropTypes.object.isRequired
+}
+
+module.exports = PeriodForm
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js
new file mode 100644
index 000000000..de3f31ee0
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodManager.js
@@ -0,0 +1,65 @@
+var React = require('react')
+var Component = require('react').Component
+var PropTypes = require('react').PropTypes
+var actions = require('../actions')
+
+class PeriodManager extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render() {
+ return (
+ <div
+ className='period_manager'
+ id={this.props.value.id}
+ >
+ <p className='strong'>
+ {actions.getHumanDate(this.props.value.period_start, 3).substr(0, 7) + ' > ' + actions.getHumanDate(this.props.value.period_end, 3)}
+ </p>
+
+ <div className='dropdown'>
+ <div
+ className='btn dropdown-toggle'
+ id='period_actions'
+ data-toggle='dropdown'
+ aria-haspopup='true'
+ aria-expanded='true'
+ >
+ <span className='fa fa-cog'></span>
+ </div>
+ <ul
+ className='dropdown-menu'
+ aria-labelledby='date_selector'
+ >
+ <li>
+ <button
+ type='button'
+ onClick={() => this.props.onOpenEditPeriodForm(this.props.value, this.props.index)}
+ >
+ Modifier
+ </button>
+ </li>
+ <li className='delete-action'>
+ <button
+ type='button'
+ onClick={() => this.props.onDeletePeriod(this.props.index, this.props.metas.day_types)}
+ >
+ <span className='fa fa-trash'></span>
+ Supprimer
+ </button>
+ </li>
+ </ul>
+ </div>
+ </div>
+ )
+ }
+}
+
+PeriodManager.propTypes = {
+ value: PropTypes.object.isRequired,
+ onDeletePeriod: PropTypes.func.isRequired,
+ onOpenEditPeriodForm: PropTypes.func.isRequired
+}
+
+module.exports = PeriodManager
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js
new file mode 100644
index 000000000..93a8fe433
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodsInDay.js
@@ -0,0 +1,78 @@
+var React = require('react')
+var Component = require('react').Component
+var PropTypes = require('react').PropTypes
+var PeriodManager = require('./PeriodManager')
+
+class PeriodsInDay extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ isIn(date) {
+ let currentDate = date.getTime()
+ let cls = 'td'
+ let periods = this.props.value
+
+ periods.map((p, i) => {
+ if (!p.deleted){
+ let begin = new Date(p.period_start).getTime()
+ let end = new Date(p.period_end).getTime()
+
+ if(currentDate >= begin && currentDate <= end) {
+ if(currentDate == begin) {
+ cls += ' in_periods start_period'
+ } else if(currentDate == end) {
+ cls += ' in_periods end_period'
+ } else {
+ cls += ' in_periods'
+ }
+ }
+ }
+ })
+ return cls
+ }
+
+ render() {
+ return (
+ <div
+ className={this.isIn(this.props.currentDate)}
+ >
+ {this.props.value.map((p, i) => {
+ if(!p.deleted){
+ let begin = new Date(p.period_start).getTime()
+ let end = new Date(p.period_end).getTime()
+ let d = this.props.currentDate.getTime()
+
+ if(d >= begin && d <= end) {
+ if(d == begin || (this.props.currentDate.getUTCDate() == 1)) {
+ return (
+ <PeriodManager
+ key={i}
+ index={i}
+ value={p}
+ onDeletePeriod={this.props.onDeletePeriod}
+ onOpenEditPeriodForm={this.props.onOpenEditPeriodForm}
+ metas={this.props.metas}
+ />
+ )
+ } else {
+ return false
+ }
+ }
+ }else{
+ return false
+ }
+ })}
+ </div>
+ )
+ }
+}
+
+PeriodsInDay.propTypes = {
+ value: PropTypes.array.isRequired,
+ currentDate: PropTypes.object.isRequired,
+ index: PropTypes.number.isRequired,
+ onDeletePeriod: PropTypes.func.isRequired
+}
+
+module.exports = PeriodsInDay
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js b/app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js
new file mode 100644
index 000000000..16ebc250a
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/TagsSelect2.js
@@ -0,0 +1,73 @@
+var _ = require('lodash')
+var React = require('react')
+var PropTypes = require('react').PropTypes
+var Select2 = require('react-select2')
+
+// get JSON full path
+var origin = window.location.origin
+var path = window.location.pathname.split('/', 4).join('/')
+var _ = require('lodash')
+
+class TagsSelect2 extends React.Component{
+ constructor(props) {
+ super(props)
+ }
+
+ mapKeys(array){
+ return array.map((item) =>
+ _.mapKeys(item, (v, k) =>
+ ((k == 'name') ? 'text' : k)
+ )
+ )
+ }
+
+ render() {
+ return (
+ <Select2
+ value={(this.props.tags.length) ? _.map(this.props.tags, 'id') : undefined}
+ data={(this.props.tags.length) ? this.mapKeys(this.props.tags) : undefined}
+ onSelect={(e) => this.props.onSelect2Tags(e)}
+ onUnselect={(e) => setTimeout( () => this.props.onUnselect2Tags(e, 150))}
+ multiple={true}
+ ref='tags_id'
+ options={{
+ allowClear: true,
+ theme: 'bootstrap',
+ width: '100%',
+ placeholder: 'Cherchez un tag...',
+ ajax: {
+ url: origin + path + '/tags.json',
+ dataType: 'json',
+ delay: '500',
+ data: function(params) {
+ return {
+ tag: params.term,
+ };
+ },
+ processResults: function(data, params) {
+
+ return {
+ results: data.map(
+ item => _.assign(
+ {},
+ item,
+ {text: item.name}
+ )
+ )
+ };
+ },
+ cache: true
+ },
+ minimumInputLength: 3,
+ templateResult: formatRepo
+ }}
+ />
+ )
+ }
+}
+
+const formatRepo = (props) => {
+ if(props.name) return props.name
+}
+
+module.exports = TagsSelect2
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js b/app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js
new file mode 100644
index 000000000..29c894565
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/TimeTableDay.js
@@ -0,0 +1,35 @@
+var React = require('react')
+var Component = require('react').Component
+var PropTypes = require('react').PropTypes
+
+class TimeTableDay extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render() {
+ return (
+ <span
+ className={'day' + (this.props.value.wday == 0 ? ' last_wday' : '')}
+ data-wday={'S' + this.props.value.wnumber}
+ >
+ <span className='dayname'>
+ {((this.props.value.day).charAt(0) == 'm') ? (this.props.value.day).substr(0, 2) : (this.props.value.day).charAt(0)}
+ </span>
+ <span
+ className={'daynumber' + (((this.props.value.in_periods && this.props.dayTypeActive && !this.props.value.excluded_date) || (this.props.value.include_date && this.props.dayTypeActive)) ? ' included' : '')}
+ >
+ {this.props.value.mday}
+ </span>
+ </span>
+ )
+ }
+}
+
+TimeTableDay.propTypes = {
+ value: PropTypes.object.isRequired,
+ index: PropTypes.number.isRequired,
+ dayTypeActive: PropTypes.bool.isRequired
+}
+
+module.exports = TimeTableDay
diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js b/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js
new file mode 100644
index 000000000..65aae0e11
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/components/Timetable.js
@@ -0,0 +1,103 @@
+var React = require('react')
+var Component = require('react').Component
+var PropTypes = require('react').PropTypes
+var TimeTableDay = require('./TimeTableDay')
+var PeriodsInDay = require('./PeriodsInDay')
+var ExceptionsInDay = require('./ExceptionsInDay')
+var actions = require('../actions')
+
+class Timetable extends Component{
+ constructor(props){
+ super(props)
+ }
+
+ currentDate(mFirstday, day) {
+ let currentMonth = mFirstday.split('-')
+ let twodigitsDay = day < 10 ? ('0' + day) : day
+ let currentDate = new Date(currentMonth[0] + '-' + currentMonth[1] + '-' + twodigitsDay)
+
+ return currentDate
+ }
+
+ render() {
+ return (
+ <div className='row'>
+ <div className="col-lg-8 col-lg-offset-2 col-md-8 col-md-offset-2 col-sm-10 col-sm-offset-1">
+ <div className="table table-2entries mb-sm">
+ <div className="t2e-head w20">
+ <div className="th">
+ <div className="strong">Synthèse</div>
+ </div>
+ <div className="td"><span>Journées d'application</span></div>
+ <div className="td"><span>Périodes</span></div>
+ <div className="td"><span>Exceptions</span></div>
+ </div>
+ <div className="t2e-item-list w80">
+ <div>
+ <div className="t2e-item">
+ <div className="th">
+ <div className="strong monthName">
+ {actions.monthName(this.props.timetable.current_periode_range)}
+ </div>
+
+ <div className='monthDays'>
+ {this.props.timetable.current_month.map((d, i) =>
+ <TimeTableDay
+ key={i}
+ index={i}
+ value={d}
+ dayTypeActive={this.props.metas.day_types[d.wday]}
+ />
+ )}
+ </div>
+ </div>
+
+ {this.props.timetable.current_month.map((d, i) =>
+ <div
+ key={i}
+ className={'td-group' + (this.props.metas.day_types[d.wday] ? '' : ' out_from_daytypes') + (d.wday == 0 ? ' last_wday' : '')}
+ >
+ {/* day_types */}
+ <div className="td"></div>
+
+ {/* periods */}
+ <PeriodsInDay
+ index={i}
+ value={this.props.timetable.time_table_periods}
+ currentDate={this.currentDate(this.props.timetable.current_periode_range, d.mday)}
+ onDeletePeriod={this.props.onDeletePeriod}
+ onOpenEditPeriodForm={this.props.onOpenEditPeriodForm}
+ metas={this.props.metas}
+ />
+
+ {/* exceptions */}
+ <ExceptionsInDay
+ index={i}
+ value={this.props.timetable}
+ metas={this.props.metas}
+ outFromDaytypes={this.props.metas.day_types[d.wday]}
+ onExcludeDateFromPeriod={this.props.onExcludeDateFromPeriod}
+ onIncludeDateInPeriod={this.props.onIncludeDateInPeriod}
+ />
+ </div>
+ )}
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ )
+ }
+}
+
+Timetable.propTypes = {
+ metas: PropTypes.object.isRequired,
+ timetable: PropTypes.object.isRequired,
+ status: PropTypes.object.isRequired,
+ onDeletePeriod: PropTypes.func.isRequired,
+ onExcludeDateFromPeriod: PropTypes.func.isRequired,
+ onIncludeDateInPeriod: PropTypes.func.isRequired
+}
+
+module.exports = Timetable
diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/App.js b/app/assets/javascripts/es6_browserified/time_tables/containers/App.js
new file mode 100644
index 000000000..fede03aec
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/containers/App.js
@@ -0,0 +1,38 @@
+var React = require('react')
+var connect = require('react-redux').connect
+var Component = require('react').Component
+var actions = require('../actions')
+var Metas = require('./Metas')
+var Timetable = require('./Timetable')
+var Navigate = require('./Navigate')
+var PeriodForm = require('./PeriodForm')
+
+class App extends Component {
+ componentDidMount(){
+ this.props.onLoadFirstPage()
+ }
+
+ render(){
+ return(
+ <div>
+ <Metas />
+ <Navigate />
+ <Timetable />
+ <PeriodForm />
+ </div>
+ )
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onLoadFirstPage: () =>{
+ dispatch(actions.fetchingApi())
+ actions.fetchTimeTables(dispatch)
+ }
+ }
+}
+
+const timeTableApp = connect(null, mapDispatchToProps)(App)
+
+module.exports = timeTableApp
diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/Metas.js b/app/assets/javascripts/es6_browserified/time_tables/containers/Metas.js
new file mode 100644
index 000000000..514ed2347
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/containers/Metas.js
@@ -0,0 +1,33 @@
+var actions = require('../actions')
+var connect = require('react-redux').connect
+var MetasComponent = require('../components/Metas')
+
+const mapStateToProps = (state) => {
+ return {
+ metas: state.metas
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onUpdateDayTypes: (index) => {
+ dispatch(actions.updateDayTypes(index))
+ },
+ onUpdateComment: (comment) => {
+ dispatch(actions.updateComment(comment))
+ },
+ onUpdateColor: (color) => {
+ dispatch(actions.updateColor(color))
+ },
+ onSelect2Tags: (e) => {
+ dispatch(actions.select2Tags(e.params.data))
+ },
+ onUnselect2Tags: (e) => {
+ dispatch(actions.unselect2Tags(e.params.data))
+ }
+ }
+}
+
+const Metas = connect(mapStateToProps, mapDispatchToProps)(MetasComponent)
+
+module.exports = Metas
diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/Navigate.js b/app/assets/javascripts/es6_browserified/time_tables/containers/Navigate.js
new file mode 100644
index 000000000..c70583c25
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/containers/Navigate.js
@@ -0,0 +1,18 @@
+var React = require('react')
+var connect = require('react-redux').connect
+var actions = require('../actions')
+var NavigateComponent = require('../components/Navigate')
+
+const mapStateToProps = (state) => {
+ return {
+ metas: state.metas,
+ timetable: state.timetable,
+ status: state.status,
+ pagination: state.pagination
+ }
+}
+
+
+const Navigate = connect(mapStateToProps)(NavigateComponent)
+
+module.exports = Navigate
diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/PeriodForm.js b/app/assets/javascripts/es6_browserified/time_tables/containers/PeriodForm.js
new file mode 100644
index 000000000..0a785c680
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/containers/PeriodForm.js
@@ -0,0 +1,28 @@
+var connect = require('react-redux').connect
+var PeriodFormComponent = require('../components/PeriodForm')
+var actions = require('../actions')
+
+const mapStateToProps = (state) => {
+ return {
+ modal: state.modal,
+ timetable: state.timetable
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onOpenAddPeriodForm: () => {
+ dispatch(actions.openAddPeriodForm())
+ },
+ onClosePeriodForm: () => {
+ dispatch(actions.closePeriodForm())
+ },
+ onUpdatePeriodForm: (val, group, selectType) => {
+ dispatch(actions.updatePeriodForm(val, group, selectType))
+ }
+ }
+}
+
+const PeriodForm = connect(mapStateToProps, mapDispatchToProps)(PeriodFormComponent)
+
+module.exports = PeriodForm
diff --git a/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js b/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js
new file mode 100644
index 000000000..2a17d3dea
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/containers/Timetable.js
@@ -0,0 +1,32 @@
+var connect = require('react-redux').connect
+var TimetableComponent = require('../components/Timetable')
+var actions = require('../actions')
+
+const mapStateToProps = (state) => {
+ return {
+ metas: state.metas,
+ timetable: state.timetable,
+ status: state.status
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onDeletePeriod: (index, dayTypes) =>{
+ dispatch(actions.deletePeriod(index, dayTypes))
+ },
+ onExcludeDateFromPeriod: (index, day, dayTypes) => {
+ dispatch(actions.excludeDateFromPeriod(index, day, dayTypes))
+ },
+ onIncludeDateInPeriod: (index, day, dayTypes) => {
+ dispatch(actions.includeDateInPeriod(index, day, dayTypes))
+ },
+ onOpenEditPeriodForm: (period, index) => {
+ dispatch(actions.openEditPeriodForm(period, index))
+ }
+ }
+}
+
+const Timetable = connect(mapStateToProps, mapDispatchToProps)(TimetableComponent)
+
+module.exports = Timetable
diff --git a/app/assets/javascripts/es6_browserified/time_tables/index.js b/app/assets/javascripts/es6_browserified/time_tables/index.js
new file mode 100644
index 000000000..69b7fdd7c
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/index.js
@@ -0,0 +1,69 @@
+var React = require('react')
+var render = require('react-dom').render
+var Provider = require('react-redux').Provider
+var createStore = require('redux').createStore
+var timeTablesApp = require('./reducers')
+var App = require('./containers/App')
+
+// logger, DO NOT REMOVE
+var applyMiddleware = require('redux').applyMiddleware
+var createLogger = require('redux-logger')
+var thunkMiddleware = require('redux-thunk').default
+var promise = require('redux-promise')
+
+var initialState = {
+ status: {
+ policy: window.perms,
+ fetchSuccess: true,
+ isFetching: false
+ },
+ timetable: {
+ current_month: [],
+ current_periode_range: '',
+ periode_range: [],
+ time_table_periods: []
+ },
+ metas: {
+ comment: '',
+ day_types: [],
+ tags: [],
+ color: '',
+ calendar: {}
+ },
+ pagination: {
+ stateChanged: false,
+ currentPage: '',
+ periode_range: []
+ },
+ modal: {
+ type: '',
+ modalProps: {
+ active: false,
+ begin: {
+ day: '01',
+ month: '01',
+ year: String(new Date().getFullYear())
+ },
+ end: {
+ day: '01',
+ month: '01',
+ year: String(new Date().getFullYear())
+ }
+ },
+ confirmModal: {}
+ }
+}
+const loggerMiddleware = createLogger()
+
+let store = createStore(
+ timeTablesApp,
+ initialState,
+ applyMiddleware(thunkMiddleware, promise, loggerMiddleware)
+)
+
+render(
+ <Provider store={store}>
+ <App />
+ </Provider>,
+ document.getElementById('periods')
+)
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/index.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/index.js
new file mode 100644
index 000000000..5b05aadda
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/index.js
@@ -0,0 +1,16 @@
+var combineReducers = require('redux').combineReducers
+var status = require('./status')
+var pagination = require('./pagination')
+var modal = require('./modal')
+var timetable = require('./timetable')
+var metas = require('./metas')
+
+const timeTablesApp = combineReducers({
+ timetable,
+ metas,
+ status,
+ pagination,
+ modal
+})
+
+module.exports = timeTablesApp
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js
new file mode 100644
index 000000000..555730908
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/metas.js
@@ -0,0 +1,33 @@
+const _ = require('lodash')
+const actions = require('../actions')
+
+const metas = (state = {}, action) => {
+ switch (action.type) {
+ case 'RECEIVE_TIME_TABLES':
+ return _.assign({}, state, {
+ comment: action.json.comment,
+ day_types: actions.strToArrayDayTypes(action.json.day_types),
+ tags: action.json.tags,
+ color: action.json.color,
+ calendar: action.json.calendar ? action.json.calendar : {name : 'Aucun'}
+ })
+ case 'UPDATE_DAY_TYPES':
+ let dayTypes = state.day_types.slice(0)
+ dayTypes[action.index] = !dayTypes[action.index]
+ return _.assign({}, state, {day_types: dayTypes})
+ case 'UPDATE_COMMENT':
+ return _.assign({}, state, {comment: action.comment})
+ case 'UPDATE_COLOR':
+ return _.assign({}, state, {color: action.color})
+ case 'UPDATE_SELECT_TAG':
+ let tags = [...state.tags]
+ tags.push(action.selectedItem)
+ return _.assign({}, state, {tags: tags})
+ case 'UPDATE_UNSELECT_TAG':
+ return _.assign({}, state, {tags: _.filter(state.tags, (t) => (t.id != action.selectedItem.id))})
+ default:
+ return state
+ }
+}
+
+module.exports = metas
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/modal.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/modal.js
new file mode 100644
index 000000000..e9c0c2fb9
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/modal.js
@@ -0,0 +1,42 @@
+var _ = require('lodash')
+let newModalProps = {}
+
+const modal = (state = {}, action) => {
+ switch (action.type) {
+ case 'CLOSE_PERIOD_FORM':
+ let emptyDate = {
+ begin: '',
+ month: '',
+ year: ''
+ }
+ newModalProps = _.assign({}, state.modalProps, {active: false, begin: emptyDate, end: emptyDate, index: false})
+ return _.assign({}, state, {modalProps: newModalProps})
+ case 'OPEN_EDIT_PERIOD_FORM':
+ let period_start = action.period.period_start.split('-')
+ let period_end = action.period.period_end.split('-')
+ newModalProps = JSON.parse(JSON.stringify(state.modalProps))
+
+ newModalProps.begin.year = period_start[0]
+ newModalProps.begin.month = period_start[1]
+ newModalProps.begin.day = period_start[2]
+
+ newModalProps.end.year = period_end[0]
+ newModalProps.end.month = period_end[1]
+ newModalProps.end.day = period_end[2]
+
+ newModalProps.active = true
+ newModalProps.index = action.index
+ return _.assign({}, state, {modalProps: newModalProps})
+ case 'OPEN_ADD_PERIOD_FORM':
+ newModalProps = _.assign({}, state.modalProps, {active: true})
+ return _.assign({}, state, {modalProps: newModalProps})
+ case 'UPDATE_PERIOD_FORM':
+ newModalProps = JSON.parse(JSON.stringify(state.modalProps))
+ newModalProps[action.group][action.selectType] = action.val
+ return _.assign({}, state, {modalProps: newModalProps})
+ default:
+ return state
+ }
+}
+
+module.exports = modal
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js
new file mode 100644
index 000000000..35b9b3cd8
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/pagination.js
@@ -0,0 +1,30 @@
+var _ = require('lodash')
+
+const pagination = (state = {}, action) => {
+ switch (action.type) {
+ case 'RECEIVE_TIME_TABLES':
+ return _.assign({}, state, {
+ currentPage: action.json.current_periode_range,
+ periode_range: action.json.periode_range
+ })
+ case 'GO_TO_PREVIOUS_PAGE':
+ case 'GO_TO_NEXT_PAGE':
+ let nextPage = action.nextPage ? 1 : -1
+ let newPage = action.pagination.periode_range[action.pagination.periode_range.indexOf(action.pagination.currentPage) + nextPage]
+ toggleOnConfirmModal()
+ return _.assign({}, state, {currentPage : newPage, stateChanged: false})
+ case 'CHANGE_PAGE':
+ toggleOnConfirmModal()
+ return _.assign({}, state, {currentPage : action.page, stateChanged: false})
+ default:
+ return state
+ }
+}
+
+const toggleOnConfirmModal = (arg = '') =>{
+ $('.confirm').each(function(){
+ $(this).data('toggle','')
+ })
+}
+
+module.exports = pagination
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/status.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/status.js
new file mode 100644
index 000000000..fc205d0ae
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/status.js
@@ -0,0 +1,17 @@
+var _ = require('lodash')
+
+const status = (state = {}, action) => {
+ switch (action.type) {
+ case 'UNAVAILABLE_SERVER':
+ return _.assign({}, state, {fetchSuccess: false})
+ case 'FETCH_API':
+ return _.assign({}, state, {isFetching: true})
+ case 'RECEIVE_TIME_TABLES':
+ case 'RECEIVE_MONTH':
+ return _.assign({}, state, {fetchSuccess: true, isFetching: false})
+ default:
+ return state
+ }
+}
+
+module.exports = status
diff --git a/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js b/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js
new file mode 100644
index 000000000..b052b5fcc
--- /dev/null
+++ b/app/assets/javascripts/es6_browserified/time_tables/reducers/timetable.js
@@ -0,0 +1,63 @@
+const _ = require('lodash')
+var actions = require('../actions')
+let newState = {}
+
+const timetable = (state = {}, action) => {
+ switch (action.type) {
+ case 'RECEIVE_TIME_TABLES':
+ let fetchedState = _.assign({}, state, {
+ current_month: action.json.current_month,
+ current_periode_range: action.json.current_periode_range,
+ periode_range: action.json.periode_range,
+ time_table_periods: action.json.time_table_periods
+ })
+ return _.assign({}, fetchedState, {current_month: actions.updateSynthesis(fetchedState, actions.strToArrayDayTypes(action.json.day_types))})
+ case 'RECEIVE_MONTH':
+ newState = _.assign({}, state, {
+ current_month: action.json.days
+ })
+ return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, actions.strToArrayDayTypes(action.json.day_types))})
+ case 'GO_TO_PREVIOUS_PAGE':
+ case 'GO_TO_NEXT_PAGE':
+ let nextPage = action.nextPage ? 1 : -1
+ let newPage = action.pagination.periode_range[action.pagination.periode_range.indexOf(action.pagination.currentPage) + nextPage]
+ $('#ConfirmModal').modal('hide')
+ actions.fetchTimeTables(action.dispatch, newPage)
+ return _.assign({}, state, {current_periode_range: newPage})
+ case 'CHANGE_PAGE':
+ $('#ConfirmModal').modal('hide')
+ actions.fetchTimeTables(action.dispatch, action.page)
+ return _.assign({}, state, {current_periode_range: action.page})
+ case 'DELETE_PERIOD':
+ let ttperiods = state.time_table_periods.map((period, i) =>{
+ if(i == action.index){
+ period.deleted = true
+ }
+ return period
+ })
+ newState = _.assign({}, state, {time_table_periods : ttperiods})
+ return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)})
+ case 'INCLUDE_DATE_IN_PERIOD':
+ let newCMi = state.current_month.map((d, i) => {
+ if(i == action.index){
+ d.include_date = !d.include_date
+ }
+ return d
+ })
+ newState = _.assign({}, state, {current_month: newCMi})
+ return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)})
+ case 'EXCLUDE_DATE_FROM_PERIOD':
+ let newCMe = state.current_month.map((d, i) => {
+ if(i == action.index){
+ d.excluded_date = !d.excluded_date
+ }
+ return d
+ })
+ newState = _.assign({}, state, {current_month: newCMe})
+ return _.assign({}, newState, {current_month: actions.updateSynthesis(newState, action.dayTypes)})
+ default:
+ return state
+ }
+}
+
+module.exports = timetable
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js
index 4e67482da..81bbcdbb0 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js
@@ -315,9 +315,12 @@ const actions = {
selected: false,
published_journey_name: val.published_journey_name || 'non renseigné',
published_journey_identifier: val.published_journey_name || 'non renseigné',
- company_id: val.published_journey_name || 'non renseigné'
+ company_id: val.published_journey_name || 'non renseigné',
+ transport_mode: val.route.line.transport_mode || 'non renseigné',
+ transport_mode: val.route.line.transport_submode || 'non renseigné'
})
}
+ window.currentItemsLength = vehicleJourneys.length
dispatch(actions.receiveVehicleJourneys(vehicleJourneys))
dispatch(actions.receiveTotalCount(json.total))
}
@@ -348,9 +351,10 @@ const actions = {
if(next) {
dispatch(next)
} else {
- if(json.length != window.vehicleJourneysPerPage){
- dispatch(actions.updateTotalCount(window.vehicleJourneysPerPage - json.length))
+ if(json.length != window.currentItemsLength){
+ dispatch(actions.updateTotalCount(window.currentItemsLength - json.length))
}
+ window.currentItemsLength = json.length
dispatch(actions.receiveVehicleJourneys(json))
}
}
@@ -362,13 +366,29 @@ const actions = {
return obj.selected
})
},
- pad: (d) => {
+ simplePad: (d) => {
if(d.toString().length == 1){
return (d < 10) ? '0' + d.toString() : d.toString();
}else{
return d.toString()
}
},
+ pad: (d, timeUnit) => {
+ let val = d.toString()
+ if(d.toString().length == 1){
+ val = (d < 10) ? '0' + d.toString() : d.toString();
+ }
+ if(val.length > 2){
+ val = val.substr(1)
+ }
+ if(timeUnit == 'minute' && parseInt(val) > 59){
+ val = '59'
+ }
+ if(timeUnit == 'hour' && parseInt(val) > 23){
+ val = '23'
+ }
+ return val
+ },
encodeParams: (params) => {
let esc = encodeURIComponent
let queryString = Object.keys(params).map((k) => esc(k) + '=' + esc(params[k])).join('&')
@@ -390,20 +410,61 @@ const actions = {
return vjas
},
checkSchedules: (schedule) => {
+ let hours = 0
+ let minutes = 0
if (parseInt(schedule.departure_time.minute) > 59){
- schedule.departure_time.minute = actions.pad(parseInt(schedule.departure_time.minute) - 60)
- schedule.departure_time.hour = actions.pad(parseInt(schedule.departure_time.hour) + 1)
+ hours = Math.floor(parseInt(schedule.departure_time.minute) / 60)
+ minutes = parseInt(schedule.departure_time.minute) % 60
+ schedule.departure_time.minute = actions.simplePad(minutes, 'minute')
+ schedule.departure_time.hour = parseInt(schedule.departure_time.hour) + hours
}
if (parseInt(schedule.arrival_time.minute) > 59){
- schedule.arrival_time.minute = actions.pad(parseInt(schedule.arrival_time.minute) - 60)
- schedule.arrival_time.hour = actions.pad(parseInt(schedule.arrival_time.hour) + 1)
+ hours = Math.floor(parseInt(schedule.arrival_time.minute) / 60)
+ minutes = parseInt(schedule.arrival_time.minute) % 60
+ schedule.arrival_time.minute = actions.simplePad(minutes, 'minute')
+ schedule.arrival_time.hour = parseInt(schedule.arrival_time.hour) + hours
}
- if (parseInt(schedule.departure_time.hour) > 23){
- schedule.departure_time.hour = actions.pad(parseInt(schedule.departure_time.hour) - 24)
+ if (parseInt(schedule.departure_time.minute) < 0){
+ hours = Math.floor(parseInt(schedule.departure_time.minute) / 60)
+ minutes = (parseInt(schedule.departure_time.minute) % 60) + 60
+ schedule.departure_time.minute = actions.simplePad(minutes, 'minute')
+ schedule.departure_time.hour = parseInt(schedule.departure_time.hour) + hours
}
- if (parseInt(schedule.arrival_time.hour) > 23){
- schedule.arrival_time.hour = actions.pad(parseInt(schedule.arrival_time.hour) - 24)
+ if (parseInt(schedule.arrival_time.minute) < 0){
+ hours = Math.floor(parseInt(schedule.arrival_time.minute) / 60)
+ minutes = (parseInt(schedule.arrival_time.minute) % 60) + 60
+ schedule.arrival_time.minute = actions.simplePad(minutes, 'minute')
+ schedule.arrival_time.hour = parseInt(schedule.arrival_time.hour) + hours
}
+
+ if(schedule.departure_time.hour > 23){
+ schedule.departure_time.hour = '23'
+ schedule.departure_time.minute = '59'
+ }
+ if(schedule.arrival_time.hour > 23){
+ schedule.arrival_time.hour = '23'
+ schedule.arrival_time.minute = '59'
+ }
+
+ if(schedule.departure_time.hour < 0){
+ schedule.departure_time.hour = '00'
+ schedule.departure_time.minute = '00'
+ }
+ if(schedule.arrival_time.hour > 23){
+ schedule.arrival_time.hour = '00'
+ schedule.arrival_time.minute = '00'
+ }
+
+ schedule.departure_time.hour = actions.simplePad(parseInt(schedule.departure_time.hour), 'hour')
+ schedule.arrival_time.hour = actions.simplePad(parseInt(schedule.arrival_time.hour), 'hour')
+ // if (parseInt(schedule.departure_time.hour) > 23){
+ // schedule.departure_time.hour = parseInt(schedule.departure_time.hour) - 24
+ // }
+ // if (parseInt(schedule.arrival_time.hour) > 23){
+ // schedule.arrival_time.hour = parseInt(schedule.arrival_time.hour) - 24
+ // }
+ // schedule.departure_time.hour = actions.pad(schedule.departure_time.hour, 'hour')
+ // schedule.arrival_time.hour = actions.pad(schedule.arrival_time.hour, 'hour')
}
}
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Filters.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Filters.js
index bddb29434..6f07dd880 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Filters.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Filters.js
@@ -97,7 +97,7 @@ const Filters = ({filters, pagination, onFilter, onResetFilters, onUpdateStartTi
onChange={onToggleWithoutSchedule}
checked={filters.query.withoutSchedule}
></input>
- <span className='switch-label' data-checkedvalue='Oui' data-uncheckedvalue='Non'></span>
+ <span className='switch-label' data-checkedvalue='Non' data-uncheckedvalue='Oui'></span>
</label>
</div>
</div>
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Navigate.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Navigate.js
index 2d5923a4d..a62e034ae 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Navigate.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/Navigate.js
@@ -29,7 +29,7 @@ let Navigate = ({ dispatch, vehicleJourneys, pagination, status, filters}) => {
type='button'
data-target='#ConfirmModal'
className={(pagination.page == firstPage ? 'disabled ' : '') + 'previous_page'}
- disabled={(pagination.page == firstPage ? true : false)}
+ disabled={(pagination.page == firstPage ? 'disabled' : '')}
></button>
<button
onClick={e => {
@@ -39,7 +39,7 @@ let Navigate = ({ dispatch, vehicleJourneys, pagination, status, filters}) => {
type='button'
data-target='#ConfirmModal'
className={(pagination.page == lastPage ? 'disabled ' : '') + 'next_page'}
- disabled={(pagination.page == lastPage ? true : false)}
+ disabled={(pagination.page == lastPage ? 'disabled' : '')}
></button>
</form>
</div>
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js
index b22e1d826..bd34ae114 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/SaveVehicleJourneys.js
@@ -15,7 +15,7 @@ class SaveVehicleJourneys extends Component{
}
render() {
- if(this.props.status.isFetching == true) {
+ if(this.props.status.isFetching == true || this.props.filters.policy['vehicle_journeys.edit'] == false) {
return false
}
if(this.props.status.fetchSuccess == true) {
@@ -46,7 +46,8 @@ class SaveVehicleJourneys extends Component{
SaveVehicleJourneys.propTypes = {
vehicleJourneys: PropTypes.array.isRequired,
page: PropTypes.number.isRequired,
- status: PropTypes.object.isRequired
+ status: PropTypes.object.isRequired,
+ filters: PropTypes.object.isRequired
}
module.exports = SaveVehicleJourneys
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js
index dc0621f76..0645fdd19 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/VehicleJourney.js
@@ -54,7 +54,7 @@ class VehicleJourney extends Component {
<div key={i}>{this.timeTableURL(tt.id)}</div>
)}
- {this.isDisabled(this.props.filters.policy['vehicle_journeys.edit'], this.props.filters.policy['vehicle_journeys.destroy']) &&
+ {(this.props.filters.policy['vehicle_journeys.edit'] == true) &&
<div className={(this.props.value.deletable ? 'disabled ' : '') + 'checkbox'}>
<input
id={this.props.index}
@@ -73,14 +73,14 @@ class VehicleJourney extends Component {
<div key={i} className='td text-center'>
<div className={'cellwrap' + (vj.dummy ? ' headlined' : '') + (this.cityNameChecker(vj) ? ' headlined' : '')}>
{this.props.filters.toggleArrivals &&
- <div data-headline='Départ à'>
- <span className={((this.props.value.deletable && (!vj.dummy)) ? 'disabled ' : '') + 'input-group time'}>
+ <div data-headline='Arrivée à'>
+ <span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false) ? 'disabled ' : '') + 'input-group time'}>
<input
type='number'
min='00'
max='23'
className='form-control'
- disabled={(this.props.value.deletable && (!vj.dummy))}
+ disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)}
onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', false, false)}}
value={vj.arrival_time['hour']}
/>
@@ -90,7 +90,7 @@ class VehicleJourney extends Component {
min='00'
max='59'
className='form-control'
- disabled={((this.props.value.deletable) && (!vj.dummy))}
+ disabled={((this.isDisabled(this.props.value.deletable), vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)}
onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'minute', false, false)}}
value={vj.arrival_time['minute']}
/>
@@ -102,14 +102,14 @@ class VehicleJourney extends Component {
<span className='sb sb-chrono sb-lg text-warning' data-textinside={vj.delta}></span>
}
</div>
- <div data-headline='Arrivée à'>
- <span className={(this.isDisabled(this.props.value.deletable, vj.dummy) ? 'disabled ' : '') + 'input-group time'}>
+ <div data-headline='Départ à'>
+ <span className={((this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false) ? 'disabled ' : '') + 'input-group time'}>
<input
type='number'
min='00'
max='23'
className='form-control'
- disabled={this.isDisabled(this.props.value.deletable, vj.dummy)}
+ disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)}
onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, 'hour', true, this.props.filters.toggleArrivals)}}
value={vj.departure_time['hour']}
/>
@@ -119,7 +119,7 @@ class VehicleJourney extends Component {
min='00'
max='59'
className='form-control'
- disabled={this.isDisabled(this.props.value.deletable, vj.dummy)}
+ disabled={(this.isDisabled(this.props.value.deletable, vj.dummy) || this.props.filters.policy['vehicle_journeys.edit'] == false)}
onChange={(e) => {this.props.onUpdateTime(e, i, this.props.index, "minute", true, this.props.filters.toggleArrivals)}}
value={vj.departure_time['minute']}
/>
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CalendarsEditVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CalendarsEditVehicleJourney.js
index 19a5af869..e32c873e6 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CalendarsEditVehicleJourney.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CalendarsEditVehicleJourney.js
@@ -22,15 +22,15 @@ class CalendarsEditVehicleJourney extends Component {
if(this.props.status.fetchSuccess == true) {
return (
<li className='st_action'>
- <a
- href='#'
- className={(actions.getSelected(this.props.vehicleJourneys).length > 0 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'}
+ <button
+ type='button'
+ disabled={(actions.getSelected(this.props.vehicleJourneys).length > 0 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'}
data-toggle='modal'
data-target='#CalendarsEditVehicleJourneyModal'
onClick={() => this.props.onOpenCalendarsEditModal(actions.getSelected(this.props.vehicleJourneys))}
>
<span className='fa fa-calendar'></span>
- </a>
+ </button>
<div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='CalendarsEditVehicleJourneyModal'>
<div className='modal-container'>
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js
index 1a1588f85..1273921e7 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/CreateModal.js
@@ -25,15 +25,15 @@ class CreateModal extends Component {
if(this.props.status.fetchSuccess == true) {
return (
<li className='st_action'>
- <a
- href='#'
- className={((this.props.filters.policy['vehicle_journeys.create']) ? '' : 'disabled')}
+ <button
+ type='button'
+ disabled={((this.props.filters.policy['vehicle_journeys.edit'] == true) ? '' : 'disabled')}
data-toggle='modal'
data-target='#NewVehicleJourneyModal'
onClick={this.props.onOpenCreateModal}
>
<span className='fa fa-plus'></span>
- </a>
+ </button>
<div className={ 'modal fade ' + ((this.props.modal.type == 'create') ? 'in' : '') } id='NewVehicleJourneyModal'>
<div className='modal-container'>
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DeleteVehicleJourneys.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DeleteVehicleJourneys.js
index e2425cc22..c98b794a8 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DeleteVehicleJourneys.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DeleteVehicleJourneys.js
@@ -5,9 +5,9 @@ var actions = require('../../actions')
const DeleteVehicleJourneys = ({onDeleteVehicleJourneys, vehicleJourneys, filters}) => {
return (
<li className='st_action'>
- <a
- href='#'
- className={(actions.getSelected(vehicleJourneys).length > 0 && filters.policy['vehicle_journeys.destroy']) ? '' : 'disabled'}
+ <button
+ type='button'
+ disabled={(actions.getSelected(vehicleJourneys).length > 0 && filters.policy['vehicle_journeys.destroy']) ? '' : 'disabled'}
onClick={e => {
e.preventDefault()
onDeleteVehicleJourneys()
@@ -15,7 +15,7 @@ const DeleteVehicleJourneys = ({onDeleteVehicleJourneys, vehicleJourneys, filter
title='Supprimer'
>
<span className='fa fa-trash'></span>
- </a>
+ </button>
</li>
)
}
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js
index b0cb1c850..7448aa06e 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/DuplicateVehicleJourney.js
@@ -23,15 +23,15 @@ class DuplicateVehicleJourney extends Component {
if(this.props.status.fetchSuccess == true) {
return (
<li className='st_action'>
- <a
- href='#'
- className={((actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled')}
+ <button
+ type='button'
+ disabled={((actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled')}
data-toggle='modal'
data-target='#DuplicateVehicleJourneyModal'
onClick={this.props.onOpenDuplicateModal}
>
<span className='fa fa-files-o'></span>
- </a>
+ </button>
<div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='DuplicateVehicleJourneyModal'>
<div className='modal-container'>
@@ -68,7 +68,7 @@ class DuplicateVehicleJourney extends Component {
<input
type='number'
ref='additional_time'
- min='0'
+ min='-59'
max='59'
className='form-control'
onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js
index f7726dad9..9a4790051 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/EditVehicleJourney.js
@@ -24,15 +24,15 @@ class EditVehicleJourney extends Component {
if(this.props.status.fetchSuccess == true) {
return (
<li className='st_action'>
- <a
- href='#'
- className={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'}
+ <button
+ type='button'
+ disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'}
data-toggle='modal'
data-target='#EditVehicleJourneyModal'
onClick={() => this.props.onOpenEditModal(actions.getSelected(this.props.vehicleJourneys)[0])}
>
<span className='fa fa-info'></span>
- </a>
+ </button>
<div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='EditVehicleJourneyModal'>
<div className='modal-container'>
@@ -74,22 +74,51 @@ class EditVehicleJourney extends Component {
<div className='row'>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
- <label className='control-label is-required'>Numéro de train</label>
- <input
- type='text'
- ref='published_journey_identifier'
- className='form-control'
- defaultValue={this.props.modal.modalProps.vehicleJourney.published_journey_identifier}
- onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
- required
+ <div className='form-group'>
+ <label className='control-label is-required'>Numéro de train</label>
+ <input
+ type='text'
+ ref='published_journey_identifier'
+ className='form-control'
+ defaultValue={this.props.modal.modalProps.vehicleJourney.published_journey_identifier}
+ onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
+ required
/>
+ </div>
</div>
<div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
- <label className='control-label'>Transporteur</label>
+ <div className='form-group'>
+ <label className='control-label'>Transporteur</label>
<CompanySelect2
company = {this.props.modal.modalProps.vehicleJourney.company}
onSelect2Company = {(e) => this.props.onSelect2Company(e)}
/>
+ </div>
+ </div>
+ </div>
+
+ <div className='row'>
+ <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
+ <div className='form-group'>
+ <label className='control-label'>Mode de transport</label>
+ <input
+ type='text'
+ className='form-control'
+ value={(this.props.modal.modalProps.vehicleJourney.transport_mode || 'non renseigné')}
+ disabled={true}
+ />
+ </div>
+ </div>
+ <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
+ <div className='form-group'>
+ <label className='control-label'>Sous mode de transport</label>
+ <input
+ type='text'
+ className='form-control'
+ value={(this.props.modal.modalProps.vehicleJourney.transport_submode || 'non renseigné')}
+ disabled={true}
+ />
+ </div>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js
index 7c5df3333..ca8b2ec7d 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/NotesEditVehicleJourney.js
@@ -44,15 +44,15 @@ class NotesEditVehicleJourney extends Component {
if(this.props.status.fetchSuccess == true) {
return (
<li className='st_action'>
- <a
- href='#'
- className={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'}
+ <button
+ type='button'
+ disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'}
data-toggle='modal'
data-target='#NotesEditVehicleJourneyModal'
onClick={() => this.props.onOpenNotesEditModal(actions.getSelected(this.props.vehicleJourneys)[0])}
>
<span className='fa fa-sticky-note'></span>
- </a>
+ </button>
<div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='NotesEditVehicleJourneyModal'>
<div className='modal-container'>
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js
index a373ed1e5..ee7d01cf5 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/ShiftVehicleJourney.js
@@ -23,15 +23,15 @@ class ShiftVehicleJourney extends Component {
if(this.props.status.fetchSuccess == true) {
return (
<li className='st_action'>
- <a
- href='#'
- className={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'}
+ <button
+ type='button'
+ disabled={(actions.getSelected(this.props.vehicleJourneys).length == 1 && this.props.filters.policy['vehicle_journeys.edit']) ? '' : 'disabled'}
data-toggle='modal'
data-target='#ShiftVehicleJourneyModal'
onClick={this.props.onOpenShiftModal}
>
<span className='sb sb-update-vj'></span>
- </a>
+ </button>
<div className={ 'modal fade ' + ((this.props.modal.type == 'shift') ? 'in' : '') } id='ShiftVehicleJourneyModal'>
<div className='modal-container'>
@@ -54,7 +54,7 @@ class ShiftVehicleJourney extends Component {
<input
type='number'
ref='additional_time'
- min='0'
+ min='-59'
max='59'
className='form-control'
onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js
index 7837cdbff..1f5e5e98f 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/components/tools/select2s/CompanySelect2.js
@@ -6,6 +6,7 @@ var Select2 = require('react-select2')
// get JSON full path
var origin = window.location.origin
var path = window.location.pathname.split('/', 3).join('/')
+var line = window.location.pathname.split('/')[4]
class BSelect4 extends React.Component{
@@ -27,7 +28,7 @@ class BSelect4 extends React.Component{
width: '100%',
placeholder: 'Filtrer par transporteur...',
ajax: {
- url: origin + path + '/companies.json',
+ url: origin + path + '/companies.json' + '?line_id=' + line,
dataType: 'json',
delay: '500',
data: function(params) {
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/containers/SaveVehicleJourneys.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/containers/SaveVehicleJourneys.js
index 5af30ab82..87bbe5353 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/containers/SaveVehicleJourneys.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/containers/SaveVehicleJourneys.js
@@ -7,7 +7,8 @@ const mapStateToProps = (state) => {
return {
vehicleJourneys: state.vehicleJourneys,
page: state.pagination.page,
- status: state.status
+ status: state.status,
+ filters: state.filters
}
}
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/index.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/index.js
index 1b9ff8f41..4c9423c1f 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/index.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/index.js
@@ -21,7 +21,7 @@ if (window.journeyPatternId)
var initialState = {
filters: {
selectedJourneyPatterns : selectedJP,
- policy: perms,
+ policy: window.perms,
toggleArrivals: false,
queryString: '',
query: {
@@ -44,7 +44,7 @@ var initialState = {
timetable: {
comment: ''
},
- withoutSchedule: false
+ withoutSchedule: true
}
},
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/filters.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/filters.js
index 4b67dc4df..cd065e362 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/filters.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/filters.js
@@ -15,14 +15,14 @@ const filters = (state = {}, action) => {
minute: '59'
}
}
- newQuery = _.assign({}, state.query, {interval: interval, journeyPattern: {}, timetable: {}, withoutSchedule: false })
+ newQuery = _.assign({}, state.query, {interval: interval, journeyPattern: {}, timetable: {}, withoutSchedule: true })
return _.assign({}, state, {query: newQuery, queryString: ''})
case 'TOGGLE_WITHOUT_SCHEDULE':
newQuery = _.assign({}, state.query, {withoutSchedule: !state.query.withoutSchedule})
return _.assign({}, state, {query: newQuery})
case 'UPDATE_END_TIME_FILTER':
newInterval = JSON.parse(JSON.stringify(state.query.interval))
- newInterval.end[action.unit] = actions.pad(action.val)
+ newInterval.end[action.unit] = actions.pad(action.val, action.unit)
if(parseInt(newInterval.start.hour + newInterval.start.minute) < parseInt(newInterval.end.hour + newInterval.end.minute)){
newQuery = _.assign({}, state.query, {interval: newInterval})
return _.assign({}, state, {query: newQuery})
@@ -31,7 +31,7 @@ const filters = (state = {}, action) => {
}
case 'UPDATE_START_TIME_FILTER':
newInterval = JSON.parse(JSON.stringify(state.query.interval))
- newInterval.start[action.unit] = actions.pad(action.val)
+ newInterval.start[action.unit] = actions.pad(action.val, action.unit)
if(parseInt(newInterval.start.hour + newInterval.start.minute) < parseInt(newInterval.end.hour + newInterval.end.minute)){
newQuery = _.assign({}, state.query, {interval: newInterval})
return _.assign({}, state, {query: newQuery})
@@ -54,7 +54,8 @@ const filters = (state = {}, action) => {
'q[journey_pattern_id_eq]': state.query.journeyPattern.id || undefined,
'q[time_tables_id_eq]': state.query.timetable.id || undefined,
'q[vehicle_journey_at_stops_departure_time_gteq]': (state.query.interval.start.hour + ':' + state.query.interval.start.minute),
- 'q[vehicle_journey_at_stops_departure_time_lteq]': (state.query.interval.end.hour + ':' + state.query.interval.end.minute)
+ 'q[vehicle_journey_at_stops_departure_time_lteq]': (state.query.interval.end.hour + ':' + state.query.interval.end.minute),
+ 'q[vehicle_journey_without_departure_time]' : state.query.withoutSchedule
}
let queryString = actions.encodeParams(params)
return _.assign({}, state, {queryString: queryString})
diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/vehicleJourneys.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/vehicleJourneys.js
index 5924f5cc7..2db76deae 100644
--- a/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/vehicleJourneys.js
+++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/reducers/vehicleJourneys.js
@@ -47,19 +47,26 @@ const vehicleJourney= (state = {}, action) => {
case 'SHIFT_VEHICLEJOURNEY':
let shiftedArray, shiftedSchedule, shiftedVjas
shiftedArray = state.vehicle_journey_at_stops.map((vjas, i) => {
- shiftedSchedule = {
- departure_time: {
- hour: vjas.departure_time.hour,
- minute: String(parseInt(vjas.departure_time.minute) + parseInt(action.data.additional_time.value))
- },
- arrival_time: {
- hour: vjas.arrival_time.hour,
- minute: String(parseInt(vjas.arrival_time.minute) + parseInt(action.data.additional_time.value))
+ if (!vjas.dummy){
+ shiftedSchedule = {
+ departure_time: {
+ hour: vjas.departure_time.hour,
+ minute: actions.simplePad(parseInt(vjas.departure_time.minute) + parseInt(action.data.additional_time.value))
+ },
+ arrival_time: {
+ hour: vjas.arrival_time.hour,
+ minute: actions.simplePad(parseInt(vjas.arrival_time.minute) + parseInt(action.data.additional_time.value))
+ }
}
+ actions.checkSchedules(shiftedSchedule)
+ shiftedVjas = _.assign({}, state.vehicle_journey_at_stops[i], shiftedSchedule)
+ vjas = _.assign({}, state.vehicle_journey_at_stops[i], shiftedVjas)
+ delete vjas['id']
+ return vjas
+ }else {
+ delete vjas['id']
+ return vjas
}
- actions.checkSchedules(shiftedSchedule)
- shiftedVjas = _.assign({}, state.vehicle_journey_at_stops[i], shiftedSchedule)
- return _.assign({}, state.vehicle_journey_at_stops[i], shiftedVjas)
})
return _.assign({}, state, {vehicle_journey_at_stops: shiftedArray})
case 'UPDATE_TIME':
@@ -71,14 +78,20 @@ const vehicleJourney= (state = {}, action) => {
arrival_time: _.assign({}, vjas.arrival_time)
}
if (action.isDeparture){
- newSchedule.departure_time[action.timeUnit] = actions.pad(action.val)
+ newSchedule.departure_time[action.timeUnit] = actions.pad(action.val, action.timeUnit)
if(!action.isArrivalsToggled)
- newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val)
+ newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val, action.timeUnit)
newSchedule = actions.getDelta(newSchedule)
+ if(newSchedule.delta < 0){
+ return vjas
+ }
return _.assign({}, state.vehicle_journey_at_stops[action.subIndex], {arrival_time: newSchedule.arrival_time, departure_time: newSchedule.departure_time, delta: newSchedule.delta})
}else{
- newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val)
+ newSchedule.arrival_time[action.timeUnit] = actions.pad(action.val, action.timeUnit)
newSchedule = actions.getDelta(newSchedule)
+ if(newSchedule.delta < 0){
+ return vjas
+ }
return _.assign({}, state.vehicle_journey_at_stops[action.subIndex], {arrival_time: newSchedule.arrival_time, departure_time: newSchedule.departure_time, delta: newSchedule.delta})
}
}else{
@@ -160,11 +173,12 @@ const vehicleJourneys = (state = [], action) => {
let dupeVj
let dupes = []
let selectedIndex
+ let val = action.data.additional_time.value
state.map((vj, i) => {
if(vj.selected){
selectedIndex = i
for (i = 0; i< action.data.duplicate_number.value; i++){
- action.data.additional_time.value *= (i + 1)
+ action.data.additional_time.value = val * (i + 1)
dupeVj = vehicleJourney(vj, action)
dupeVj.published_journey_name = dupeVj.published_journey_name + '-' + i
dupeVj.selected = false
diff --git a/app/assets/javascripts/forms.coffee b/app/assets/javascripts/forms.coffee
index 9d884edcd..6b00e9c26 100644
--- a/app/assets/javascripts/forms.coffee
+++ b/app/assets/javascripts/forms.coffee
@@ -30,9 +30,21 @@ isEdge = !isIE && !!window.StyleMedia
if isIE || isEdge
$('.formSubmitr').off()
-$(document).on 'ready page:load', togglableFilter
-$(document).on 'ready page:load', submitMover
-$(document).on 'ready page:load', switchInput
+@colorSelector = ->
+ $('.form-group .dropdown.color_selector').each ->
+ selectedStatus = $(this).children('.dropdown-toggle').children('.fa-circle')
+
+ $(this).on 'click', "input[type='radio']", (e) ->
+ selectedValue = e.currentTarget.value
+ if selectedValue == ''
+ $(selectedStatus).css('color', 'transparent')
+ else
+ $(selectedStatus).css('color', selectedValue)
+
+$(document).on 'turbolinks:load', togglableFilter
+$(document).on 'turbolinks:load', submitMover
+$(document).on 'turbolinks:load', switchInput
+$(document).on 'turbolinks:load', colorSelector
if isIE || isEdge
$(document).on 'click', '.formSubmitr', (e)->
diff --git a/app/assets/javascripts/main_menu.coffee b/app/assets/javascripts/main_menu.coffee
index 9357cff34..2e0cd3470 100644
--- a/app/assets/javascripts/main_menu.coffee
+++ b/app/assets/javascripts/main_menu.coffee
@@ -1,4 +1,4 @@
-$(document).on 'ready page:load', ->
+$(document).on 'turbolinks:load', ->
link = []
ptitleCont = ""
@@ -49,5 +49,6 @@ $(document).on 'ready page:load', ->
$('#main_nav').removeClass 'sticky'
if $('#menu_top').find('.sticky-content').length > 0
- $('.page-action .small').after(link)
+ if !$('.page-action').find('.formSubmitr').length
+ $('.page-action .small').after(link)
$('.sticky-content').remove()
diff --git a/app/assets/javascripts/nav_panels.coffee b/app/assets/javascripts/nav_panels.coffee
index b254b9f94..829db5ad0 100644
--- a/app/assets/javascripts/nav_panels.coffee
+++ b/app/assets/javascripts/nav_panels.coffee
@@ -1,4 +1,4 @@
-$(document).on 'ready page:load', ->
+$(document).on 'turbolinks:load', ->
$('#menu_top [data-panel="toggle"]').on 'click', (e) ->
e.preventDefault()
$(this).siblings().removeClass 'active'
diff --git a/app/assets/javascripts/routing_constraint_zones.coffee b/app/assets/javascripts/routing_constraint_zones.coffee
new file mode 100644
index 000000000..458189b36
--- /dev/null
+++ b/app/assets/javascripts/routing_constraint_zones.coffee
@@ -0,0 +1,27 @@
+fill_stop_points_options = ->
+ stop_point_select = $('#routing_constraint_zone_stop_point_ids')
+ stop_point_select.empty()
+ referential_id = document.location.pathname.match(/\d+/g)[0]
+ line_id = document.location.pathname.match(/\d+/g)[1]
+ route_id = $('#routing_constraint_zone_route_id').val()
+ if errors_on_form()
+ stop_point_ids = eval($('#stop_point_ids').val())
+ $.ajax
+ url: "/referentials/#{referential_id}/lines/#{line_id}/routes/#{route_id}/stop_points"
+ dataType: 'json'
+ success: (data, textStatus, jqXHR) ->
+ for stop_point in data
+ selected = $.inArray(stop_point.id, stop_point_ids) != -1
+ stop_point_select.append "<option value='#{stop_point.id}'" + "#{if selected then ' selected' else ''}" + ">#{stop_point.name}</option>"
+ error: (jqXHR, textStatus, errorThrown) ->
+ console.log textStatus
+ console.log errorThrown
+
+errors_on_form = ->
+ document.location.pathname.endsWith('routing_constraint_zones') && $('#new_routing_constraint_zone').length
+
+$(document).on 'turbolinks:load', ->
+ if document.location.pathname.endsWith('new') || errors_on_form()
+ fill_stop_points_options()
+ $('#routing_constraint_zone_route_id').change(fill_stop_points_options)
+
diff --git a/app/assets/javascripts/select2.coffee b/app/assets/javascripts/select2.coffee
index edd4c476d..1870f7f9a 100644
--- a/app/assets/javascripts/select2.coffee
+++ b/app/assets/javascripts/select2.coffee
@@ -7,5 +7,13 @@
placeholder: target.data('select2ed-placeholder')
allowClear: true
+ $('select.form-control.tags').each ->
+ target = $(this)
+ target.select2
+ theme: 'bootstrap'
+ language: 'fr'
+ allowClear: true
+ tags: true
+
-$(document).on 'ready page:load', select_2
+$(document).on 'turbolinks:load', select_2
diff --git a/app/assets/javascripts/selectable_table.coffee b/app/assets/javascripts/selectable_table.coffee
index 4d9f5122a..4086bf6c2 100644
--- a/app/assets/javascripts/selectable_table.coffee
+++ b/app/assets/javascripts/selectable_table.coffee
@@ -53,4 +53,4 @@
.addClass 'noselect'
.children('.info-msg').children('span').text(selection.length)
-$(document).on 'ready page:load', selectTable
+$(document).on 'turbolinks:load', selectTable
diff --git a/app/assets/stylesheets/application.sass b/app/assets/stylesheets/application.sass
index e4a2a5445..47cccba65 100644
--- a/app/assets/stylesheets/application.sass
+++ b/app/assets/stylesheets/application.sass
@@ -15,3 +15,4 @@
@import 'modules/routes_stopoints'
@import 'modules/jp_collection'
@import 'modules/vj_collection'
+@import 'modules/timetables'
diff --git a/app/assets/stylesheets/base/_config.sass b/app/assets/stylesheets/base/_config.sass
index ae8b386e6..65444479f 100644
--- a/app/assets/stylesheets/base/_config.sass
+++ b/app/assets/stylesheets/base/_config.sass
@@ -21,3 +21,4 @@ $green: #70b12b
$red: #da2f36
$orange: #ed7f00
+$gold: #ffcc00
diff --git a/app/assets/stylesheets/components/_buttons.sass b/app/assets/stylesheets/components/_buttons.sass
index 00551f7cb..fd3561dc8 100644
--- a/app/assets/stylesheets/components/_buttons.sass
+++ b/app/assets/stylesheets/components/_buttons.sass
@@ -5,15 +5,45 @@
.btn
font-weight: 700
- .fa + span
+ .fa + span:not(.caret)
padding-left: 0.5em
span + .fa
padding-left: 0.5em
- &.btn-link
+ &.btn-link, &.btn-circle
&, &:focus
outline: none
+ &.btn-circle
+ position: relative
+ top: 50%
+ transform: translateY(-50%)
+ border: 1px solid $blue
+ background-color: transparent
+ width: 22px
+ height: 22px
+ line-height: 22px
+ text-align: center
+ border-radius: 50%
+ padding: 0
+ color: $grey
+
+ > .fa
+ display: block
+ line-height: 20px
+
+ &[data-actiontype='add']
+ &:hover, &.active
+ border-color: $green
+ background-color: $green
+ color: #fff
+
+ &[data-actiontype='remove']
+ &:hover, &.active
+ border-color: $red
+ background-color: $red
+ color: #fff
+
&.btn-default
background-color: #fff
border-color: rgba(#fff, 0.5)
@@ -113,12 +143,12 @@ table, .table
border-radius: 0
box-shadow: 0 0 3px rgba($darkgrey, 0.25)
- > li > a
+ > li > a, > li > button
padding: 5px 15px
> li.delete-action
-
- > a
+ > a, > button
+ display: block
position: relative
margin-top: 11px
diff --git a/app/assets/stylesheets/components/_calendar.sass b/app/assets/stylesheets/components/_calendar.sass
new file mode 100644
index 000000000..c3d93d325
--- /dev/null
+++ b/app/assets/stylesheets/components/_calendar.sass
@@ -0,0 +1,73 @@
+//-----------//
+// CALENDARS //
+//-----------//
+
+table.calendar
+ display: table
+ width: 100%
+ table-layout: fixed
+ margin-bottom: 20px
+
+ th, td
+ border: 1px solid $darkgrey
+ text-align: center
+ padding: 0.35em 0.5em
+
+ th
+ padding: 0.5em
+
+ thead
+ tr
+ > th
+ border: none
+
+ &:first-child
+ text-transform: uppercase
+
+ tbody
+ tr > td
+ &.weekNumber
+ border: none
+ padding: 0.5em 0.5em 0.5em 0
+
+ &.outsideMonth
+ color: rgba($darkgrey, 0.35)
+
+ &.weekend
+ font-weight: bold
+
+ &.selected_period, &.selected_date, &.overlaped_date
+ > a
+ display: block
+ margin: 0 auto
+ width: 24px
+ height: 24px
+ line-height: 24px
+ color: $darkgrey
+ background-color: rgba($gold, 0.75)
+ border-radius: 50%
+
+ &:hover, &:focus
+ color: $darkgrey
+ text-decoration: none
+
+.col-xs-6
+ &:nth-child(2n +1)
+ clear: both
+
+.col-sm-4
+ @media (min-width: 768px)
+ &:nth-child(2n +1)
+ clear: none
+ &:nth-child(3n+1)
+ clear: both
+
+// .col-md-4
+// @media (min-width: 992px)
+
+.col-lg-3
+ @media (min-width: 1200px)
+ &:nth-child(2n +1), &:nth-child(3n+1)
+ clear: none
+ &:nth-child(4n+1)
+ clear: both
diff --git a/app/assets/stylesheets/components/_dropdown.sass b/app/assets/stylesheets/components/_dropdown.sass
index ee26aaeb5..99dc6292e 100644
--- a/app/assets/stylesheets/components/_dropdown.sass
+++ b/app/assets/stylesheets/components/_dropdown.sass
@@ -3,6 +3,22 @@
//-------------//
.dropdown-menu
- > .disabled > a
+ > li > button
+ display: block
+ width: 100%
+ text-align: left
+ border: none
+ background-color: transparent
+ color: #333
+
+ &:hover, &:focus
+ color: #262626
+ background-color: whitesmoke
+ outline: none
+
+ > .disabled > a, > .disabled > button
+ cursor: not-allowed
&, &:hover, &:focus
color: rgba($darkgrey, 0.5)
+ background-color: transparent
+ outline: none
diff --git a/app/assets/stylesheets/components/_forms.sass b/app/assets/stylesheets/components/_forms.sass
index 3b7a135d5..8419c2345 100644
--- a/app/assets/stylesheets/components/_forms.sass
+++ b/app/assets/stylesheets/components/_forms.sass
@@ -77,6 +77,57 @@ input
border-color: #4cae4c
box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px #5cb85c
+// BS horizontal form label positionning fix
+.form-horizontal
+ .form-group
+ position: relative
+
+ > .control-label
+ &[class*='col-sm-']
+ float: none
+ padding-top: 0
+ position: absolute
+ left: 0
+ right: 0
+ top: 50%
+ transform: translateY(-50%)
+
+ + [class*='col-sm-']
+ float: right
+
+// Colors dropdown
+.dropdown.color_selector
+ .btn.btn-default
+ &, &:hover, &:focus
+ border: 1px solid #cccccc
+ background-color: #fff
+ font-weight: normal
+ color: $darkgrey
+
+ .dropdown-menu
+ position: absolute
+ margin: 2px 0 0 0
+ min-width: 56px
+
+ > .radio
+ position: relative
+ padding: 3px 20px
+ // cursor: pointer
+
+ &:hover, &:focus
+ background-color: #f5f5f5
+
+ > label
+ padding: 0
+
+ input.color_selector, input[type='radio']
+ position: absolute
+ cursor: pointer
+ z-index: 1
+ width: 100%
+ margin: 0
+ opacity: 0
+
// Search bar
.search_bar
position: relative
@@ -646,6 +697,59 @@ table, .table
.control-label.time
min-width: 60px
+// Form group checkboxes
+$grp-cbx-size: 34px
+.form-group.labelled-checkbox-group
+ margin: 0
+
+ > .lcbx-group-item
+ display: inline-block
+ margin: 0 5px
+
+ &:first-child
+ margin-left: 0
+
+ > .checkbox
+ display: block
+ width: $grp-cbx-size
+ height: $grp-cbx-size
+ line-height: $grp-cbx-size
+ margin: 0
+ padding: 0
+
+ > label
+ position: relative
+ min-height: 0
+ padding: 0
+ margin: 0
+
+ > input
+ &[type='checkbox']:not(:checked), &[type='checkbox']:checked
+ position: absolute
+ left: -9999px
+ margin: 0
+
+ + .lcbx-group-item-label
+ position: relative
+ cursor: pointer
+ font-weight: bold
+ display: inline-block
+ vertical-align: top
+ width: $grp-cbx-size
+ height: $grp-cbx-size
+ line-height: $grp-cbx-size - 2px
+ text-align: center
+ margin: 0
+ background-color: rgba($grey, 0.15)
+ color: rgba($grey, 0.5)
+ border: 1px solid rgba($grey, 0.5)
+ border-radius: 3px
+
+ &[type='checkbox']:checked + .lcbx-group-item-label
+ background-color: $blue
+ border-color: $blue
+ color: #fff
+
// Nested fields
.nested-fields
margin: 0
@@ -727,7 +831,7 @@ table, .table
margin: 0
padding: 0 5px
- + .nested-fields
+ + .nested-fields, + .links.nested-linker
border-top: 2px solid $darkgrey
.wrapper
diff --git a/app/assets/stylesheets/components/_labels.sass b/app/assets/stylesheets/components/_labels.sass
index 3514bce81..9607a97b8 100644
--- a/app/assets/stylesheets/components/_labels.sass
+++ b/app/assets/stylesheets/components/_labels.sass
@@ -8,7 +8,15 @@
font-weight: inherit
padding: 0.35em 0.4em
border-radius: 2px
+ border: 1px solid
+
+ + .label
+ margin-left: 0.5em
&.label-default
- background-color: rgba(#fff, 0.3)
- color: #fff
+ background-color: #fff
+ color: $darkgrey
+ border-color: rgba($grey, 0.5)
+
+ &.disabled
+ color: rgba($grey, 0.5)
diff --git a/app/assets/stylesheets/components/_select2.sass b/app/assets/stylesheets/components/_select2.sass
index 5e3741bf0..cbb3a80da 100644
--- a/app/assets/stylesheets/components/_select2.sass
+++ b/app/assets/stylesheets/components/_select2.sass
@@ -50,9 +50,19 @@
.form-filter
.form-group.select2ed
- .select2-container--bootstrap .select2-selection--single
- height: 31px
- padding: 4px 24px 5px 12px
+ .select2-container--bootstrap
+ .select2-selection--single, .select2-selection--multiple
+ height: 31px
+ padding: 0px 3px 4px 6px
+
+ .select2-selection--single
+ line-height: 31px
+
+ .select2-selection--multiple
+ min-height: 31px
+
+ .select2-search--inline .select2-search__field
+ height: 28px
.select2-container--bootstrap .select2-selection
border-color: rgba($grey, 0.3)
diff --git a/app/assets/stylesheets/components/_tables.sass b/app/assets/stylesheets/components/_tables.sass
index ade9bacf4..bc04b49e3 100644
--- a/app/assets/stylesheets/components/_tables.sass
+++ b/app/assets/stylesheets/components/_tables.sass
@@ -118,13 +118,15 @@
height: 35px
margin: 5px
- > a
+ > a, > button
display: block
height: 35px
+ width: 100%
text-align: center
line-height: 35px
border-radius: 50%
background-color: $blue
+ border: none
color: #fff
&:focus
@@ -139,7 +141,7 @@
&:hover
background-color: darken($red, 5%)
- &.disabled
+ &.disabled, &:disabled
&, &[title='Supprimer'], &:hover, &:focus
background-color: rgba($grey, 0.3)
cursor: not-allowed
@@ -262,3 +264,11 @@
&.disabled
color: rgba($darkgrey, 0.5)
background-color: rgba(#fff, 0.5)
+
+ // TD group
+ > .td-group
+ display: inline-block
+ vertical-align: top
+
+ > .td
+ display: block
diff --git a/app/assets/stylesheets/main/time_tables.sass b/app/assets/stylesheets/main/time_tables.sass
index de2ae8253..6918bec1e 100644
--- a/app/assets/stylesheets/main/time_tables.sass
+++ b/app/assets/stylesheets/main/time_tables.sass
@@ -28,13 +28,13 @@
z-index: 100001
.validity_out
- color: $brand-danger
+ color: red
.validity_out_soon
- color: $brand-warning
+ color: orange
.validity_regular
- color: $brand-success
+ color: green
span.included_day_type
font-weight: bolder
diff --git a/app/assets/stylesheets/modules/_jp_collection.sass b/app/assets/stylesheets/modules/_jp_collection.sass
index eff1e2abc..d1f864e5c 100644
--- a/app/assets/stylesheets/modules/_jp_collection.sass
+++ b/app/assets/stylesheets/modules/_jp_collection.sass
@@ -78,3 +78,7 @@
&:after
bottom: -6px
+
+ .t2e-head > .td:last-child > div > span
+ &:after
+ bottom: 50%
diff --git a/app/assets/stylesheets/modules/_timetables.sass b/app/assets/stylesheets/modules/_timetables.sass
new file mode 100644
index 000000000..27188060f
--- /dev/null
+++ b/app/assets/stylesheets/modules/_timetables.sass
@@ -0,0 +1,195 @@
+//---------------//
+// Time Tables //
+//---------------//
+
+#periods
+ .t2e-head
+ > .th
+ height: 135px
+ text-align: left
+ border-color: $darkgrey
+ border-top-width: 2px
+
+ > .strong
+ padding-top: 123px
+ transform: translateY(-1.4em)
+
+ .t2e-head > .td, .t2e-item > .td-group > .td
+ height: 65px
+
+ .t2e-head > .td
+ line-height: 50px
+
+ > span
+ display: inline-block
+ vertical-align: middle
+ line-height: 1.4
+
+ .t2e-item-list > div
+ border-color: #fff
+
+ .t2e-item
+ .th
+ padding: 6px 0 0 0
+ border-color: $darkgrey
+ border-top-width: 2px
+
+ > .monthName
+ padding: 0 0 6px 8px
+
+ .monthDays
+ white-space: nowrap
+
+ .day
+ display: inline-block
+ width: 40px
+ padding: 20px 0 6px 0
+
+ &.last_wday
+ &:not(:last-child)
+ border-right: 2px solid
+
+ &:before
+ content: attr(data-wday)
+ display: block
+ text-align: left
+ color: rgba($grey, 0.5)
+ padding-bottom: 10px
+
+ .dayname
+ display: block
+ text-align: center
+ text-transform: capitalize
+ padding-bottom: 2px
+
+ .daynumber
+ display: block
+ margin: 0 auto
+ width: 24px
+ height: 24px
+ line-height: 24px
+ text-align: center
+ font-weight: bold
+ border-radius: 50%
+ background-color: transparent
+
+ &.included
+ background-color: rgba($gold, 0.75)
+
+ > .td-group
+ width: 40px
+ > .td
+ border-right: 1px solid rgba($grey, 0.5)
+
+ &.last_wday
+ &:not(:last-child) > .td
+ border-right: 2px solid $darkgrey
+
+ &.out_from_daytypes
+ background-image: linear-gradient(45deg, rgba($grey, 0.15) 0%, rgba($grey, 0.15) 49%, rgba($grey, 0.5) 50%, rgba($grey, 0.15) 51%, rgba($grey, 0.15) 99%, rgba($grey, 0.15) 100%)
+ background-size: 25px 25px
+
+ > .td
+ &.in_periods
+ background-color: rgba($gold, 0.5)
+ border-left-color: rgba($gold, 0.5)
+ border-right-color: rgba($gold, 0.5)
+
+ &.start_period
+ border-left-color: rgba($grey, 0.5)
+ &.end_period
+ border-right-color: rgba($grey, 0.5)
+
+ .form-group > .month_selector
+ > .btn.btn-default
+ background-color: rgba($grey, 0.15)
+ color: $darkgrey
+ border: none
+ border-radius: 0
+ padding: 8px 15px 7px 15px
+
+ &:active, &.active
+ box-shadow: none
+
+ > .caret
+ margin-left: 10px
+ color: $blue
+
+ > .dropdown-menu
+ margin-top: 1px
+ border-radius: 0 0 4px 4px
+ max-height: 230px
+ overflow: auto
+
+ .period_manager
+ display: block
+ height: auto
+ word-wrap: normal
+ white-space: nowrap
+ position: absolute
+ left: 8px
+ top: 50%
+ transform: translateY(-50%)
+ z-index: 5
+
+ > *
+ display: inline-block
+ vertical-align: middle
+ margin: 0
+
+ &.dropdown
+ margin-left: 5px
+
+ .btn.dropdown-toggle
+ color: $blue
+ background-color: rgba(#fff, 0)
+ padding: 1px 5px
+ border-radius: 0
+ transition: 0.2s
+
+ &:hover, &:focus, &:active, &.active
+ background-color: rgba(#fff, 1)
+ border-color: $blue
+ outline: none
+ box-shadow: none
+ transition: 0.2s
+
+ .open > .btn.dropdown-toggle
+ background-color: rgba(#fff, 1)
+ border-color: $blue
+ box-shadow: none
+ transition: 0.2s
+
+ .dropdown-menu
+ margin: 0
+ border-radius: 0
+ box-shadow: 0 0 3px rgba($darkgrey, 0.25)
+ min-width: 120px
+
+ > li > a, > li > button
+ padding: 5px 15px
+
+ > li.delete-action
+ > a, > button
+ display: block
+ position: relative
+ margin-top: 11px
+
+ &:before
+ content: ''
+ display: block
+ position: absolute
+ left: 15px
+ right: 15px
+ top: -6px
+ height: 1px
+ background-color: $grey
+
+ .fa:first-child
+ margin-right: 0.5em
+
+ .td-group.last_wday ~ .td-group.last_wday ~ .td-group.last_wday ~ .td-group.last_wday
+ > .td, ~ .td-group > .td
+ > .period_manager .dropdown-menu
+ left: auto
+ right: 0
diff --git a/app/assets/stylesheets/typography/_fonts.sass b/app/assets/stylesheets/typography/_fonts.sass
index 0bb0fd2db..0cc387d74 100644
--- a/app/assets/stylesheets/typography/_fonts.sass
+++ b/app/assets/stylesheets/typography/_fonts.sass
@@ -35,6 +35,6 @@
//-- sBoiv --//
@font-face
font-family: 'sboiv'
- src: url(asset-path('sBoiv/sboiv.woff?5l6pxj')) format('woff'), url(asset-path('sBoiv/sboiv.ttf?5l6pxj')) format('ttf')
+ src: url(asset-path('sBoiv/sboiv.woff?vhxdui')) format('woff'), url(asset-path('sBoiv/sboiv.ttf?vhxdui')) format('ttf')
font-weight: normal
font-style: normal
diff --git a/app/assets/stylesheets/typography/_sboiv.sass b/app/assets/stylesheets/typography/_sboiv.sass
index cd3af8ab7..1f89bad74 100644
--- a/app/assets/stylesheets/typography/_sboiv.sass
+++ b/app/assets/stylesheets/typography/_sboiv.sass
@@ -18,6 +18,8 @@
&[data-textinside]
position: relative
+ // width: 1em
+ // height: 1em
&:after
content: attr(data-textinside)
font-family: $base-font-family
@@ -50,6 +52,7 @@
&.sb-5x
font-size: 5em
+
.sb-update-vj:before
content: '\e900'
@@ -58,3 +61,6 @@
.sb-current-ref:before
content: '\e902'
+
+.sb-chrono:before
+ content: '\e903'
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index c2414f5bb..2bdf8078a 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -15,6 +15,10 @@ class ApplicationController < ActionController::Base
I18n.locale = session[:language] || I18n.default_locale
end
+ def pundit_user
+ UserContext.new(current_user, referential: self.try(:current_referential))
+ end
+
protected
def user_not_authorized
diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb
index c68a60804..accf119a3 100644
--- a/app/controllers/errors_controller.rb
+++ b/app/controllers/errors_controller.rb
@@ -1,9 +1,14 @@
class ErrorsController < ApplicationController
def not_found
- render :status => 404, :formats => [:html]
+ render template: 'errors/not_found', status: 404, formats: [:html]
end
def server_error
- render :status => 500, :formats => [:html]
+ render template: 'errors/server_error', status: 500, formats: [:html]
end
-end \ No newline at end of file
+
+ def not_allowed
+ render template: 'errors/not_found', status: 403, formats: [:html]
+ end
+end
+
diff --git a/app/controllers/journey_patterns_collections_controller.rb b/app/controllers/journey_patterns_collections_controller.rb
index 51cc48c2a..ba54ddf26 100644
--- a/app/controllers/journey_patterns_collections_controller.rb
+++ b/app/controllers/journey_patterns_collections_controller.rb
@@ -1,6 +1,7 @@
class JourneyPatternsCollectionsController < ChouetteController
respond_to :html
respond_to :json
+ before_action :user_permissions, only: :show
belongs_to :referential do
belongs_to :line, :parent_class => Chouette::Line do
@@ -41,6 +42,14 @@ class JourneyPatternsCollectionsController < ChouetteController
@stop_points_list = @stop_points_list.sort_by {|a| a[:position] }
end
+ def user_permissions
+ @perms = {}.tap do |perm|
+ ['journey_patterns.create', 'journey_patterns.edit', 'journey_patterns.destroy'].each do |name|
+ perm[name] = policy(:journey_pattern).send("#{name.split('.').last}?")
+ end
+ end.to_json
+ end
+
def update
state = JSON.parse request.raw_post
Chouette::JourneyPattern.state_update route, state
diff --git a/app/controllers/line_footnotes_controller.rb b/app/controllers/line_footnotes_controller.rb
index 7bc048731..c42aa785b 100644
--- a/app/controllers/line_footnotes_controller.rb
+++ b/app/controllers/line_footnotes_controller.rb
@@ -1,7 +1,6 @@
class LineFootnotesController < BreadcrumbController
defaults :resource_class => Chouette::Line
include PolicyChecker
- before_action :check_policy, only: [:edit, :update, :destroy]
respond_to :json, :only => :show
belongs_to :referential
@@ -27,7 +26,6 @@ class LineFootnotesController < BreadcrumbController
end
protected
-
# overrides default
def check_policy
authorize resource, "#{action_name}_footnote?".to_sym
diff --git a/app/controllers/referential_companies_controller.rb b/app/controllers/referential_companies_controller.rb
index 0966389b4..e8b104d14 100644
--- a/app/controllers/referential_companies_controller.rb
+++ b/app/controllers/referential_companies_controller.rb
@@ -27,7 +27,12 @@ class ReferentialCompaniesController < ChouetteController
end
def collection
- @q = referential.workbench.companies.search(params[:q])
+ scope = referential.line_referential.companies
+ if params[:line_id]
+ scope = referential.line_referential.lines.find(params[:line_id]).companies
+ end
+
+ @q = scope.search(params[:q])
if sort_column && sort_direction
@companies ||= @q.result(:distinct => true).order(sort_column + ' ' + sort_direction).paginate(:page => params[:page])
diff --git a/app/controllers/referentials_controller.rb b/app/controllers/referentials_controller.rb
index ce875b6ba..f46cd188d 100644
--- a/app/controllers/referentials_controller.rb
+++ b/app/controllers/referentials_controller.rb
@@ -1,7 +1,7 @@
class ReferentialsController < BreadcrumbController
defaults :resource_class => Referential
include PolicyChecker
- before_action :check_policy, :only => [:edit, :update, :archive, :unarchive] # overrides default
+ before_action :check_policy, :only => [:edit, :update, :destroy, :archive, :unarchive] # overrides default
respond_to :html
respond_to :json, :only => :show
diff --git a/app/controllers/route_stop_points_controller.rb b/app/controllers/route_stop_points_controller.rb
new file mode 100644
index 000000000..e12acb33b
--- /dev/null
+++ b/app/controllers/route_stop_points_controller.rb
@@ -0,0 +1,18 @@
+class RouteStopPointsController < ChouetteController
+ defaults resource_class: Chouette::StopPoint
+ actions :index
+ respond_to :json, only: :index
+
+ belongs_to :referential do
+ belongs_to :line, :parent_class => Chouette::Line do
+ belongs_to :route, :parent_class => Chouette::Route
+ end
+ end
+
+ def index
+ respond_to do |format|
+ format.json { render json: referential.lines.find(params[:line_id]).routes.find(params[:route_id]).stop_points.map { |sp| { id: sp.id, name: sp.name } } }
+ end
+ end
+end
+
diff --git a/app/controllers/routing_constraint_zones_controller.rb b/app/controllers/routing_constraint_zones_controller.rb
index c39c50326..f2f74e801 100644
--- a/app/controllers/routing_constraint_zones_controller.rb
+++ b/app/controllers/routing_constraint_zones_controller.rb
@@ -3,6 +3,8 @@ class RoutingConstraintZonesController < ChouetteController
respond_to :html, :xml, :json
+ before_action :remove_empty_stop_point, only: [:create, :update]
+
belongs_to :referential do
belongs_to :line, parent_class: Chouette::Line
end
@@ -11,7 +13,10 @@ class RoutingConstraintZonesController < ChouetteController
private
def routing_constraint_zone_params
- params.require(:routing_constraint_zone).permit(:name, { stop_area_ids: [] }, :line_id, :objectid, :object_version, :creator_id)
+ params.require(:routing_constraint_zone).permit(:name, { stop_point_ids: [] }, :line_id, :route_id, :objectid, :object_version, :creator_id)
end
+ def remove_empty_stop_point
+ params.require(:routing_constraint_zone)[:stop_point_ids].delete('')
+ end
end
diff --git a/app/controllers/time_tables_controller.rb b/app/controllers/time_tables_controller.rb
index bdde5d3ab..eedfef07c 100644
--- a/app/controllers/time_tables_controller.rb
+++ b/app/controllers/time_tables_controller.rb
@@ -18,6 +18,11 @@ class TimeTablesController < ChouetteController
end
end
+ def month
+ @date = params['date'] ? Date.parse(params['date']) : Date.today
+ @time_table = resource
+ end
+
def new
@autocomplete_items = ActsAsTaggableOn::Tag.all
new! do
@@ -88,19 +93,25 @@ class TimeTablesController < ChouetteController
protected
def collection
- ransack_params = params[:q]
- # Hack to delete params can't be used by ransack
- tag_search = ransack_params["tag_search"].split(",").collect(&:strip) if ransack_params.present? && ransack_params["tag_search"].present?
- ransack_params.delete("tag_search") if ransack_params.present?
+ scope = select_time_tables
+ if params[:q] && params[:q]["tag_search"]
+ tags = params[:q]["tag_search"].reject {|c| c.empty?}
+ params[:q].delete("tag_search")
+ scope = select_time_tables.tagged_with(tags, :wild => true, :any => true) if tags.any?
+ end
- selected_time_tables = tag_search ? select_time_tables.tagged_with(tag_search, :wild => true, :any => true) : select_time_tables
- @q = selected_time_tables.search(ransack_params)
- @time_tables ||= @q.result(:distinct => true).order(:comment).paginate(:page => params[:page])
+ @q = scope.search(params[:q])
+ if sort_column && sort_direction
+ @time_tables ||= @q.result(:distinct => true).order("#{sort_column} #{sort_direction}")
+ else
+ @time_tables ||= @q.result(:distinct => true).order(:comment)
+ end
+ @time_tables = @time_tables.paginate(page: params[:page], per_page: 10)
end
def select_time_tables
if params[:route_id]
- referential.time_tables.joins( vehicle_journeys: :route).where( "routes.id IN (#{params[:route_id]})")
+ referential.time_tables.joins(vehicle_journeys: :route).where( "routes.id IN (#{params[:route_id]})")
else
referential.time_tables
end
@@ -115,8 +126,34 @@ class TimeTablesController < ChouetteController
end
private
+ def sort_column
+ referential.time_tables.column_names.include?(params[:sort]) ? params[:sort] : 'comment'
+ end
+ def sort_direction
+ %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
+ end
def time_table_params
- params.require(:time_table).permit( :objectid, :object_version, :creator_id, :calendar_id, :version, :comment, :int_day_types, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday, :start_date, :end_date, { :dates_attributes => [:date, :in_out, :id, :_destroy] }, { :periods_attributes => [:period_start, :period_end, :_destroy, :id] }, :tag_list, :tag_search )
+ params.require(:time_table).permit(
+ :objectid,
+ :object_version,
+ :creator_id,
+ :calendar_id,
+ :version, :comment, :color,
+ :int_day_types,
+ :monday,
+ :tuesday,
+ :wednesday,
+ :thursday,
+ :friday,
+ :saturday,
+ :sunday,
+ :start_date,
+ :end_date,
+ { :dates_attributes => [:date, :in_out, :id, :_destroy] },
+ { :periods_attributes => [:period_start, :period_end, :_destroy, :id] },
+ {tag_list: []},
+ :tag_search
+ )
end
end
diff --git a/app/controllers/vehicle_journeys_controller.rb b/app/controllers/vehicle_journeys_controller.rb
index 5199d8632..c084b592a 100644
--- a/app/controllers/vehicle_journeys_controller.rb
+++ b/app/controllers/vehicle_journeys_controller.rb
@@ -1,8 +1,6 @@
class VehicleJourneysController < ChouetteController
defaults :resource_class => Chouette::VehicleJourney
- before_action :check_policy, only: [:edit, :update, :destroy]
before_action :user_permissions, only: :index
- before_action :ransack_params, only: :index
respond_to :json, :only => :index
respond_to :js, :only => [:select_journey_pattern, :edit, :new, :index]
@@ -61,8 +59,7 @@ class VehicleJourneysController < ChouetteController
}
end
- @jp_origin = Chouette::JourneyPattern.find_by(objectid: params[:jp])
-
+ @jp_origin = Chouette::JourneyPattern.find_by(objectid: params[:jp])
index! do
if collection.out_of_bounds?
@@ -80,14 +77,39 @@ class VehicleJourneysController < ChouetteController
protected
def collection
+ scope = route.vehicle_journeys.joins(:journey_pattern).joins('LEFT JOIN "vehicle_journey_at_stops" ON "vehicle_journey_at_stops"."vehicle_journey_id" = "vehicle_journeys"."id"')
+
+ @q = scope.search filtered_ransack_params
+ grouping = ransack_periode_filter
+ @q.build_grouping(grouping) if grouping
+
@ppage = 20
- @q = route.sorted_vehicle_journeys('vehicle_journeys').search params[:q]
- @vehicle_journeys = @q.result.paginate(:page => params[:page], :per_page => @ppage)
+ @vehicle_journeys = @q.result(distinct: true).paginate(:page => params[:page], :per_page => @ppage)
@footnotes = route.line.footnotes.to_json
@matrix = resource_class.matrix(@vehicle_journeys)
@vehicle_journeys
end
+ def ransack_periode_filter
+ if params[:q] && params[:q][:vehicle_journey_at_stops_departure_time_gteq]
+ params[:q] = params[:q].reject{|k| params[:q][k] == 'undefined'}
+ between = [:departure_time_gteq, :departure_time_lteq].map do |filter|
+ "2000-01-01 #{params[:q]["vehicle_journey_at_stops_#{filter}"]}:00 UTC"
+ end
+ {
+ :m => 'or',
+ :vehicle_journey_at_stops_departure_time_between => between.join(' to '),
+ :vehicle_journey_at_stops_id_null => params[:q][:vehicle_journey_without_departure_time]
+ }
+ end
+ end
+
+ def filtered_ransack_params
+ if params[:q]
+ params[:q].except(:vehicle_journey_at_stops_departure_time_gteq, :vehicle_journey_at_stops_departure_time_lteq)
+ end
+ end
+
def adapted_params
params.tap do |adapted_params|
adapted_params.merge!( :route => parent)
@@ -107,30 +129,15 @@ class VehicleJourneysController < ChouetteController
@matrix = resource_class.matrix(@vehicle_journeys)
end
- def check_policy
- authorize resource
- end
-
def user_permissions
@perms = {}.tap do |perm|
['vehicle_journeys.create', 'vehicle_journeys.edit', 'vehicle_journeys.destroy'].each do |name|
- perm[name] = current_user.permissions.include?(name)
+ perm[name] = policy(:vehicle_journey).send("#{name.split('.').last}?")
end
- end
- @perms = @perms.to_json
+ end.to_json
end
private
- def ransack_params
- if params[:q]
- params[:q] = params[:q].reject{|k| params[:q][k] == 'undefined'}
- [:departure_time_gteq, :departure_time_lteq].each do |filter|
- time = params[:q]["vehicle_journey_at_stops_#{filter}"]
- params[:q]["vehicle_journey_at_stops_#{filter}"] = "2000-01-01 #{time}:00 UTC"
- end
- end
- end
-
def vehicle_journey_params
params.require(:vehicle_journey).permit( { footnote_ids: [] } , :journey_pattern_id, :number, :published_journey_name,
:published_journey_identifier, :comment, :transport_mode,
diff --git a/app/controllers/workbenches_controller.rb b/app/controllers/workbenches_controller.rb
index 1424fe03c..d621a28d7 100644
--- a/app/controllers/workbenches_controller.rb
+++ b/app/controllers/workbenches_controller.rb
@@ -37,10 +37,11 @@ class WorkbenchesController < BreadcrumbController
end
def sort_result collection
- col = (Workbench.find(params[:id]).referentials.column_names + %w{lines}).include?(params[:sort]) ? params[:sort] : 'name'
+ col = (Workbench.find(params[:id]).referentials.column_names + %w{lines validity_period}).include?(params[:sort]) ? params[:sort] : 'name'
dir = %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
- if col == "lines"
- collection.joins(:metadatas).group("referentials.id").order("sum(array_length(referential_metadata.line_ids,1)) #{dir}")
+
+ if ['lines', 'validity_period'].include?(col)
+ collection.send("order_by_#{col}", dir)
else
collection.order("#{col} #{dir}")
end
diff --git a/app/helpers/access_links_helper.rb b/app/helpers/access_links_helper.rb
new file mode 100644
index 000000000..8df452f65
--- /dev/null
+++ b/app/helpers/access_links_helper.rb
@@ -0,0 +1,7 @@
+module AccessLinksHelper
+ def access_link_type_label_pairs
+ Chouette::AccessLink
+ .access_link_types
+ .zip_map { |type| t("connection_link_types.label.#{type}") }
+ end
+end
diff --git a/app/helpers/access_points_helper.rb b/app/helpers/access_points_helper.rb
index c5e9f672e..c954e6cad 100644
--- a/app/helpers/access_points_helper.rb
+++ b/app/helpers/access_points_helper.rb
@@ -1,28 +1,14 @@
module AccessPointsHelper
- def access_links_pairs(access_links)
- hpairs = Hash.new
- pairs = Array.new
- access_links.each do |link|
- key = pair_key(link)
- pair = nil
- if (hpairs.has_key? key)
- pair = hpairs[key]
- else
- pair = AccessLinkPair.new
- pairs << pair
- hpairs[key] = pair
- end
- if (link.link_orientation_type == "access_point_to_stop_area")
- pair.from_access_point = link
- else
- pair.to_access_point = link
- end
- end
- pairs
+
+
+ def access_point_type_label_pairs
+ Chouette::AccessPoint
+ .access_point_types
+ .zip_map { |access_point_type| t("access_types.label.#{access_point_type}") }
end
-
+
def pair_key(access_link)
"#{access_link.access_point.id}-#{access_link.stop_area.id}"
end
-
+
end
diff --git a/app/helpers/common_helpers.rb b/app/helpers/common_helpers.rb
new file mode 100644
index 000000000..29cabddac
--- /dev/null
+++ b/app/helpers/common_helpers.rb
@@ -0,0 +1,26 @@
+
+module CommonHelpers
+ # TODO: Needs refactoring, but does not seem to be under test
+ # so let us refactor this **after** test coverage.
+ def access_links_pairs(access_links)
+ hpairs = Hash.new
+ pairs = Array.new
+ access_links.each do |link|
+ key = pair_key(link)
+ pair = nil
+ if (hpairs.has_key? key)
+ pair = hpairs[key]
+ else
+ pair = AccessLinkPair.new
+ pairs << pair
+ hpairs[key] = pair
+ end
+ if (link.link_orientation_type == "access_point_to_stop_area")
+ pair.from_access_point = link
+ else
+ pair.to_access_point = link
+ end
+ end
+ pairs
+ end
+end
diff --git a/app/helpers/connection_links_helper.rb b/app/helpers/connection_links_helper.rb
new file mode 100644
index 000000000..d9c201028
--- /dev/null
+++ b/app/helpers/connection_links_helper.rb
@@ -0,0 +1,8 @@
+module ConnectionLinksHelper
+
+ def connection_link_type_label_pairs
+ Chouette::ConnectionLink
+ .connection_link_types
+ .zip_map { |type| t("connection_link_types.label.#{type}") }
+ end
+end
diff --git a/app/helpers/core_helper.rb b/app/helpers/core_helper.rb
new file mode 100644
index 000000000..af2f6664c
--- /dev/null
+++ b/app/helpers/core_helper.rb
@@ -0,0 +1,7 @@
+module CoreHelper
+ module ::Enumerable
+ def zip_map
+ map { |ele| [ele, yield(ele)] }
+ end
+ end
+end
diff --git a/app/helpers/networks_helper.rb b/app/helpers/networks_helper.rb
new file mode 100644
index 000000000..b881ce078
--- /dev/null
+++ b/app/helpers/networks_helper.rb
@@ -0,0 +1,7 @@
+module NetworksHelper
+
+ def source_type_name_label_pairs
+ Chouette::Network.source_type_names
+ .zip_map { |source_type_name| t("source_types.label.#{source_type_name}") }
+ end
+end
diff --git a/app/helpers/newapplication_helper.rb b/app/helpers/newapplication_helper.rb
index c9da544d1..42fca489f 100644
--- a/app/helpers/newapplication_helper.rb
+++ b/app/helpers/newapplication_helper.rb
@@ -16,7 +16,7 @@ module NewapplicationHelper
end
columns.map do |k, v|
- if ["ID Codif", "Oid", "OiD", "ID Reflex", "Arrêt de départ", "Arrêt d'arrivée"].include? k
+ if ["ID Codif", "Oid", "OiD", "ID Reflex", "Arrêt de départ", "Arrêt d'arrivée", "Période de validité englobante"].include? k
hcont << content_tag(:th, k)
else
hcont << content_tag(:th, sortable_columns(collection, k))
@@ -30,6 +30,7 @@ module NewapplicationHelper
body = content_tag :tbody do
collection.collect do |item|
+
content_tag :tr do
bcont = []
@@ -47,17 +48,17 @@ module NewapplicationHelper
else
item.try(attribute)
end
- if attribute == 'name'
+ if attribute == 'name' or attribute == 'comment'
lnk = []
- unless item.class.to_s == 'Calendar' or item.class.to_s == 'Referential'
+ unless item.class == Calendar or item.class == Referential
if current_referential
lnk << current_referential
lnk << item.line if item.respond_to? :line
- lnk << item if item.class.to_s == 'Chouette::RoutingConstraintZone'
+ lnk << item.route.line if item.class == Chouette::RoutingConstraintZone
lnk << item if item.respond_to? :line_referential
lnk << item.stop_area if item.respond_to? :stop_area
- lnk << item if item.respond_to? :stop_points
+ lnk << item if item.respond_to? :stop_points or item.class.to_s == 'Chouette::TimeTable'
elsif item.respond_to? :referential
lnk << item.referential
end
@@ -101,14 +102,14 @@ module NewapplicationHelper
polymorph_url << action
end
- unless item.class.to_s == 'Calendar' or item.class.to_s == 'Referential'
+ unless item.class == Calendar or item.class == Referential
if current_referential
polymorph_url << current_referential
polymorph_url << item.line if item.respond_to? :line
- polymorph_url << item if item.class.to_s == 'Chouette::RoutingConstraintZone'
+ polymorph_url << item.route.line if item.class == Chouette::RoutingConstraintZone
polymorph_url << item if item.respond_to? :line_referential
polymorph_url << item.stop_area if item.respond_to? :stop_area
- polymorph_url << item if item.respond_to? :stop_points
+ polymorph_url << item if item.respond_to? :stop_points or item.class.to_s == 'Chouette::TimeTable'
elsif item.respond_to? :referential
polymorph_url << item.referential
end
diff --git a/app/helpers/rule_parameter_sets_helper.rb b/app/helpers/rule_parameter_sets_helper.rb
index 538a5cddd..bb210d9cd 100644
--- a/app/helpers/rule_parameter_sets_helper.rb
+++ b/app/helpers/rule_parameter_sets_helper.rb
@@ -18,6 +18,11 @@ module RuleParameterSetsHelper
t "false"
end
+ def transport_mode_label_pairs
+ Chouette::TransportMode
+ .all
+ .zip_map { |mode| t("transport_modes.label.#{mode}") }
+ end
end
diff --git a/app/helpers/stop_area_copies_helper.rb b/app/helpers/stop_area_copies_helper.rb
new file mode 100644
index 000000000..023a9d750
--- /dev/null
+++ b/app/helpers/stop_area_copies_helper.rb
@@ -0,0 +1,8 @@
+module StopAreaCopiesHelper
+
+ def label_stop_area_types(*stop_area_types)
+ stop_area_types
+ .flatten
+ .zip_map { |stop_area_type| t("area_types.label.#{stop_area_type}") }
+ end
+end
diff --git a/app/helpers/stop_areas_helper.rb b/app/helpers/stop_areas_helper.rb
index 2188a272d..3e04fac7d 100644
--- a/app/helpers/stop_areas_helper.rb
+++ b/app/helpers/stop_areas_helper.rb
@@ -33,27 +33,6 @@ module StopAreasHelper
@stop_area.stop_area_type == 'stop_place' || @stop_area.stop_area_type == 'commercial_stop_point'
end
- def access_links_pairs(access_links)
- hpairs = Hash.new
- pairs = Array.new
- access_links.each do |link|
- key = pair_key(link)
- pair = nil
- if (hpairs.has_key? key)
- pair = hpairs[key]
- else
- pair = AccessLinkPair.new
- pairs << pair
- hpairs[key] = pair
- end
- if (link.link_orientation_type == "access_point_to_stop_area")
- pair.from_access_point = link
- else
- pair.to_access_point = link
- end
- end
- pairs
- end
def pair_key(access_link)
"#{access_link.access_point.id}-#{access_link.stop_area.id}"
diff --git a/app/helpers/time_tables_helper.rb b/app/helpers/time_tables_helper.rb
index 9fdb791b1..b380a2b0a 100644
--- a/app/helpers/time_tables_helper.rb
+++ b/app/helpers/time_tables_helper.rb
@@ -1,3 +1,178 @@
+require 'date'
+
module TimeTablesHelper
-end
+ def month_periode_enum(years)
+ start_date = Date.today - years.years
+ end_date = Date.today + years.years
+ (start_date..end_date).map(&:beginning_of_month).uniq.map(&:to_s)
+ end
+
+ def new_alt_calendar(options = {}, &block)
+ raise(ArgumentError, "No year given") unless options.has_key?(:year)
+ raise(ArgumentError, "No month given") unless options.has_key?(:month)
+
+ block ||= Proc.new {|d| nil}
+
+ month_names = (!defined?(I18n) || I18n.t("date.month_names").include?("missing")) ? Date::MONTHNAMES.dup : I18n.t("date.month_names")
+
+ defaults = {
+ :table_id => "calendar-#{options[:year]}-#{"%02d" % options[:month]}",
+ :table_class => 'calendar',
+ :month_name_class => 'monthName',
+ :other_month_class => 'outsideMonth',
+ :day_name_class => 'dayName',
+ :day_class => 'day',
+ :abbrev => false,
+ :first_day_of_week => 0,
+ :accessible => false,
+ :show_today => true,
+ :previous_month_text => nil,
+ :next_month_text => nil,
+ :month_header => true,
+ :calendar_title => month_names[options[:month]],
+ :summary => "Calendrier pour #{month_names[options[:month]]} #{options[:year]}"
+ }
+ options = defaults.merge options
+
+ first = Date.civil(options[:year], options[:month], 1)
+ last = Date.civil(options[:year], options[:month], -1)
+
+ first_weekday = first_day_of_week(options[:first_day_of_week])
+ last_weekday = last_day_of_week(options[:first_day_of_week])
+
+ day_names = (!defined?(I18n) || I18n.t("date.day_names").include?("missing")) ? Date::DAYNAMES : I18n.t("date.day_names")
+ abbr_day_names = (!defined?(I18n) || I18n.t("date.abbr_day_names").include?("missing")) ? Date::ABBR_DAYNAMES : I18n.t("date.abbr_day_names")
+ week_days = (0..6).to_a
+ first_weekday.times do
+ week_days.push(week_days.shift)
+ end
+
+ # TODO Use some kind of builder instead of straight HTML
+ cal = %(<table id="#{options[:table_id]}" class="#{options[:table_class]}" border="0" cellspacing="0" cellpadding="0" summary="#{options[:summary]}">)
+ cal << %(<thead>)
+
+ if (options[:month_header])
+ cal << %(<tr>)
+ cal << %(<th class='weekNumber' scope="col"></th>)
+ if options[:previous_month_text] or options[:next_month_text]
+ cal << %(<th colspan="2">#{options[:previous_month_text]}</th>)
+ colspan=3
+ else
+ colspan=7
+ end
+ cal << %(<th colspan="#{colspan}" class="#{options[:month_name_class]}">#{options[:calendar_title]}</th>)
+ cal << %(<th colspan="2">#{options[:next_month_text]}</th>) if options[:next_month_text]
+ cal << %(</tr>)
+ end
+
+ cal << %(<tr class="#{options[:day_name_class]}">)
+ cal << %(<th class='weekNumber' scope="col"></th>)
+
+ week_days.each do |wday|
+ cal << %(<th id="#{th_id(Date::DAYNAMES[wday], options[:table_id])}" scope="col">)
+ cal << (options[:abbrev] ? %(<abbr title="#{day_names[wday]}">#{t("calendars.days.#{Date::DAYNAMES[wday].downcase}")}</abbr>) : t("calendars.days.#{Date::DAYNAMES[wday].downcase}"))
+ cal << %(</th>)
+ end
+
+ cal << "</tr></thead><tbody><tr>"
+
+ # previous month
+ beginning_of_week(first, first_weekday).upto(first - 1) do |d|
+ cal << "<td class='weekNumber'>S#{d.strftime("%W").to_s}</td>" if d.wday == first_weekday
+ cal << generate_other_month_cell(d, options)
+ end unless first.wday == first_weekday
+
+ first.upto(last) do |cur|
+ cell_text, cell_attrs = block.call(cur)
+ cell_text ||= cur.mday
+ cell_attrs ||= {}
+ cell_attrs[:headers] = th_id(cur, options[:table_id])
+ cell_attrs[:class] ||= options[:day_class]
+ cell_attrs[:class] += " weekend" if [0, 6].include?(cur.wday)
+ today = (Time.respond_to?(:zone) && !(zone = Time.zone).nil? ? zone.now.to_date : Date.today)
+ cell_attrs[:class] += " today" if (cur == today) and options[:show_today]
+
+ cal << "<td class='weekNumber'>S#{cur.strftime("%W").to_s}</td>" if cur.wday == first_weekday
+
+ cal << generate_cell(cell_text, cell_attrs)
+ cal << "</tr><tr>" if cur.wday == last_weekday
+ end
+
+ # next month
+ (last + 1).upto(beginning_of_week(last + 7, first_weekday) - 1) do |d|
+ cal << generate_other_month_cell(d, options)
+ end unless last.wday == last_weekday
+
+ cal << "</tr></tbody></table>"
+ cal.respond_to?(:html_safe) ? cal.html_safe : cal
+ end
+
+ private
+
+ def first_day_of_week(day)
+ day
+ end
+
+ def last_day_of_week(day)
+ if day > 0
+ day - 1
+ else
+ 6
+ end
+ end
+
+ def days_between(first, second)
+ if first > second
+ second + (7 - first)
+ else
+ second - first
+ end
+ end
+
+ def beginning_of_week(date, start = 1)
+ days_to_beg = days_between(start, date.wday)
+ date - days_to_beg
+ end
+
+ def generate_cell(cell_text, cell_attrs)
+ cell_attrs = cell_attrs.map {|k, v| %(#{k}="#{v}") }.join(" ")
+ "<td #{cell_attrs}>#{cell_text}</td>"
+ end
+
+ def generate_other_month_cell(date, options)
+ cell_attrs = {}
+ cell_attrs[:headers] = th_id(date, options[:table_id])
+ cell_attrs[:class] = options[:other_month_class]
+ cell_attrs[:class] += " weekend" if weekend?(date)
+ cell_attrs[:title] ||= date.strftime("%W").to_i if options[:first_day_of_week] == 1
+
+ cell_text = date.day
+ if options[:accessible]
+ cell_text += %(<span class="hidden"> #{month_names[date.month]}</span>)
+ end
+
+ generate_cell(date.day, cell_attrs)
+ end
+
+ # Calculates id for th element.
+ # derived from calendar_id and dow.
+ #
+ # Params:
+ # `day` can be either Date or DOW('Sunday', 'Monday')
+ def th_id(day, calendar_id)
+ return th_id(Date::DAYNAMES[day.wday], calendar_id) if day.is_a?(Date)
+ "#{calendar_id}-#{day[0..2].downcase}"
+ end
+
+ def weekend?(date)
+ [0, 6].include?(date.wday)
+ end
+
+ class Engine < Rails::Engine # :nodoc:
+ ActiveSupport.on_load(:action_view) do
+ include CalendarHelper
+ end
+ end if defined? Rails::Engine
+
+end
diff --git a/app/helpers/vehicle_journeys_helper.rb b/app/helpers/vehicle_journeys_helper.rb
index e70f2954b..6877abd11 100644
--- a/app/helpers/vehicle_journeys_helper.rb
+++ b/app/helpers/vehicle_journeys_helper.rb
@@ -41,6 +41,12 @@ module VehicleJourneysHelper
end
end
+ def route_journey_pattern_label_pairs route
+ route
+ .journey_patterns
+ .zip_map { |jp| journey_name(jp) }
+ end
+
def edit_vehicle_title( vehicle)
return t('vehicle_journeys.edit.title_stopless', :name => vehicle_name( vehicle)) if vehicle.vehicle_journey_at_stops.empty?
first_vjas = vehicle.vehicle_journey_at_stops.first
diff --git a/app/inputs/tags_input.rb b/app/inputs/tags_input.rb
index 4fbf0465f..1dc6129ee 100644
--- a/app/inputs/tags_input.rb
+++ b/app/inputs/tags_input.rb
@@ -1,19 +1,16 @@
-class TagsInput < Formtastic::Inputs::StringInput
-
- def to_html
- input_wrapping do
- label_html <<
- '<span id="tagsContainer"></span>'.html_safe <<
- builder.text_field(method, input_html_options)
- end
+class TagsInput < SimpleForm::Inputs::CollectionInput
+ enable :placeholder
+
+ def input(wrapper_options = {})
+ @collection ||= @builder.object.send(attribute_name)
+ label_method, value_method = detect_collection_methods
+
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
+ merged_input_options.reverse_merge!(multiple: true)
+
+ @builder.collection_select(
+ attribute_name, collection, value_method, label_method,
+ input_options, merged_input_options
+ )
end
-
- def input_html_options
- super.merge({
- :required => nil,
- :autofocus => nil,
- :class => 'tm-input',
- })
- end
-
end
diff --git a/app/models/chouette/line.rb b/app/models/chouette/line.rb
index 27a37a7f4..f44375e7d 100644
--- a/app/models/chouette/line.rb
+++ b/app/models/chouette/line.rb
@@ -14,20 +14,20 @@ class Chouette::Line < Chouette::ActiveRecord
belongs_to :company
belongs_to :network
+ belongs_to :line_referential
has_array_of :secondary_companies, class_name: 'Chouette::Company'
has_many :routes, :dependent => :destroy
has_many :journey_patterns, :through => :routes
has_many :vehicle_journeys, :through => :journey_patterns
+ has_many :routing_constraint_zones, through: :routes
has_and_belongs_to_many :group_of_lines, :class_name => 'Chouette::GroupOfLine', :order => 'group_of_lines.name'
has_many :footnotes, :inverse_of => :line, :validate => :true, :dependent => :destroy
accepts_nested_attributes_for :footnotes, :reject_if => :all_blank, :allow_destroy => true
- has_many :routing_constraint_zones
-
attr_reader :group_of_line_tokens
# validates_presence_of :network
@@ -76,4 +76,8 @@ class Chouette::Line < Chouette::ActiveRecord
[name, company.try(:name)].compact.join(' - ')
end
+ def companies
+ line_referential.companies.where(id: ([company_id] + Array(secondary_company_ids)).compact)
+ end
+
end
diff --git a/app/models/chouette/route.rb b/app/models/chouette/route.rb
index 9de7d7470..429189ff5 100644
--- a/app/models/chouette/route.rb
+++ b/app/models/chouette/route.rb
@@ -5,7 +5,7 @@ class Chouette::Route < Chouette::TridentActiveRecord
extend ActiveModel::Naming
enumerize :direction, in: %i(straight_forward backward clockwise counter_clockwise north north_west west south_west south south_east east north_east)
- enumerize :wayback, in: %i(straight_forward backward), default: :backward
+ enumerize :wayback, in: %i(straight_forward backward), default: :straight_forward
# FIXME http://jira.codehaus.org/browse/JRUBY-6358
self.primary_key = "id"
@@ -16,6 +16,7 @@ class Chouette::Route < Chouette::TridentActiveRecord
belongs_to :line
+ has_many :routing_constraint_zones
has_many :journey_patterns, :dependent => :destroy
has_many :vehicle_journeys, :dependent => :destroy do
def timeless
diff --git a/app/models/chouette/routing_constraint_zone.rb b/app/models/chouette/routing_constraint_zone.rb
index 681069416..6a8847e4d 100644
--- a/app/models/chouette/routing_constraint_zone.rb
+++ b/app/models/chouette/routing_constraint_zone.rb
@@ -1,9 +1,24 @@
class Chouette::RoutingConstraintZone < Chouette::TridentActiveRecord
- belongs_to :line
- has_array_of :stop_areas, class_name: 'Chouette::StopArea'
+ belongs_to :route
+ has_array_of :stop_points, class_name: 'Chouette::StopPoint'
- validates_presence_of :name, :stop_area_ids, :line_id
- validates :stop_areas, length: { minimum: 2 }
+ validates_presence_of :name, :stop_point_ids, :route_id
+ validates :stop_point_ids, length: { minimum: 2, too_short: I18n.t('activerecord.errors.models.routing_constraint_zone.attributes.stop_points.not_enough_stop_points') }
+ validate :stop_points_belong_to_route, :not_all_stop_points_selected
- self.primary_key = 'id'
+ def stop_points_belong_to_route
+ errors.add(:stop_point_ids, I18n.t('activerecord.errors.models.routing_constraint_zone.attributes.stop_points.stop_points_not_from_route')) unless stop_points.all? { |sp| route.stop_points.include? sp }
+ end
+
+ def not_all_stop_points_selected
+ errors.add(:stop_point_ids, I18n.t('activerecord.errors.models.routing_constraint_zone.attributes.stop_points.all_stop_points_selected')) if stop_points.length == route.stop_points.length
+ end
+
+ def stop_points_count
+ stop_points.count
+ end
+
+ def route_name
+ route.name
+ end
end
diff --git a/app/models/chouette/stop_point.rb b/app/models/chouette/stop_point.rb
index b77189fc1..e0f947487 100644
--- a/app/models/chouette/stop_point.rb
+++ b/app/models/chouette/stop_point.rb
@@ -2,7 +2,7 @@ module Chouette
class StopPoint < TridentActiveRecord
include ForBoardingEnumerations
include ForAlightingEnumerations
-
+
# FIXME http://jira.codehaus.org/browse/JRUBY-6358
self.primary_key = "id"
@@ -16,7 +16,9 @@ module Chouette
validates_presence_of :stop_area
validate :stop_area_id_validation
- scope :default_order, order("position")
+ scope :default_order, -> { order("position") }
+
+ delegate :name, to: :stop_area
before_destroy :remove_dependent_journey_pattern_stop_points
def remove_dependent_journey_pattern_stop_points
@@ -25,7 +27,7 @@ module Chouette
jp.stop_point_ids = jp.stop_point_ids - [id]
end
end
- end
+ end
def stop_area_id_validation
if stop_area_id.nil?
diff --git a/app/models/chouette/time_table.rb b/app/models/chouette/time_table.rb
index 7afdc4529..086e6fa77 100644
--- a/app/models/chouette/time_table.rb
+++ b/app/models/chouette/time_table.rb
@@ -43,6 +43,19 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
[Chouette::TimeTable.maximum(:end_date)].compact.max
end
+ def month_inspect(date)
+ (date.beginning_of_month..date.end_of_month).map do |d|
+ {
+ day: I18n.l(d, format: '%A'),
+ wday: d.wday,
+ wnumber: d.strftime("%W").to_s,
+ mday: d.mday,
+ include_date: include_in_dates?(d),
+ excluded_date: excluded_date?(d)
+ }
+ end
+ end
+
def save_shortcuts
shortcuts_update
self.update_column(:start_date, start_date)
@@ -454,4 +467,3 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord
tt
end
end
-
diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb
index 0aab9d0ed..4d7d596d8 100644
--- a/app/models/chouette/vehicle_journey.rb
+++ b/app/models/chouette/vehicle_journey.rb
@@ -49,27 +49,61 @@ module Chouette
def vehicle_journey_at_stops_matrix
at_stops = self.vehicle_journey_at_stops.to_a.dup
- filling = route.stop_points.map(&:id) - at_stops.map(&:stop_point_id)
- filling.each do |id|
- at_stops.insert(route.stop_points.map(&:id).index(id), Chouette::VehicleJourneyAtStop.new())
+ (route.stop_points.map(&:id) - at_stops.map(&:stop_point_id)).each do |id|
+ # Set stop_point id for fake vjas with no departure time yep.
+ params = {}
+ params[:stop_point_id] = id if journey_pattern.stop_points.map(&:id).include?(id)
+ at_stops.insert(route.stop_points.map(&:id).index(id), Chouette::VehicleJourneyAtStop.new(params))
end
at_stops
end
+ def create_or_find_vjas_from_state vjas
+ return vehicle_journey_at_stops.find(vjas['id']) if vjas['id']
+ stop_point = Chouette::StopPoint.find_by(objectid: vjas['stop_point_objectid'])
+ stop = vehicle_journey_at_stops.create(stop_point: stop_point)
+ vjas['id'] = stop.id
+ vjas['new_record'] = true
+ stop
+ end
+
def update_vjas_from_state state
state.each do |vjas|
next if vjas["dummy"]
- stop = vehicle_journey_at_stops.find(vjas['id']) if vjas['id']
- if stop
- params = {}.tap do |el|
- ['arrival_time', 'departure_time'].each do |field|
- time = "#{vjas[field]['hour']}:#{vjas[field]['minute']}"
- el[field.to_sym] = Time.parse("2000-01-01 #{time}:00 UTC")
- end
+ params = {}.tap do |el|
+ ['arrival_time', 'departure_time'].each do |field|
+ time = "#{vjas[field]['hour']}:#{vjas[field]['minute']}"
+ el[field.to_sym] = Time.parse("2000-01-01 #{time}:00 UTC")
+ end
+ end
+ stop = create_or_find_vjas_from_state(vjas)
+ stop.update_attributes(params)
+ vjas.delete('errors')
+ vjas['errors'] = stop.errors if stop.errors.any?
+ end
+ end
+
+ def state_update_vjas? vehicle_journey_at_stops
+ departure_times = vehicle_journey_at_stops.map do |vjas|
+ "#{vjas['departure_time']['hour']}:#{vjas['departure_time']['minute']}"
+ end
+ times = departure_times.uniq
+ (times.count == 1 && times[0] == '00:00') ? false : true
+ end
+
+ def update_has_and_belongs_to_many_from_state item
+ ['time_tables', 'footnotes'].each do |assos|
+ saved = self.send(assos).map(&:id)
+
+ (saved - item[assos].map{|t| t['id']}).each do |id|
+ self.send(assos).delete(self.send(assos).find(id))
+ end
+
+ item[assos].each do |t|
+ klass = "Chouette::#{assos.classify}".constantize
+ unless saved.include?(t['id'])
+ self.send(assos) << klass.find(t['id'])
end
- stop.update_attributes(params)
- vjas.delete('errors')
- vjas['errors'] = stop.errors if stop.errors.any?
end
end
end
@@ -81,17 +115,30 @@ module Chouette
vj = find_by(objectid: item['objectid']) || state_create_instance(route, item)
next if item['deletable'] && vj.persisted? && vj.destroy
- vj.update_vjas_from_state(item['vehicle_journey_at_stops'])
+ if vj.state_update_vjas?(item['vehicle_journey_at_stops'])
+ vj.update_vjas_from_state(item['vehicle_journey_at_stops'])
+ end
+
vj.update_attributes(state_permited_attributes(item))
+ vj.update_has_and_belongs_to_many_from_state(item)
item['errors'] = vj.errors if vj.errors.any?
end
+
+ # Delete ids of new object from state if we had to rollback
if state.any? {|item| item['errors']}
- state.map {|item| item.delete('objectid') if item['new_record']}
+ state.map do |item|
+ item.delete('objectid') if item['new_record']
+ item['vehicle_journey_at_stops'].map {|vjas| vjas.delete('id') if vjas['new_record'] }
+ end
raise ::ActiveRecord::Rollback
end
end
- state.map {|item| item.delete('new_record')}
+ # Remove new_record flag && deleted item from state if transaction has been saved
+ state.map do |item|
+ item.delete('new_record')
+ item['vehicle_journey_at_stops'].map {|vjas| vjas.delete('new_record') }
+ end
state.delete_if {|item| item['deletable']}
end
diff --git a/app/models/import.rb b/app/models/import.rb
index c407daa78..d0736ab0b 100644
--- a/app/models/import.rb
+++ b/app/models/import.rb
@@ -4,11 +4,12 @@ class Import < ActiveRecord::Base
belongs_to :referential
extend Enumerize
- enumerize :status, in: %i(new pending successful failed canceled)
+ enumerize :status, in: %i(new pending successful failed running aborted canceled)
validates :file, presence: true
before_create do
self.token_download = SecureRandom.urlsafe_base64
+ self.status = Import.status.new
end
end
diff --git a/app/models/netex_import.rb b/app/models/netex_import.rb
index 27f5846af..0da008d2e 100644
--- a/app/models/netex_import.rb
+++ b/app/models/netex_import.rb
@@ -1,3 +1,13 @@
+require 'net/http'
class NetexImport < Import
+ after_create :launch_java_import
+ def launch_java_import
+ logger.warn "Call iev get #{Rails.configuration.iev_url}/boiv_iev/referentials/importer/new?id=#{id}"
+ begin
+ Net::HTTP.get(Rails.configuration.iev_url, "/boiv_iev/referentials/importer/new?id=#{id}")
+ rescue
+ logger.error("IEV server error")
+ end
+ end
end
diff --git a/app/models/referential.rb b/app/models/referential.rb
index b6a83c6c3..50db32637 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -45,6 +45,8 @@ class Referential < ActiveRecord::Base
scope :ready, -> { where(ready: true) }
scope :in_periode, ->(periode) { where(id: referential_ids_in_periode(periode)) }
scope :include_metadatas_lines, ->(line_ids) { where('referential_metadata.line_ids && ARRAY[?]::bigint[]', line_ids) }
+ scope :order_by_validity_period, ->(dir) { joins(:metadatas).order("unnest(periodes) #{dir}") }
+ scope :order_by_lines, ->(dir) { joins(:metadatas).group("referentials.id").order("sum(array_length(referential_metadata.line_ids,1)) #{dir}") }
def lines
if metadatas.blank?
@@ -232,11 +234,19 @@ class Referential < ActiveRecord::Base
def self.referential_ids_in_periode(range)
subquery = "SELECT DISTINCT(public.referential_metadata.referential_id) FROM public.referential_metadata, LATERAL unnest(periodes) period "
- subquery << "WHERE period && '#{ActiveRecord::ConnectionAdapters::PostgreSQLColumn.range_to_string(range)}'"
+ subquery << "WHERE period && '#{range_to_string(range)}'"
query = "SELECT * FROM public.referentials WHERE referentials.id IN (#{subquery})"
self.connection.select_values(query).map(&:to_i)
end
+ # Copied from Rails 4.1 activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+ # TODO: Relace with the appropriate Rais 4.2 / 5.x helper if one is found.
+ def self.range_to_string(object)
+ from = object.begin.respond_to?(:infinite?) && object.begin.infinite? ? '' : object.begin
+ to = object.end.respond_to?(:infinite?) && object.end.infinite? ? '' : object.end
+ "[#{from},#{to}#{object.exclude_end? ? ')' : ']'}"
+ end
+
def overlapped_referential_ids
return [] unless metadatas.present?
@@ -248,7 +258,7 @@ class Referential < ActiveRecord::Base
not_myself = "and referential_id != #{id}" if persisted?
periods_query = periodes.map do |periode|
- "period && '#{ActiveRecord::ConnectionAdapters::PostgreSQLColumn.range_to_string(periode)}'"
+ "period && '[#{periode.begin},#{periode.end})'"
end.join(" OR ")
query = "select distinct(public.referential_metadata.referential_id) FROM public.referential_metadata, unnest(line_ids) line, LATERAL unnest(periodes) period
diff --git a/app/models/referential_metadata.rb b/app/models/referential_metadata.rb
index 62faf5541..3ec8398e0 100644
--- a/app/models/referential_metadata.rb
+++ b/app/models/referential_metadata.rb
@@ -12,6 +12,25 @@ class ReferentialMetadata < ActiveRecord::Base
scope :include_lines, -> (line_ids) { where('line_ids && ARRAY[?]::bigint[]', line_ids) }
scope :include_dateranges, -> (dateranges) { where('periodes && ARRAY[?]', dateranges) }
+# Transform Wed, 22 Feb 2017...Fri, 24 Feb 2017 into Wed, 22 Feb 2017..Thu, 23 Feb 2017
+ def periodes
+ attributes["periodes"].tap do | periods |
+ return periods unless periods
+ return adapted_periods(periods)
+ end
+ end
+
+ def adapted_periods(periods)
+ periods.map do | period |
+ if period.try(:exclude_end?)
+ period.begin .. (period.end - 1)
+ else
+ period
+ end
+ end
+ end
+ private :adapted_periods
+
class Period
include ActiveAttr::Model
include ActiveAttr::MultiParameterAttributes
diff --git a/app/models/user.rb b/app/models/user.rb
index b921cdef8..8e73aa1d5 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -21,7 +21,6 @@ class User < ActiveRecord::Base
validates :organisation, :presence => true
validates :email, :presence => true, :uniqueness => true
validates :name, :presence => true
- validate :permissions_unique_and_nonempty
before_validation(:on => :create) do
self.password ||= Devise.friendly_token.first(6)
@@ -32,16 +31,14 @@ class User < ActiveRecord::Base
@@edit_offer_permissions = ['routes.create', 'routes.edit', 'routes.destroy', 'journey_patterns.create', 'journey_patterns.edit', 'journey_patterns.destroy',
'vehicle_journeys.create', 'vehicle_journeys.edit', 'vehicle_journeys.destroy', 'time_tables.create', 'time_tables.edit', 'time_tables.destroy',
'footnotes.edit', 'footnotes.create', 'footnotes.destroy', 'routing_constraint_zones.create', 'routing_constraint_zones.edit',
- 'routing_constraint_zones.destroy']
+ 'routing_constraint_zones.destroy', 'referentials.create', 'referentials.edit', 'referentials.destroy']
def cas_extra_attributes=(extra_attributes)
extra = extra_attributes.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
self.name = extra[:full_name]
self.email = extra[:email]
self.organisation = Organisation.sync_update extra[:organisation_code], extra[:organisation_name], extra[:functional_scope]
- if extra[:permissions] && extra[:permissions].include?('boiv:edit-offer')
- self.permissions = @@edit_offer_permissions
- end
+ self.permissions = extra[:permissions].include?('boiv:edit-offer') ? @@edit_offer_permissions : []
end
def self.portail_api_request
@@ -69,10 +66,7 @@ class User < ActiveRecord::Base
user.locked_at = el['locked_at']
user.organisation = Organisation.sync_update el['organization_code'], el['organization_name'], el['functional_scope']
user.synced_at = Time.now
-
- if el['permissions'] && el['permissions'].include?('boiv:edit-offer')
- user.permissions = @@edit_offer_permissions
- end
+ user.permissions = el['permissions'].include?('boiv:edit-offer') ? @@edit_offer_permissions : []
user.save
puts "✓ user #{user.username} has been updated" unless Rails.env.test?
end
@@ -91,10 +85,4 @@ class User < ActiveRecord::Base
end
end
- def permissions_unique_and_nonempty
- if permissions && permissions.any?
- errors.add(:permissions, I18n.t('activerecord.errors.models.calendar.attributes.permissions.must_be_unique')) if permissions.uniq.length != permissions.length
- errors.add(:permissions, I18n.t('activerecord.errors.models.calendar.attributes.permissions.must_be_nonempty')) if permissions.include? ''
- end
- end
end
diff --git a/app/models/user_context.rb b/app/models/user_context.rb
new file mode 100644
index 000000000..e0a856e4b
--- /dev/null
+++ b/app/models/user_context.rb
@@ -0,0 +1,8 @@
+class UserContext
+ attr_reader :user, :context
+
+ def initialize(user, context = {})
+ @user = user
+ @context = context
+ end
+end
diff --git a/app/policies/acces_point_policy.rb b/app/policies/acces_point_policy.rb
index 4f604693c..904b7a242 100644
--- a/app/policies/acces_point_policy.rb
+++ b/app/policies/acces_point_policy.rb
@@ -10,11 +10,11 @@ class AccessPointPolicy < ApplicationPolicy
end
def edit?
- organisation_match?(via_referential: true) && user.has_permission?('access_points.edit')
+ organisation_match? && user.has_permission?('access_points.edit')
end
def destroy?
- organisation_match?(via_referential: true) && user.has_permission?('access_points.destroy')
+ organisation_match? && user.has_permission?('access_points.destroy')
end
def update? ; edit? end
diff --git a/app/policies/access_link_policy.rb b/app/policies/access_link_policy.rb
index 8e7a86490..73b2d1baa 100644
--- a/app/policies/access_link_policy.rb
+++ b/app/policies/access_link_policy.rb
@@ -10,11 +10,11 @@ class AccessLinkPolicy < ApplicationPolicy
end
def edit?
- organisation_match?(via_referential: true) && user.has_permission?('access_links.edit')
+ organisation_match? && user.has_permission?('access_links.edit')
end
def destroy?
- organisation_match?(via_referential: true) && user.has_permission?('access_links.destroy')
+ organisation_match? && user.has_permission?('access_links.destroy')
end
def update? ; edit? end
diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb
index 07138b38e..4a2d760fb 100644
--- a/app/policies/application_policy.rb
+++ b/app/policies/application_policy.rb
@@ -1,11 +1,21 @@
class ApplicationPolicy
attr_reader :user, :record
- def initialize(user, record)
- @user = user
+ def initialize(user_context, record)
+ @user = user_context.user
+ @referential = user_context.context[:referential]
@record = record
end
+ attr_accessor :referential
+ def referential
+ @referential ||= record_referential
+ end
+
+ def record_referential
+ record.referential if record.respond_to?(:referential)
+ end
+
def index?
false
end
@@ -38,8 +48,14 @@ class ApplicationPolicy
Pundit.policy_scope!(user, record.class)
end
- def organisation_match?(via_referential: false)
- eval("user.organisation == record#{'.referential' if via_referential}.organisation")
+ def organisation_match?
+ user.organisation == organisation
+ end
+
+ def organisation
+ # When sending permission to react UI, we don't have access to record object for edit & destroy.. actions
+ organisation = record.is_a?(Symbol) ? nil : record.try(:organisation)
+ organisation or referential.try :organisation
end
class Scope
diff --git a/app/policies/connection_link_policy.rb b/app/policies/connection_link_policy.rb
index cc49f575f..abefd741c 100644
--- a/app/policies/connection_link_policy.rb
+++ b/app/policies/connection_link_policy.rb
@@ -10,11 +10,11 @@ class ConnectionLinkPolicy < ApplicationPolicy
end
def edit?
- organisation_match?(via_referential: true) && user.has_permission?('connection_links.edit')
+ organisation_match? && user.has_permission?('connection_links.edit')
end
def destroy?
- organisation_match?(via_referential: true) && user.has_permission?('connection_links.destroy')
+ organisation_match? && user.has_permission?('connection_links.destroy')
end
def update? ; edit? end
diff --git a/app/policies/journey_pattern_policy.rb b/app/policies/journey_pattern_policy.rb
index a11fd6bcc..56f32613c 100644
--- a/app/policies/journey_pattern_policy.rb
+++ b/app/policies/journey_pattern_policy.rb
@@ -6,15 +6,16 @@ class JourneyPatternPolicy < ApplicationPolicy
end
def create?
- user.has_permission?('journey_patterns.create') # organisation match via referential is checked in the view
+ # organisation match via referential is checked in the view
+ user.has_permission?('journey_patterns.create')
end
def edit?
- organisation_match?(via_referential: true) && user.has_permission?('journey_patterns.edit')
+ organisation_match? && user.has_permission?('journey_patterns.edit')
end
def destroy?
- organisation_match?(via_referential: true) && user.has_permission?('journey_patterns.destroy')
+ organisation_match? && user.has_permission?('journey_patterns.destroy')
end
def update? ; edit? end
diff --git a/app/policies/referential_policy.rb b/app/policies/referential_policy.rb
index 1175ba5c6..8d366aff7 100644
--- a/app/policies/referential_policy.rb
+++ b/app/policies/referential_policy.rb
@@ -6,24 +6,30 @@ class ReferentialPolicy < ApplicationPolicy
end
def create?
- true
+ user.has_permission?('referentials.create')
end
def edit?
- organisation_match?
+ organisation_match? && user.has_permission?('referentials.edit')
end
- def update?
- edit? && !record.archived?
+ def destroy?
+ organisation_match? && user.has_permission?('referentials.destroy')
end
def archive?
edit?
end
+ def clone?
+ organisation_match? && create?
+ end
+
def unarchive? ; archive? end
- def new? ; create? end
- def destroy? ; edit? end
+ def update? ; edit? end
+ def new? ; create? end
end
+
+
diff --git a/app/policies/route_policy.rb b/app/policies/route_policy.rb
index 0f42b7f08..c4d048f2a 100644
--- a/app/policies/route_policy.rb
+++ b/app/policies/route_policy.rb
@@ -10,11 +10,11 @@ class RoutePolicy < ApplicationPolicy
end
def edit?
- organisation_match?(via_referential: true) && user.has_permission?('routes.edit')
+ organisation_match? && user.has_permission?('routes.edit')
end
def destroy?
- organisation_match?(via_referential: true) && user.has_permission?('routes.destroy')
+ organisation_match? && user.has_permission?('routes.destroy')
end
def update? ; edit? end
diff --git a/app/policies/routing_constraint_zone_policy.rb b/app/policies/routing_constraint_zone_policy.rb
index fbf322066..3126241f0 100644
--- a/app/policies/routing_constraint_zone_policy.rb
+++ b/app/policies/routing_constraint_zone_policy.rb
@@ -10,11 +10,11 @@ class RoutingConstraintZonePolicy < ApplicationPolicy
end
def edit?
- organisation_match?(via_referential: true) && user.has_permission?('routing_constraint_zones.edit')
+ organisation_match? && user.has_permission?('routing_constraint_zones.edit')
end
def destroy?
- organisation_match?(via_referential: true) && user.has_permission?('routing_constraint_zones.destroy')
+ organisation_match? && user.has_permission?('routing_constraint_zones.destroy')
end
def update? ; edit? end
diff --git a/app/policies/time_table_policy.rb b/app/policies/time_table_policy.rb
index 1d14c646a..6ca02f451 100644
--- a/app/policies/time_table_policy.rb
+++ b/app/policies/time_table_policy.rb
@@ -10,11 +10,11 @@ class TimeTablePolicy < ApplicationPolicy
end
def edit?
- organisation_match?(via_referential: true) && user.has_permission?('time_tables.edit')
+ organisation_match? && user.has_permission?('time_tables.edit')
end
def destroy?
- organisation_match?(via_referential: true) && user.has_permission?('time_tables.destroy')
+ organisation_match? && user.has_permission?('time_tables.destroy')
end
def update? ; edit? end
diff --git a/app/policies/vehicle_journey_policy.rb b/app/policies/vehicle_journey_policy.rb
index 785c2bb1f..ae3680adf 100644
--- a/app/policies/vehicle_journey_policy.rb
+++ b/app/policies/vehicle_journey_policy.rb
@@ -10,11 +10,11 @@ class VehicleJourneyPolicy < ApplicationPolicy
end
def edit?
- organisation_match?(via_referential: true) && user.has_permission?('vehicle_journeys.edit')
+ organisation_match? && user.has_permission?('vehicle_journeys.edit')
end
def destroy?
- organisation_match?(via_referential: true) && user.has_permission?('vehicle_journeys.destroy')
+ organisation_match? && user.has_permission?('vehicle_journeys.destroy')
end
def update? ; edit? end
diff --git a/app/views/access_links/_form.html.slim b/app/views/access_links/_form.html.slim
index 463cdf9e3..429656115 100644
--- a/app/views/access_links/_form.html.slim
+++ b/app/views/access_links/_form.html.slim
@@ -5,7 +5,7 @@
= form.input :stop_area_id , as: :hidden
= form.input :link_orientation_type , as: :hidden
= form.input :name
- = form.input :access_link_type, as: :select, collection: Chouette::AccessLink.access_link_types, include_blank: true, member_label: Proc.new { |type| t("connection_link_types.label.#{type}") }
+ = form.input :access_link_type, as: :select, collection: access_link_type_label_pairs, include_blank: true
= form.input :comment
= form.input :link_distance
= form.input :mobility_restricted_suitability, as: :select, collection: [[t("true"), true], [t("false"), false]], include_blank: true
@@ -21,4 +21,4 @@
= form.actions do
= form.action :submit, as: :button
- = form.action :cancel, as: :link \ No newline at end of file
+ = form.action :cancel, as: :link
diff --git a/app/views/access_points/_form.html.slim b/app/views/access_points/_form.html.slim
index 1874644d5..5ba7a6863 100644
--- a/app/views/access_points/_form.html.slim
+++ b/app/views/access_points/_form.html.slim
@@ -7,9 +7,8 @@
= form.input :name
= form.input :access_point_type, as: :select,
:input_html => {:disabled => !@access_point.new_record? },
- :collection => Chouette::AccessPoint.access_point_types,
- include_blank: false,
- :member_label => Proc.new { |access_point_type| t("access_types.label.#{access_point_type}") }
+ :collection => access_point_type_label_pairs,
+ include_blank: false
= form.input :street_name
= form.input :country_code
= form.input :zip_code
@@ -41,4 +40,4 @@
= form.actions do
= form.action :submit, as: :button
- = form.action :cancel, as: :link \ No newline at end of file
+ = form.action :cancel, as: :link
diff --git a/app/views/connection_links/_form.html.slim b/app/views/connection_links/_form.html.slim
index afef3bba7..a3774ec88 100644
--- a/app/views/connection_links/_form.html.slim
+++ b/app/views/connection_links/_form.html.slim
@@ -1,9 +1,9 @@
= semantic_form_for [@referential, @connection_link] do |form|
= form.inputs do
= form.input :name
- = form.input :connection_link_type, as: :select, :collection => Chouette::ConnectionLink.connection_link_types, :include_blank => true, :member_label => Proc.new { |type| t("connection_link_types.label.#{type}") }
+ = form.input :connection_link_type, as: :select, collection: connection_link_type_label_pairs, include_blank: true
= form.input :comment
- = form.input :link_distance, input_html: { :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.connection_link.link_distance") }
+ = form.input :link_distance, input_html: { title: t("formtastic.titles#{format_restriction_for_locales(@referential)}.connection_link.link_distance") }
= form.input :mobility_restricted_suitability, as: :select, :collection => [[t("true"), true], [t("false"), false]], include_blank: true
= form.input :stairs_availability, as: :select, :collection => [[t("true"), true], [t("false"), false]], include_blank: true
= form.input :lift_availability, as: :select, :collection => [[t("true"), true], [t("false"), false]], include_blank: true
@@ -18,4 +18,4 @@
= form.actions do
= form.action :submit, as: :button
- = form.action :cancel, as: :link \ No newline at end of file
+ = form.action :cancel, as: :link
diff --git a/app/views/errors/not_allowed.html.slim b/app/views/errors/not_allowed.html.slim
new file mode 100644
index 000000000..6c94328cc
--- /dev/null
+++ b/app/views/errors/not_allowed.html.slim
@@ -0,0 +1,21 @@
+/ PageHeader
+= pageheader 'bug',
+ 'Erreur 403',
+ ''
+
+.page_content
+ .container-fluid
+ .row
+ .col-lg-12
+ .alert.alert-danger
+ - if I18n.locale == :fr
+ p
+ strong = "Désolé, la page demandée la page n'est pas accessible avec votre profil utilisateur."
+
+ p = "Vous pouvez néanmoins continuer à utiliser l'application IBOO."
+
+ - else
+ p
+ strong = "You are not allowed to access the page you were looking for."
+
+ p = "You can still continue the use the IBOO application. Thank you for understanding."
diff --git a/app/views/journey_patterns_collections/show.html.slim b/app/views/journey_patterns_collections/show.html.slim
index 33e13e3bb..b5607090f 100644
--- a/app/views/journey_patterns_collections/show.html.slim
+++ b/app/views/journey_patterns_collections/show.html.slim
@@ -11,9 +11,10 @@
.col-lg-12
#journey_patterns
-
= javascript_tag do
| window.stopPoints = #{(@stop_points_list.to_json).html_safe};
| window.journeyPatternLength = #{@journey_patterns.total_entries()};
- | window.journeyPatternsPerPage = #{@ppage}
+ | window.journeyPatternsPerPage = #{@ppage};
+ | window.perms = #{raw @perms}
+
= javascript_include_tag 'es6_browserified/journey_patterns/index.js'
diff --git a/app/views/lines/index.html.slim b/app/views/lines/index.html.slim
index ce4930d92..d7b6be5c8 100644
--- a/app/views/lines/index.html.slim
+++ b/app/views/lines/index.html.slim
@@ -20,6 +20,7 @@
{ 'Oid' => Proc.new { |n| n.objectid.local_id },
:number => 'number',
:name => 'name',
+ :deactivated => Proc.new{|n| n.deactivated? ? t('false') : t('true')},
'networks.name' => Proc.new { |n| n.try(:network).try(:name) },
'companies.name' => Proc.new { |n| n.try(:company).try(:name) },
:transport_mode => Proc.new { |n| n.transport_mode.nil? ? '-' : t("enumerize.line.transport_mode.#{n.try(:transport_mode)}") },
diff --git a/app/views/networks/_form.html.slim b/app/views/networks/_form.html.slim
index f7b97c27d..7b048edc9 100644
--- a/app/views/networks/_form.html.slim
+++ b/app/views/networks/_form.html.slim
@@ -6,10 +6,10 @@
= form.input :version_date, as: :date_picker
= form.input :description
= form.input :source_name
- = form.input :source_type_name, as: :select, :collection => Chouette::Network.source_type_names, :include_blank => true, :member_label => Proc.new { |mode| t("source_types.label.#{mode}") }
+ = form.input :source_type_name, as: :select, :collection => source_type_name_label_pairs, :include_blank => true
= form.input :source_identifier
= form.input :objectid, :required => !@network.new_record?, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.network.objectid")}
= form.actions do
= form.action :submit, as: :button
- = form.action :cancel, as: :link \ No newline at end of file
+ = form.action :cancel, as: :link
diff --git a/app/views/referential_networks/_form.html.slim b/app/views/referential_networks/_form.html.slim
index e7020ef68..a92fc7121 100644
--- a/app/views/referential_networks/_form.html.slim
+++ b/app/views/referential_networks/_form.html.slim
@@ -1,15 +1,15 @@
= semantic_form_for [@referential, @network] do |form|
= form.inputs do
- = form.input :name, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.network.name")}
- = form.input :registration_number, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.network.registration_number")}
+ = form.input :name, input_html: { title: t("formtastic.titles#{format_restriction_for_locales(@referential)}.network.name")}
+ = form.input :registration_number, input_html: { title: t("formtastic.titles#{format_restriction_for_locales(@referential)}.network.registration_number")}
= form.input :comment
= form.input :version_date, as: :date_picker
= form.input :description
= form.input :source_name
- = form.input :source_type_name, as: :select, :collection => Chouette::Network.source_type_names, :include_blank => true, :member_label => Proc.new { |mode| t("source_types.label.#{mode}") }
+ = form.input :source_type_name, as: :select, collection: source_type_name_label_pairs, include_blank: true
= form.input :source_identifier
- = form.input :objectid, :required => !@network.new_record?, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.network.objectid")}
+ = form.input :objectid, required: !@network.new_record?, input_html: { title: t("formtastic.titles#{format_restriction_for_locales(@referential)}.network.objectid")}
= form.actions do
= form.action :submit, as: :button
- = form.action :cancel, as: :link \ No newline at end of file
+ = form.action :cancel, as: :link
diff --git a/app/views/referentials/index.html.slim b/app/views/referentials/index.html.slim
index 8186f725f..8943d419c 100644
--- a/app/views/referentials/index.html.slim
+++ b/app/views/referentials/index.html.slim
@@ -13,7 +13,6 @@
ul.actions
li = link_to 'Données Reflex', stop_area_referential_path(1)
li = link_to 'Données CodifLigne', line_referential_path(1)
- li= link_to t('calendars.standard_calendars'), calendars_path
- / FIXME #823
+ li = link_to t('calendars.standard_calendars'), calendars_path
- if false
li = link_to t('referentials.actions.new'), new_referential_path, class: 'add'
diff --git a/app/views/referentials/show.html.slim b/app/views/referentials/show.html.slim
index 04f93738e..fd6ebf91a 100644
--- a/app/views/referentials/show.html.slim
+++ b/app/views/referentials/show.html.slim
@@ -5,10 +5,12 @@
t('last_update', time: l(@referential.updated_at, format: :short)),
((@referential.archived? || !policy(@referential).edit?) ? '' : link_to(t('actions.edit'), edit_referential_path(@referential), class: 'btn btn-default')) do
- / Below is secundary actions & optional contents (filters, ...)
+ / Below is secondary actions & optional contents (filters, ...)
.row.mb-sm
.col-lg-12.text-right
- - if policy(@referential).new?
+ = link_to t('time_tables.index.title'), referential_time_tables_path(@referential), class: 'btn btn-primary'
+
+ - if policy(@referential).clone?
= link_to t('actions.clone'), new_referential_path(from: @referential.id), class: 'btn btn-primary'
- if policy(@referential).edit?
diff --git a/app/views/routes/show.html.slim b/app/views/routes/show.html.slim
index 21a64b61e..9f84b31ad 100644
--- a/app/views/routes/show.html.slim
+++ b/app/views/routes/show.html.slim
@@ -39,7 +39,6 @@
:deleted_at => Proc.new{|s| s.try(:stop_area).deleted_at ? t('false') : t('true')},
:zip_code => Proc.new {|s| s.try(:stop_area).try(:zip_code)},
:city_name => Proc.new {|s| s.try(:stop_area).try(:city_name)},
- :area_type => Proc.new {|s| t("area_types.label.#{s.try(:stop_area).try(:area_type)}")},
:for_boarding => Proc.new {|s| t("stop_points.stop_point.for_boarding.#{s.for_boarding}")},
:for_alighting => Proc.new {|s| t("stop_points.stop_point.for_alighting.#{s.for_alighting}")},
:position => 'position' },
diff --git a/app/views/routing_constraint_zones/_form.html.slim b/app/views/routing_constraint_zones/_form.html.slim
index afc993a0f..b1c77a44b 100644
--- a/app/views/routing_constraint_zones/_form.html.slim
+++ b/app/views/routing_constraint_zones/_form.html.slim
@@ -4,10 +4,16 @@
= f.input :name
.row
.col-lg-6.col-sm-12
- / Temporarily limit the collection to 10 items... otherwise it kills RoR
- = f.input :stop_area_ids, as: :select, collection: Chouette::StopArea.limit(10), selected: @routing_constraint_zone.stop_area_ids, label: Chouette::StopArea.model_name.human.pluralize.capitalize, label_method: :name, input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': 'Sélection de arrêts', 'multiple': 'multiple', style: 'width: 100%' }
+ = f.input :route_id, collection: @line.routes.select { |route| route.stop_points.count > 2 }, include_blank: false
+ .row
+ .col-lg-6.col-sm-12
+ - stop_points_collection = @routing_constraint_zone.persisted? ? @routing_constraint_zone.route.stop_points : []
+ = f.input :stop_point_ids, as: :select, collection: stop_points_collection, selected: @routing_constraint_zone.stop_point_ids, label: Chouette::StopPoint.model_name.human.pluralize.capitalize, label_method: :name, input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': 'Sélection des arrêts sur séquence d\'arrêts', 'multiple': 'multiple', style: 'width: 100%' }
.row
.col-lg-12.text-right
= link_to 'Annuler', :back, class: 'btn btn-link'
= f.button :submit, class: 'btn btn-danger'
+
+
+= hidden_field_tag 'stop_point_ids', @routing_constraint_zone.stop_point_ids.to_s, id: 'stop_point_ids'
diff --git a/app/views/routing_constraint_zones/index.html.slim b/app/views/routing_constraint_zones/index.html.slim
index 9061fbdfd..620b0f7db 100644
--- a/app/views/routing_constraint_zones/index.html.slim
+++ b/app/views/routing_constraint_zones/index.html.slim
@@ -1,11 +1,11 @@
= title_tag Chouette::RoutingConstraintZone.model_name.human.pluralize(:fr)
- if policy(Chouette::RoutingConstraintZone).create? && @referential.organisation == current_organisation
- = link_to t('routing_constraint_zones.actions.new'), new_referential_line_routing_constraint_zone_path
+ = link_to t('routing_constraint_zones.actions.new'), new_referential_line_routing_constraint_zone_path(@referential, @line)
- if @routing_constraint_zones.any?
= table_builder @routing_constraint_zones,
- { :name => 'name' },
+ { objectid: 'objectid', name: 'name', route: 'route_name', stop_points_count: 'stop_points_count' },
[:show, :edit, :delete],
[],
'table table-bordered'
diff --git a/app/views/routing_constraint_zones/show.html.slim b/app/views/routing_constraint_zones/show.html.slim
index 0f88f5b3f..351784ecc 100644
--- a/app/views/routing_constraint_zones/show.html.slim
+++ b/app/views/routing_constraint_zones/show.html.slim
@@ -5,14 +5,13 @@ p
= @routing_constraint_zone.name
p
- label => "#{Chouette::Line.model_name.human.capitalize} : "
- = link_to @routing_constraint_zone.line.name, referential_line_path(@referential, @line)
+ label => "#{Chouette::Route.model_name.human.capitalize} : "
+ = link_to @routing_constraint_zone.route.name, referential_line_route_path(@referential, @line, @routing_constraint_zone.route)
p
- label => "#{Chouette::StopArea.model_name.human.pluralize.capitalize} : "
+ label => "#{Chouette::StopPoint.model_name.human.pluralize.capitalize} : "
br
- - @routing_constraint_zone.stop_areas.each do |stop_area|
- = link_to stop_area.name, referential_stop_area_path(@referential, stop_area)
+ - @routing_constraint_zone.stop_points.each do |stop_point|
+ = link_to stop_point.name, referential_stop_area_path(@referential, stop_point.stop_area)
br
-
diff --git a/app/views/rule_parameter_sets/_transport_mode_parameter_set_fields.html.slim b/app/views/rule_parameter_sets/_transport_mode_parameter_set_fields.html.slim
index a60c966e2..ede7e2b75 100644
--- a/app/views/rule_parameter_sets/_transport_mode_parameter_set_fields.html.slim
+++ b/app/views/rule_parameter_sets/_transport_mode_parameter_set_fields.html.slim
@@ -1,9 +1,9 @@
= f.inputs class: 'transport_mode_parameter_sets nested-fields' do
- = f.input :transport_mode, as: :select, :collection => Chouette::TransportMode.all, include_blank: false, member_label: Proc.new { |mode| t("transport_modes.label.#{mode}") }, label: "transport_mode", wrapper_html: { class: 'fl1' }
+ = f.input :transport_mode, as: :select, collection: transport_mode_label_pairs, include_blank: false, label: "transport_mode", wrapper_html: { class: 'fl1' }
= f.input :inter_stop_area_distance_min, as: :number, label: "inter_stop_area_distance_min", wrapper_html: { class: 'fl1' }
= f.input :inter_stop_area_distance_max, as: :number, label: "inter_stop_area_distance_max", wrapper_html: { class: 'fl2' }
= f.input :speed_min, as: :number, label: "speed_min", wrapper_html: { class: 'fl2' }
= f.input :speed_max, as: :number, label: "speed_max", wrapper_html: { class: 'fl2' }
= f.input :inter_stop_duration_variation_max, as: :number, label: "inter_stop_duration_variation_max", wrapper_html: { class: 'fl2' }
- = link_to_remove_association t('actions.destroy'), f \ No newline at end of file
+ = link_to_remove_association t('actions.destroy'), f
diff --git a/app/views/stop_area_copies/new.html.slim b/app/views/stop_area_copies/new.html.slim
index a4c0c8bde..1a8764cbc 100644
--- a/app/views/stop_area_copies/new.html.slim
+++ b/app/views/stop_area_copies/new.html.slim
@@ -8,13 +8,21 @@
- if @stop_area_copy.hierarchy == "child"
- if @stop_area.area_type.underscore == "stop_place"
- = form.input :area_type, as: :select, :collection => ["stop_place","commercial_stop_point"], :include_blank => false, :member_label => Proc.new { |stop_area_type| t("area_types.label.#{stop_area_type}") }
+ = form.input :area_type,
+ as: :select,
+ collection: label_stop_area_types( "stop_place","commercial_stop_point" ),
+ include_blank: false
- else
- = form.input :area_type, as: :select, :collection => ["boarding_position","quay"], :include_blank => false, :member_label => Proc.new { |stop_area_type| t("area_types.label.#{stop_area_type}") }
-
+ = form.input :area_type,
+ as: :select,
+ collection: label_stop_area_types( "boarding_position","quay" ),
+ include_blank: false
- else
- = form.input :area_type, as: :select, :collection => [@stop_area_copy.area_type], :include_blank => false, :member_label => Proc.new { |stop_area_type| t("area_types.label.#{stop_area_type}") }
+ = form.input :area_type,
+ as: :select,
+ collection: label_stop_area_types(@stop_area_copy.area_type),
+ include_blank: false
= form.actions do
= form.action :submit, as: :button , label: t('formtastic.duplicate')
- = form.action :cancel, as: :link \ No newline at end of file
+ = form.action :cancel, as: :link
diff --git a/app/views/stop_areas/index.html.slim b/app/views/stop_areas/index.html.slim
index c9ff2cecd..bc1529e68 100644
--- a/app/views/stop_areas/index.html.slim
+++ b/app/views/stop_areas/index.html.slim
@@ -17,7 +17,7 @@
.row
.col-lg-12
= table_builder @stop_areas,
- { 'Oid' => Proc.new { |n| n.try(:objectid).try(:local_id) },
+ { 'Oid' => Proc.new { |n| n.try(:user_objectid) },
:name => 'name', :registration_number => 'registration_number', :zip_code => 'zip_code',
:city_name => 'city_name', :area_type => Proc.new{|s| (s.area_type.nil? ? '-' : t("enumerize.stop_area.area_type.#{s.try(:area_type)}"))} },
[:show, :edit, :delete],
diff --git a/app/views/stop_areas/show.html.slim b/app/views/stop_areas/show.html.slim
index 9affba08e..58a2dbde3 100644
--- a/app/views/stop_areas/show.html.slim
+++ b/app/views/stop_areas/show.html.slim
@@ -22,7 +22,7 @@
= definition_list t('metadatas'),
{ @stop_area.human_attribute_name(:stop_area_type) => t("area_types.label.#{@stop_area.stop_area_type}"),
@stop_area.human_attribute_name(:registration_number) => @stop_area.registration_number,
- 'Code Reflex' => @stop_area.try(:objectid),
+ 'Code Reflex' => @stop_area.user_objectid,
'Coordonnées' => geo_data(@stop_area, @stop_area_referential),
@stop_area.human_attribute_name(:zip_code) => @stop_area.zip_code,
@stop_area.human_attribute_name(:city_name) => @stop_area.city_name,
diff --git a/app/views/time_tables/_date_fields.html.slim b/app/views/time_tables/_date_fields.html.slim
index f17fcaa2c..1599dd7ff 100644
--- a/app/views/time_tables/_date_fields.html.slim
+++ b/app/views/time_tables/_date_fields.html.slim
@@ -1,5 +1,14 @@
-= f.inputs class: 'nested-fields date' do
- = f.label @time_table.human_attribute_name("date"), class: 'col-md-1'
- = f.input :date, as: :date_picker, :label => false, :input_html => { class: 'form-control col-md-3' }
- = f.input :in_out, as: :hidden, :input_html => {:value => true}
- = link_to_remove_association t('actions.destroy'), f, class: "col-md-3" \ No newline at end of file
+.nested-fields
+ - if f.object.errors.has_key? :base
+ .row
+ .col-lg-12
+ .alert.alert-danger
+ - f.object.errors[:base].each do |message|
+ p.small = message
+
+ .wrapper
+ div
+ = f.input :date, as: :date, label: false, wrapper_html: { class: 'date' }
+ = f.input :in_out, as: :hidden, :input_html => {:value => true}
+ div
+ = link_to_remove_association '', f, class: 'fa fa-trash', data: { confirm: 'Etes-vous sûr(e) ?' }, title: t('actions.delete')
diff --git a/app/views/time_tables/_excluded_date_fields.html.slim b/app/views/time_tables/_excluded_date_fields.html.slim
index 294d103fc..dba5bf952 100644
--- a/app/views/time_tables/_excluded_date_fields.html.slim
+++ b/app/views/time_tables/_excluded_date_fields.html.slim
@@ -1,5 +1,15 @@
-= f.inputs class: 'nested-fields date' do
- = f.label @time_table.human_attribute_name("date"), class: 'col-md-1'
- = f.input :date, as: :date_picker, :label => false, :input_html => { class: 'form-control col-md-3' }
- = f.input :in_out, as: :hidden, :input_html => {:value => false}
- = link_to_remove_association t('actions.destroy'), f, class: "col-md-3" \ No newline at end of file
+.nested-fields
+ - if f.object.errors.has_key? :base
+ .row
+ .col-lg-12
+ .alert.alert-danger
+ - f.object.errors[:base].each do |message|
+ p.small = message
+
+ .wrapper
+ div
+ / = f.label @time_table.human_attribute_name("date"), class: 'col-md-1'
+ = f.input :date, as: :date, label: false, wrapper_html: { class: 'date' }
+ = f.input :in_out, as: :hidden, input_html: {value: false}
+ div
+ = link_to_remove_association '', f, class: 'fa fa-trash', data: { confirm: 'Etes-vous sûr(e) ?' }, title: t('actions.delete')
diff --git a/app/views/time_tables/_form.html.slim b/app/views/time_tables/_form.html.slim
index 8652f7cb5..97df72fd3 100644
--- a/app/views/time_tables/_form.html.slim
+++ b/app/views/time_tables/_form.html.slim
@@ -1,73 +1,102 @@
-= semantic_form_for [@referential, @time_table] do |form|
- = form.inputs do
- = form.input :comment, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.time_table.comment")}
- = form.input :version
- = form.input :tag_search, as: :tags, :input_html => { :id => "tag_search",:placeholder => t("formtastic.placeholders.time_table.tag_search") }
- = form.input :tag_list, as: :hidden, :input_html => { :id => "tag_list" }
- = form.input :objectid, :required => !@time_table.new_record?, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.time_table.objectid")}
- - if @time_table.new_record?
- = form.input :calendar, as: :select, collection: current_organisation.calendars
-
- h3.time_table_periods = @time_table.human_attribute_name("periods")
-
- #periods_content
- = form.inputs class: 'day_type' do
- label.day_type_label = @time_table.human_attribute_name("day_types")
- = form.input :monday, as: :boolean, class: "others"
- = form.input :tuesday, as: :boolean
- = form.input :wednesday, as: :boolean
- = form.input :thursday, as: :boolean
- = form.input :friday, as: :boolean
- = form.input :saturday, as: :boolean
- = form.input :sunday, as: :boolean
-
- #periods
- = form.semantic_fields_for :periods do |p|
- == render "period_fields", :f => p
-
- = link_to_add_association t("time_tables.actions.add_period"), form, :periods , :"data-association-insertion-method" => "append", :"data-association-insertion-node" => "div#periods"
-
- h3.time_table_dates = @time_table.human_attribute_name("dates")
-
- #dates_content
- #dates
- = form.semantic_fields_for :dates, @time_table.dates.to_a.select {|d| d.in_out == true} do |p|
- == render "date_fields", :f => p
-
- = link_to_add_association t("time_tables.actions.add_date"), form, :dates, :"data-association-insertion-method" => "append", :"partial" => "date_fields", :"data-association-insertion-node" => "div#dates"
-
- h3.time_table_dates = @time_table.human_attribute_name("excluded_dates")
-
- #excluded_dates_content
- #excluded_dates
- = form.semantic_fields_for :dates, @time_table.dates.to_a.select {|d| d.in_out == false} do |p|
- == render "excluded_date_fields", :f => p
-
- = link_to_add_association t("time_tables.actions.add_excluded_date"), form, :dates, :"data-association-insertion-method" => "append", :"partial" => "excluded_date_fields", :"data-association-insertion-node" => "div#excluded_dates"
-
- = form.actions do
- = form.action :submit, as: :button
- = form.action :cancel, as: :link
-
-= javascript_tag "var items = #{ @time_table.tag_list.to_a };"
-
-javascript:
- $("#tag_search").tagsManager({
- prefilled: items,
- output: '#tag_list',
- tagsContainer: '#tagsContainer'
- });
-
- var time_tables_tag_list = new Bloodhound({
- datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
- queryTokenizer: Bloodhound.tokenizers.whitespace,
- remote: "#{tags_referential_time_tables_path(@referential, format: 'json')}?tag=%QUERY",
- });
-
- time_tables_tag_list.initialize();
-
- $("#tag_search").typeahead(null, {
- name: 'time_tables_tag_list',
- displayKey: 'name',
- source: time_tables_tag_list.ttAdapter()
- });
+= simple_form_for [@referential, @time_table], html: {class: 'form-horizontal', id: 'timetable_form'}, wrapper: :horizontal_form do |form|
+
+ .row
+ .col-lg-12
+ = form.input :comment, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.time_table.comment")}
+
+ .form-group
+ = form.label @time_table.human_attribute_name(:color), required: false, class: 'control-label col-sm-4'
+
+ .col-sm-8
+ .dropdown.color_selector
+ button.btn.btn-default.dropdown-toggle type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"
+ span.fa.fa-circle.mr-xs style="color:#{@time_table.color.nil? ? 'transparent' : @time_table.color}"
+ span.caret
+
+ = form.input :color, as: :radio_buttons, label: false, collection: ["", "#9B9B9B", "#FFA070", "#C67300", "#7F551B", "#41CCE3", "#09B09C", "#3655D7", "#6321A0", "#E796C6", "#DD2DAA"], input_html: {class: 'color_selector'}, label_method: lambda{|c| ("<span class='fa fa-circle' style='color:" + (c.empty? ? 'transparent' : c) + "'></span>").html_safe}, wrapper_html: { class: 'dropdown-menu', 'aria-labelledby': "dropdownMenu1"}, include_blank: true
+
+ / = form.input :tag_list, as: :tags
+
+ .form-group
+ label.control-label.col-sm-4
+ = "Journées d'applications pour les périodes ci-dessous"
+
+ .col-sm-8
+ .form-group.labelled-checkbox-group
+ = form.input :monday, as: :boolean, label: ("<span class='lcbx-group-item-label'>L</span>").html_safe, wrapper_html: { class: 'lcbx-group-item' }
+ = form.input :tuesday, as: :boolean, label: ("<span class='lcbx-group-item-label'>Ma</span>").html_safe, wrapper_html: { class: 'lcbx-group-item' }
+ = form.input :wednesday, as: :boolean, label: ("<span class='lcbx-group-item-label'>Me</span>").html_safe, wrapper_html: { class: 'lcbx-group-item' }
+ = form.input :thursday, as: :boolean, label: ("<span class='lcbx-group-item-label'>J</span>").html_safe, wrapper_html: { class: 'lcbx-group-item' }
+ = form.input :friday, as: :boolean, label: ("<span class='lcbx-group-item-label'>V</span>").html_safe, wrapper_html: { class: 'lcbx-group-item' }
+ = form.input :saturday, as: :boolean, label: ("<span class='lcbx-group-item-label'>S</span>").html_safe, wrapper_html: { class: 'lcbx-group-item' }
+ = form.input :sunday, as: :boolean, label: ("<span class='lcbx-group-item-label'>D</span>").html_safe, wrapper_html: { class: 'lcbx-group-item' }
+
+ - if @time_table.new_record?
+ = form.input :calendar, as: :select, collection: current_organisation.calendars
+
+ .separator
+
+ .row
+ .col-lg-8.col-lg-offset-4
+ .subform
+ .nested-head
+ .wrapper
+ div
+ .form-group
+ label.control-label.required
+ = t('simple_form.labels.referential.metadatas.periods.begin')
+ abbr title='requis' *
+ div
+ .form-group
+ label.control-label.required
+ = t('simple_form.labels.referential.metadatas.periods.end')
+ abbr title='requis' *
+ div
+
+ = form.simple_fields_for :periods do |p|
+ = render "period_fields", f: p
+
+ .links.nested-linker
+ = link_to_add_association t("time_tables.actions.add_period"), form, :periods, class: 'btn btn-outline-primary'
+
+ .row
+ .col-lg-12.mb-sm.mt-md
+ #time_tables
+ .alert.alert-warning
+ |Les éléments ci-dessous sont à supprimer.
+
+ .row
+ .col-lg-6.col-md-6.col-sm-12.col-xs-12
+ .subform
+ .nested-head
+ .wrapper
+ div
+ .form-group
+ label.control-label
+ = @time_table.human_attribute_name("dates")
+ div
+
+ = form.simple_fields_for :dates, @time_table.dates.to_a.select {|d| d.in_out == true} do |p|
+ = render "date_fields", f: p
+
+ .links.nested-linker
+ = link_to_add_association t("time_tables.actions.add_date"), form, :dates, partial: 'date_fields', class: 'btn btn-outline-primary'
+
+ .col-lg-6.col-md-6.col-sm-12.col-xs-12
+ .subform
+ .nested-head
+ .wrapper
+ div
+ .form-group
+ label.control-label
+ = @time_table.human_attribute_name("excluded_dates")
+ div
+
+ = form.simple_fields_for :dates, @time_table.dates.to_a.select {|d| d.in_out == false} do |q|
+ = render "excluded_date_fields", f: q
+
+ .links.nested-linker
+ = link_to_add_association t("time_tables.actions.add_excluded_date"), form, :dates, partial: 'excluded_date_fields', class: 'btn btn-outline-primary'
+
+
+ = form.button :submit, t('actions.submit'), class: 'btn btn-default formSubmitr', form: 'timetable_form'
diff --git a/app/views/time_tables/_period_fields.html.slim b/app/views/time_tables/_period_fields.html.slim
index cefa68df5..f879ded00 100644
--- a/app/views/time_tables/_period_fields.html.slim
+++ b/app/views/time_tables/_period_fields.html.slim
@@ -1,8 +1,15 @@
-= f.inputs class: 'nested-fields period' do
- = f.label @time_table.human_attribute_name("period_start"), class: "col-md-1"
- = f.input :period_start, as: :date_picker, :label => false, :input_html => { class: 'form-control col-md-3' }
-
- = f.label @time_table.human_attribute_name("period_end"), class: "col-md-1"
- = f.input :period_end, as: :date_picker, :label => false, :input_html => { class: 'form-control col-md-3' }
-
- = link_to_remove_association t('actions.destroy'), f, class: "col-md-2" \ No newline at end of file
+.nested-fields
+ - if f.object.errors.has_key? :base
+ .row
+ .col-lg-12
+ .alert.alert-danger
+ - f.object.errors[:base].each do |message|
+ p.small = message
+
+ .wrapper
+ div
+ = f.input :period_start, as: :date, label: false, wrapper_html: { class: 'date' }
+ div
+ = f.input :period_end, as: :date, label: false, wrapper_html: { class: 'date' }
+ div
+ = link_to_remove_association '', f, class: 'fa fa-trash', data: { confirm: 'Etes-vous sûr(e) ?' }, title: t('actions.delete')
diff --git a/app/views/time_tables/_periods.html.slim b/app/views/time_tables/_periods.html.slim
deleted file mode 100644
index e3c6d5f39..000000000
--- a/app/views/time_tables/_periods.html.slim
+++ /dev/null
@@ -1,5 +0,0 @@
-ul.periods
- - @time_table.periods.each do |tmp|
- li.period
- = "#{('time_tables.show.from')} #{l tmp.period_start}"
- = "#{t('time_tables.show.to')} #{l tmp.period_end}" \ No newline at end of file
diff --git a/app/views/time_tables/_show_time_table.html.slim b/app/views/time_tables/_show_time_table.html.slim
index 419d13c96..ebfe9d283 100644
--- a/app/views/time_tables/_show_time_table.html.slim
+++ b/app/views/time_tables/_show_time_table.html.slim
@@ -1,94 +1,25 @@
-#time_table_show.time_table_show
- p
- span class="state-code #{@time_table.presenter.time_table_state_code}"
- i.fa.fa-certificate
-
- label
- - if @time_table.bounding_dates.empty?
- = t(".resume_empty")
- - else
- = t(".resume", :start_date => l(@time_table.bounding_dates.min), :end_date => l(@time_table.bounding_dates.max))
-
- p
- label = "#{@time_table.human_attribute_name('tag_list')} : "
- = @time_table.tag_list
-
- ul.nav.nav-tabs id="tabs" data-tabs="tabs"
- li.active
- a href="#time_tables" data-toggle="tab"
- = @time_table.human_attribute_name("calendars")
-
- li
- a href="#time_tables_datas" data-toggle="tab"
- = @time_table.human_attribute_name("calendar_details")
-
- #my-tab-content.tab-content
- #time_tables.tab-pane.active
- #associated_calendar
- => "#{t('calendars.standard_calendar')} : "
- - if @time_table.calendar
- = link_to @time_table.calendar.name, @time_table.calendar
- - else
- = '--'
-
- .well.legend
- span.title = t(".legend")
- span.label.excluded_date X
- = t(".excluded_date")
- span.label.overlaped_date X
- = t(".overlap_date")
- span.label.selected_date X
- = t(".selected_date")
- span.label.selected_period X
- = t(".selected_period")
-
- #calendars
- .year_choice
- span.previous = link_to("<", referential_time_table_path(@referential, @time_table, year: (@year - 1)) )
- span.year = "#{@year}"
- span.next = link_to(">", referential_time_table_path(@referential, @time_table, year: (@year + 1)) )
-
- .calendar_helper
- - cal = ""
- - (1..12).each do |month|
- - cal << calendar(year: @year, month: month, first_day_of_week: 1) do |d|
- - if @time_table.excluded_date?(d)
- - [link_to(d.mday, edit_referential_time_table_path(@referential, @time_table) ), {class: "day excluded_date"}]
- - elsif @time_table.include_in_overlap_dates?(d)
- - [link_to(d.mday, edit_referential_time_table_path(@referential, @time_table) ), {class: "day overlaped_date"}]
- - elsif @time_table.include_in_dates?(d)
- - [link_to(d.mday, edit_referential_time_table_path(@referential, @time_table) ), {class: "day selected_date"}]
- - elsif @time_table.include_in_periods?(d)
- - [link_to(d.mday, edit_referential_time_table_path(@referential, @time_table) ), {class: "day selected_period"}]
-
- = cal.html_safe
-
- #time_tables_datas.tab-pane
- .summary
- p
- label = "#{@time_table.human_attribute_name('version')} : "
- = @time_table.version
-
- p
- label = "#{@time_table.human_attribute_name('day_types')} : "
- - if @time_table.int_day_types & 508 == 0
- label = "#{@time_table.human_attribute_name('none')} : "
- - else
- - %w(monday tuesday wednesday thursday friday saturday sunday).each do |day_type|
- span class="#{@time_table.send(day_type) ? 'included_day_type' :'excluded_day_type'}"
- = @time_table.human_attribute_name(day_type)
-
- - if @time_table.periods.present?
- h3.time_table_periods = @time_table.human_attribute_name("periods")
- .periods.content
- == render 'time_tables/periods'
-
- - if @time_table.dates.where("in_out = true").present?
- h3.time_table_dates = @time_table.human_attribute_name("dates")
- .dates.content
- == render "time_tables/dates"
-
- - if @time_table.dates.where("in_out = false").present?
- h3.time_table_dates = @time_table.human_attribute_name("excluded_dates")
- .excluded_dates.content
- == render "time_tables/excluded_dates"
+.row
+ - (1..12).each do |month|
+ .col-lg-3.col-md-4.col-sm-4.col-xs-6
+ = new_alt_calendar(year: @year, month: month, first_day_of_week: 1, calendar_title: "#{I18n.t("date.month_names")[month]}", show_today: false) do |d|
+ / - if @time_table.excluded_date?(d)
+ / - [link_to(d.mday, edit_referential_time_table_path(@referential, @time_table) ), {class: "day excluded_date"}]
+ - if @time_table.include_in_overlap_dates?(d)
+ - [link_to(d.mday, edit_referential_time_table_path(@referential, @time_table) ), {class: "day overlaped_date", title: 'Voir'}]
+ - elsif @time_table.include_in_dates?(d)
+ - [link_to(d.mday, edit_referential_time_table_path(@referential, @time_table) ), {class: "day selected_date", title: 'Voir'}]
+ - elsif @time_table.include_in_periods?(d)
+ - [link_to(d.mday, edit_referential_time_table_path(@referential, @time_table) ), {class: "day selected_period", title: 'Voir'}]
+
+/ .row
+/ .col-lg-12
+/ / wip
+/ - if @time_table.dates.where("in_out = true").present?
+/ h3.time_table_dates = @time_table.human_attribute_name("dates")
+/ .dates.content
+/ == render "time_tables/dates"
+/
+/ - if @time_table.dates.where("in_out = false").present?
+/ h3.time_table_dates = @time_table.human_attribute_name("excluded_dates")
+/ .excluded_dates.content
+/ == render "time_tables/excluded_dates"
diff --git a/app/views/time_tables/edit.html.slim b/app/views/time_tables/edit.html.slim
index 1746b48c7..7f4cd18df 100644
--- a/app/views/time_tables/edit.html.slim
+++ b/app/views/time_tables/edit.html.slim
@@ -1,3 +1,12 @@
-= title_tag t('time_tables.edit.title', :time_table => @time_table.comment)
+/ PageHeader
+= pageheader 'map-marker',
+ @time_table.comment,
+ '',
+ ''
-== render 'form' \ No newline at end of file
+/ PageContent
+.page_content
+ .container-fluid
+ #periods
+
+= javascript_include_tag 'es6_browserified/time_tables/index.js'
diff --git a/app/views/time_tables/index.html.slim b/app/views/time_tables/index.html.slim
index 64d2372a5..65d0787e8 100644
--- a/app/views/time_tables/index.html.slim
+++ b/app/views/time_tables/index.html.slim
@@ -1,37 +1,51 @@
-= title_tag t('time_tables.index.title')
-
-= search_form_for @q, :url => referential_time_tables_path(@referential), remote: true, :html => {:method => :get, class: "form-inline", :id => "search", role: "form"} do |f|
- .panel.panel-default
- .panel-heading
- .input-group.col-md-9
- = f.text_field :comment_cont, :placeholder => "#{t('.comment')}", class: 'form-control'
-
- .input-group-btn
- button.btn.btn-default type="submit"
- i.fa.fa-search
-
- a data-toggle="collapse" data-parent="#search" href="#advanced_search"
- i.fa.fa-plus
- = "#{t('.advanced_search')}"
-
- #advanced_search.panel-collapse.collapse
- .panel-body
- div
- label = "#{t('.from')}"
- = f.text_field :start_date_gteq, :placeholder => "#{t('.start_date')}", class: 'form-control date_picker', :type => "date"
-
- label = "#{t('.to')}"
- = f.text_field :end_date_lteq, :placeholder => "#{t('.end_date')}", class: 'form-control date_picker', :type => "date"
-
- div
- = f.text_field :tag_search, :placeholder => "#{t('.tag_search')}", class: 'form-control'
-
-#time_tables
- == render 'time_tables'
-
-- content_for :sidebar do
- ul.actions
- li
- - if policy(Chouette::TimeTable).create? && @referential.organisation == current_organisation
- = link_to t('time_tables.actions.new'), new_referential_time_table_path(@referential), class: "add"
- br
+/ PageHeader
+= pageheader 'map-marker',
+ t('time_tables.index.title'),
+ '',
+ ((policy(Chouette::TimeTable).create? && @referential.organisation == current_organisation) ? link_to(t('actions.add'), new_referential_time_table_path(@referential), class: 'btn btn-default') : '')
+
+/ PageContent
+.page_content
+ .container-fluid
+ .row
+ .col-lg-12
+ = search_form_for @q, url: referential_time_tables_path(@referential), html: { method: :get, class: 'form form-filter' } do |f|
+ .ffg-row
+ .input-group.search_bar
+ = f.text_field :comment_cont, :placeholder => "#{t('.comment')}", class: 'form-control'
+ span.input-group-btn
+ button.btn.btn-default type='submit'
+ span.fa.fa-search
+
+ .ffg-row
+ .form-group
+ = f.label @time_tables.human_attribute_name(:tag_search), required: false, class: 'control-label'
+ = f.input :tag_search, as: :tags, collection: Chouette::TimeTable.tags_on(:tags).pluck(:name), label: false, input_html: { 'data-select2ed': 'true', 'data-select2ed-placeholder': 'Indiquez une étiquette...' }, wrapper_html: { class: 'select2ed'}, include_blank: false
+
+ .form-group.togglable
+ = f.label @time_tables.human_attribute_name(:bounding_dates), required: false, class: 'control-label'
+ .filter_menu
+ = f.input :start_date_gteq, as: :date, label: t('simple_form.from'), wrapper_html: { class: 'date filter_menu-item' }
+ = f.input :end_date_lteq, as: :date, label: t('simple_form.to'), wrapper_html: { class: 'date filter_menu-item' }
+
+
+ .actions
+ = link_to 'Effacer', @workbench, class: 'btn btn-link'
+ = f.submit 'Filtrer', class: 'btn btn-default'
+
+ - if @time_tables.any?
+ .row
+ .col-lg-12
+ = table_builder @time_tables,
+ { :comment => 'comment', :color => Proc.new{|tt| tt.color ? content_tag(:span, '', class: 'fa fa-circle', style: "color:#{tt.color}") : '-' },
+ "Période de validité englobante" => Proc.new{ |tt| tt.bounding_dates.empty? ? '-' : t('bounding_dates', debut: l(tt.bounding_dates.min), end: l(tt.bounding_dates.max)) }, :calendar => Proc.new{ |tt| tt.calendar ? tt.calendar.try(:name) : '-' }, :updated_at => Proc.new {|tt| l(tt.updated_at, format: :short)} },
+ [:show, :edit, :duplicate, :delete],
+ [],
+ 'table has-search'
+
+ = new_pagination @time_tables, 'pull-right'
+
+ - unless @time_tables.any?
+ .row.mt-xs
+ .col-lg-12
+ = replacement_msg t('time_tables.search_no_results')
diff --git a/app/views/time_tables/index.js.slim b/app/views/time_tables/index.js.slim
deleted file mode 100644
index bc9585c4b..000000000
--- a/app/views/time_tables/index.js.slim
+++ /dev/null
@@ -1 +0,0 @@
-| $('#time_tables').html("#{escape_javascript(render('time_tables'))}"); \ No newline at end of file
diff --git a/app/views/time_tables/index.json.rabl b/app/views/time_tables/index.json.rabl
deleted file mode 100644
index 443cb13a2..000000000
--- a/app/views/time_tables/index.json.rabl
+++ /dev/null
@@ -1,9 +0,0 @@
-collection @time_tables, :object_root => false
-
-node do |time_table|
- { :id => time_table.id, :comment => time_table.comment,
- :time_table_bounding => time_table_bounding( time_table),
- :composition_info => composition_info(time_table),
- :tags => time_table.tags.join(','),
- :day_types => %w(monday tuesday wednesday thursday friday saturday sunday).select{ |d| time_table.send(d) }.map{ |d| time_table.human_attribute_name(d).first(2)}.join('')}
-end
diff --git a/app/views/time_tables/index.rabl b/app/views/time_tables/index.rabl
new file mode 100644
index 000000000..d8b7c6e0c
--- /dev/null
+++ b/app/views/time_tables/index.rabl
@@ -0,0 +1,2 @@
+collection @time_tables, :object_root => false
+extends "time_tables/show"
diff --git a/app/views/time_tables/month.rabl b/app/views/time_tables/month.rabl
new file mode 100644
index 000000000..5b8b67f6c
--- /dev/null
+++ b/app/views/time_tables/month.rabl
@@ -0,0 +1,9 @@
+object @time_table
+
+node do |tt|
+ {
+ name: I18n.l(@date, format: '%B'),
+ days: tt.month_inspect(@date),
+ day_types: %w(monday tuesday wednesday thursday friday saturday sunday).select{ |d| tt.send(d) }.map{ |d| tt.human_attribute_name(d).first(2)}.join('')
+ }
+end
diff --git a/app/views/time_tables/new.html.slim b/app/views/time_tables/new.html.slim
index bc15f7032..8770a59b2 100644
--- a/app/views/time_tables/new.html.slim
+++ b/app/views/time_tables/new.html.slim
@@ -1,3 +1,12 @@
-= title_tag t('time_tables.new.title')
+/ PageHeader
+= pageheader 'map-marker',
+ t('time_tables.new.title'),
+ '',
+ ''
-== render 'form' \ No newline at end of file
+/ PageContent
+.page_content
+ .container-fluid
+ .row
+ .col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1
+ == render 'form'
diff --git a/app/views/time_tables/show.html.slim b/app/views/time_tables/show.html.slim
index 436886faa..6e6833cf4 100644
--- a/app/views/time_tables/show.html.slim
+++ b/app/views/time_tables/show.html.slim
@@ -1,27 +1,51 @@
- require 'calendar_helper'
-= title_tag t('time_tables.show.title', :time_table => @time_table.comment )
+/ PageHeader
+= pageheader 'map-marker',
+ @time_table.comment,
+ '',
+ (policy(@time_table).edit? ? link_to(t('actions.edit'), edit_referential_time_table_path(@referential, @time_table), class: 'btn btn-default') : '')
-== render 'time_table_combinations/combine'
+ / Below is secundary actions & optional contents (filters, ...)
+ .row.mb-sm
+ .col-lg-12.text-right
+ / - if policy(@time_table).create? && @referential.organisation == current_organisation
+ / = link_to t('time_tables.actions.new'), new_referential_time_table_path(@referential), class: 'btn btn-primary'
-== render 'show_time_table'
+ /- if policy(@time_table).create? && @referential.organisation == current_organisation
+ = link_to t('actions.combine'), new_referential_time_table_time_table_combination_path(@referential, @time_table), {remote: true, 'data-toggle' => "modal", 'data-target' => '#modal_combine', class: 'btn btn-primary' }
-- content_for :sidebar do
- ul.actions
- li
- if policy(@time_table).create? && @referential.organisation == current_organisation
- = link_to t('time_tables.actions.new'), new_referential_time_table_path(@referential), class: 'add'
- li
- - if policy(@time_table).edit?
- = link_to t('time_tables.actions.edit'), edit_referential_time_table_path(@referential, @time_table), class: "edit"
- li
+ = link_to t('actions.clone'), duplicate_referential_time_table_path(@referential, @time_table), class: 'btn btn-primary'
+
- if policy(@time_table).destroy?
- = link_to t('time_tables.actions.destroy'), referential_time_table_path(@referential, @time_table), :method => :delete, :data => {:confirm => t('time_tables.actions.destroy_confirm')}, class: "remove"
- li
- - if policy(@time_table).create? && @referential.organisation == current_organisation
- = link_to t('time_tables.actions.duplicate'), duplicate_referential_time_table_path(@referential, @time_table), class: "clone"
- li
- /- if policy(@time_table).create? && @referential.organisation == current_organisation
- = link_to t('time_tables.actions.combine'), new_referential_time_table_time_table_combination_path(@referential, @time_table), {:remote => true, 'data-toggle' => "modal", 'data-target' => '#modal_combine', class: "merge"}
+ = link_to referential_time_table_path(@referential, @time_table), method: :delete, data: {confirm: t('time_tables.actions.destroy_confirm')}, class: 'btn btn-primary' do
+ span.fa.fa-trash
+ span = t('actions.destroy')
+
+/ PageContent
+.page_content
+ .container-fluid
+ .row
+ .col-lg-6.col-md-6.col-sm-12.col-xs-12
+ = definition_list t('metadatas'),
+ { "Période d'application" => (@time_table.bounding_dates.empty? ? '-' : t('bounding_dates', debut: l(@time_table.bounding_dates.min), end: l(@time_table.bounding_dates.max))),
+ 'Couleur associée' => content_tag(:span, '', class: 'fa fa-circle', style: "color:#{@time_table.try(:color)}"),
+ 'Etiquettes' => @time_table.tag_list,
+ 'Modèle de calendrier' => (@time_table.calendar ? link_to(@time_table.calendar.name, @time_table.calendar) : '-'),
+ "Journées d'application pour les périodes ci-dessous" => %w(monday tuesday wednesday thursday friday saturday sunday).collect{ |d| content_tag(:span, t("calendars.days.#{d}"), class: "label label-default #{@time_table.send(d) ? '' : 'disabled'}") }.join.html_safe }
+
+ .row
+ .col-lg-12.mb-sm
+ .pagination.pull-right
+ = @year
+ .page_links
+ = link_to '', referential_time_table_path(@referential, @time_table, year: (@year - 1)), class: 'previous_page'
+ = link_to '', referential_time_table_path(@referential, @time_table, year: (@year + 1)), class: 'next_page'
+
+ = render 'show_time_table'
- = creation_tag(@time_table)
+ .row
+ .col-lg-12
+ / WTF ??!
+ = render 'time_table_combinations/combine'
diff --git a/app/views/time_tables/show.rabl b/app/views/time_tables/show.rabl
new file mode 100644
index 000000000..a0a799985
--- /dev/null
+++ b/app/views/time_tables/show.rabl
@@ -0,0 +1,26 @@
+object @time_table
+
+attributes :id, :comment
+node do |tt|
+ {
+ time_table_bounding: tt.presenter.time_table_bounding,
+ tags: tt.tags.map{ |tag| {id: tag.id, name: tag.name}},
+ day_types: %w(monday tuesday wednesday thursday friday saturday sunday).select{ |d| tt.send(d) }.map{ |d| tt.human_attribute_name(d).first(2)}.join(''),
+ current_month: tt.month_inspect(Date.today),
+ periode_range: month_periode_enum(3),
+ current_periode_range: Date.today.beginning_of_month,
+ color: tt.color ? tt.color : ''
+ }
+end
+
+child(:periods, object_root: false) do
+ attributes :id, :period_start, :period_end
+end
+
+child(:dates, object_root: false) do
+ attributes :id, :date, :in_out
+end
+
+child(:calendar) do
+ attributes :id, :name
+end
diff --git a/app/views/vehicle_journeys/_form.html.slim b/app/views/vehicle_journeys/_form.html.slim
index c738b8b00..ca200a5f7 100644
--- a/app/views/vehicle_journeys/_form.html.slim
+++ b/app/views/vehicle_journeys/_form.html.slim
@@ -2,7 +2,7 @@
== render 'shared/form_messages', { errors: vehicle_journey.errors }
= form.inputs do
- = form.input :journey_pattern, as: :select, :collection => @route.journey_patterns, :member_label => Proc.new { |jp| journey_name(jp) }
+ = form.input :journey_pattern, as: :select, collection: route_journey_pattern_label_pairs(@route)
= form.input :number
= form.input :published_journey_name
= form.input :published_journey_identifier
diff --git a/app/views/vehicle_journeys/show.rabl b/app/views/vehicle_journeys/show.rabl
index 86edfafa8..6b7608342 100644
--- a/app/views/vehicle_journeys/show.rabl
+++ b/app/views/vehicle_journeys/show.rabl
@@ -8,6 +8,12 @@ child(:company) do |company|
attributes :id, :objectid, :name
end
+child(:route) do |route|
+ child(:line) do |line|
+ attributes :transport_mode, :transport_submode
+ end
+end
+
child(:journey_pattern) do |journey_pattern|
attributes :id, :objectid, :name, :published_name
end
@@ -29,6 +35,9 @@ child(:vehicle_journey_at_stops_matrix, :object_root => false) do |vehicle_stops
node(:stop_area_object_id) do
vehicle_stop.stop_point ? vehicle_stop.stop_point.stop_area.objectid : nil
end
+ node(:stop_point_objectid) do
+ vehicle_stop.stop_point ? vehicle_stop.stop_point.objectid : nil
+ end
node(:stop_area_name) do
vehicle_stop.stop_point ? vehicle_stop.stop_point.stop_area.name : nil
end
diff --git a/app/views/workbenches/show.html.slim b/app/views/workbenches/show.html.slim
index 2d13501b7..1025c1658 100644
--- a/app/views/workbenches/show.html.slim
+++ b/app/views/workbenches/show.html.slim
@@ -7,7 +7,9 @@
/ Below is secundary actions & optional contents (filters, ...)
.row.mb-sm
.col-lg-12.text-right
- = link_to t('referentials.actions.new'), new_referential_path(workbench_id: @workbench), class: 'btn btn-primary'
+ = link_to Import.model_name.human.pluralize.capitalize, workbench_imports_path(@workbench), class: 'btn btn-primary'
+ - if policy(Referential).create?
+ = link_to t('referentials.actions.new'), new_referential_path(workbench_id: @workbench), class: 'btn btn-primary'
/ PageContent
.page_content
diff --git a/app/workers/referential_cloning_worker.rb b/app/workers/referential_cloning_worker.rb
index dda569d7c..ef3acd529 100644
--- a/app/workers/referential_cloning_worker.rb
+++ b/app/workers/referential_cloning_worker.rb
@@ -1,24 +1,33 @@
class ReferentialCloningWorker
include Sidekiq::Worker
+ sidekiq_options queue: 'wip'
+ # Replace default apartment created schema with clone schema from source referential
def perform(id)
- # Replace default apartment created schema with clone schema from source referential
ref_cloning = ReferentialCloning.find id
- sql_func = "CREATE OR REPLACE FUNCTION clone_schema( source_schema text, dest_schema text, include_recs boolean) RETURNS void AS $BODY$ DECLARE src_oid oid; tbl_oid oid; func_oid oid; object text; buffer text; srctbl text; default_ text; column_ text; qry text; dest_qry text; v_def text; seqval bigint; sq_last_value bigint; sq_max_value bigint; sq_start_value bigint; sq_increment_by bigint; sq_min_value bigint; sq_cache_value bigint; sq_log_cnt bigint; sq_is_called boolean; sq_is_cycled boolean; sq_cycled char(10); BEGIN SELECT oid INTO src_oid FROM pg_namespace WHERE nspname = quote_ident(source_schema); IF NOT FOUND THEN RAISE NOTICE 'source schema % does not exist!', source_schema; RETURN ; END IF; PERFORM nspname FROM pg_namespace WHERE nspname = quote_ident(dest_schema); IF FOUND THEN RAISE NOTICE 'dest schema % already exists!', dest_schema; RETURN ; END IF; EXECUTE 'CREATE SCHEMA ' || quote_ident(dest_schema) ; FOR object IN SELECT sequence_name::text FROM information_schema.sequences WHERE sequence_schema = quote_ident(source_schema) LOOP EXECUTE 'CREATE SEQUENCE ' || quote_ident(dest_schema) || '.' || quote_ident(object); srctbl := quote_ident(source_schema) || '.' || quote_ident(object); EXECUTE 'SELECT last_value, max_value, start_value, increment_by, min_value, cache_value, log_cnt, is_cycled, is_called FROM ' || quote_ident(source_schema) || '.' || quote_ident(object) || ';' INTO sq_last_value, sq_max_value, sq_start_value, sq_increment_by, sq_min_value, sq_cache_value, sq_log_cnt, sq_is_cycled, sq_is_called ; IF sq_is_cycled THEN sq_cycled := 'CYCLE'; ELSE sq_cycled := 'NO CYCLE'; END IF; EXECUTE 'ALTER SEQUENCE ' || quote_ident(dest_schema) || '.' || quote_ident(object) || ' INCREMENT BY ' || sq_increment_by || ' MINVALUE ' || sq_min_value || ' MAXVALUE ' || sq_max_value || ' START WITH ' || sq_start_value || ' RESTART ' || sq_min_value || ' CACHE ' || sq_cache_value || sq_cycled || ' ;' ; buffer := quote_ident(dest_schema) || '.' || quote_ident(object); IF include_recs THEN EXECUTE 'SELECT setval( ''' || buffer || ''', ' || sq_last_value || ', ' || sq_is_called || ');' ; ELSE EXECUTE 'SELECT setval( ''' || buffer || ''', ' || sq_start_value || ', ' || sq_is_called || ');' ; END IF; END LOOP; FOR object IN SELECT TABLE_NAME::text FROM information_schema.tables WHERE table_schema = quote_ident(source_schema) AND table_type = 'BASE TABLE' LOOP buffer := dest_schema || '.' || quote_ident(object); EXECUTE 'CREATE TABLE ' || buffer || '(LIKE ' || quote_ident(source_schema) || '.' || quote_ident(object) || ' INCLUDING ALL)'; IF include_recs THEN EXECUTE 'INSERT INTO ' || buffer || ' SELECT * FROM ' || quote_ident(source_schema) || '.' || quote_ident(object) || ';'; END IF; FOR column_, default_ IN SELECT column_name::text, REPLACE(column_default::text, source_schema, dest_schema) FROM information_schema.COLUMNS WHERE table_schema = dest_schema AND TABLE_NAME = object AND column_default LIKE 'nextval(%' || quote_ident(source_schema) || '%::regclass)' LOOP EXECUTE 'ALTER TABLE ' || buffer || ' ALTER COLUMN ' || column_ || ' SET DEFAULT ' || default_; END LOOP; END LOOP; FOR qry IN SELECT 'ALTER TABLE ' || quote_ident(dest_schema) || '.' || quote_ident(rn.relname) || ' ADD CONSTRAINT ' || quote_ident(ct.conname) || ' ' || pg_get_constraintdef(ct.oid) || ';' FROM pg_constraint ct JOIN pg_class rn ON rn.oid = ct.conrelid WHERE connamespace = src_oid AND rn.relkind = 'r' AND ct.contype = 'f' LOOP EXECUTE qry; END LOOP; FOR object IN SELECT table_name::text, view_definition FROM information_schema.views WHERE table_schema = quote_ident(source_schema) LOOP buffer := dest_schema || '.' || quote_ident(object); SELECT view_definition INTO v_def FROM information_schema.views WHERE table_schema = quote_ident(source_schema) AND table_name = quote_ident(object); EXECUTE 'CREATE OR REPLACE VIEW ' || buffer || ' AS ' || v_def || ';' ; END LOOP; FOR func_oid IN SELECT oid FROM pg_proc WHERE pronamespace = src_oid LOOP SELECT pg_get_functiondef(func_oid) INTO qry; SELECT replace(qry, source_schema, dest_schema) INTO dest_qry; EXECUTE dest_qry; END LOOP; RETURN; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100;"
- sql_clone = "SELECT clone_schema('#{ref_cloning.source_referential.slug}', '#{ref_cloning.target_referential.slug}_tmp', TRUE);"
- sql_drop = "DROP SCHEMA #{ref_cloning.target_referential.slug} CASCADE;"
- sql_rename = "ALTER SCHEMA #{ref_cloning.target_referential.slug}_tmp RENAME TO #{ref_cloning.target_referential.slug};"
+
+ source_schema = ref_cloning.source_referential.slug
+ target_schema = "#{source_schema}_tmp"
+
+ clone_schema ref_cloning, source_schema, target_schema
+ end
+
+ private
+
+ def clone_schema ref_cloning, source_schema, target_schema
ref_cloning.run!
- begin
- ActiveRecord::Base.connection.execute sql_func
- ActiveRecord::Base.connection.execute sql_clone
- ActiveRecord::Base.connection.execute sql_drop
- ActiveRecord::Base.connection.execute sql_rename
- ref_cloning.successful!
- rescue Exception => e
- Rails.logger.error "ReferentialCloningWorker : #{e}"
- ref_cloning.failed!
- end
+ StoredProcedures.invoke_stored_procedure(:clone_schema, source_schema, target_schema, true)
+ execute_sql "DROP SCHEMA #{source_schema} CASCADE;"
+ execute_sql "ALTER SCHEMA #{target_schema} RENAME TO #{source_schema};"
+
+ ref_cloning.successful!
+ rescue Exception => e
+ Rails.logger.error "ReferentialCloningWorker : #{e}"
+ ref_cloning.failed!
+ end
+
+ def execute_sql sql
+ ActiveRecord::Base.connection.execute sql
end
end