aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/smart_date.coffee13
-rw-r--r--app/assets/stylesheets/components/_compliance_control_blocks.sass3
-rw-r--r--app/controllers/api/v1/netex_imports_controller.rb3
-rw-r--r--app/controllers/application_controller.rb12
-rw-r--r--app/controllers/clean_ups_controller.rb10
-rw-r--r--app/controllers/companies_controller.rb1
-rw-r--r--app/controllers/compliance_control_blocks_controller.rb8
-rw-r--r--app/controllers/concerns/metadata_controller_support.rb2
-rw-r--r--app/controllers/journey_patterns_collections_controller.rb2
-rw-r--r--app/controllers/line_referentials_controller.rb6
-rw-r--r--app/controllers/lines_controller.rb4
-rw-r--r--app/controllers/merges_controller.rb2
-rw-r--r--app/controllers/referential_companies_controller.rb13
-rw-r--r--app/controllers/routing_constraint_zones_controller.rb17
-rw-r--r--app/controllers/stop_area_referentials_controller.rb7
-rw-r--r--app/controllers/stop_areas_controller.rb15
-rw-r--r--app/controllers/time_tables_controller.rb14
-rw-r--r--app/controllers/vehicle_journeys_collections_controller.rb4
-rw-r--r--app/controllers/vehicle_journeys_controller.rb7
-rw-r--r--app/decorators/line_decorator.rb5
-rw-r--r--app/decorators/line_referential_decorator.rb13
-rw-r--r--app/decorators/stop_area_referential_decorator.rb13
-rw-r--r--app/helpers/line_referential_syncs_helper.rb31
-rw-r--r--app/helpers/multiple_selection_toolbox_helper.rb7
-rw-r--r--app/helpers/referentials_helper.rb7
-rw-r--r--app/helpers/search_helper.rb2
-rw-r--r--app/helpers/stop_area_referential_syncs_helper.rb31
-rw-r--r--app/helpers/stop_areas_helper.rb2
-rw-r--r--app/inputs/full_time_zone_input.rb24
-rw-r--r--app/javascript/helpers/CustomFieldsInputs.js (renamed from app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js)19
-rw-r--r--app/javascript/helpers/polyfills.js4
-rw-r--r--app/javascript/journey_patterns/actions/index.js18
-rw-r--r--app/javascript/journey_patterns/components/CreateModal.js10
-rw-r--r--app/javascript/journey_patterns/components/EditModal.js34
-rw-r--r--app/javascript/journey_patterns/containers/AddJourneyPattern.js3
-rw-r--r--app/javascript/journey_patterns/containers/Modal.js3
-rw-r--r--app/javascript/journey_patterns/reducers/index.js3
-rw-r--r--app/javascript/journey_patterns/reducers/journeyPatterns.js3
-rw-r--r--app/javascript/packs/calendars/edit.js2
-rw-r--r--app/javascript/packs/exports/new.js2
-rw-r--r--app/javascript/packs/journey_patterns/index.js5
-rw-r--r--app/javascript/packs/referential_lines/show.js2
-rw-r--r--app/javascript/packs/referential_overview/overview.js2
-rw-r--r--app/javascript/packs/routes/edit.js27
-rw-r--r--app/javascript/packs/routes/show.js2
-rw-r--r--app/javascript/packs/stop_areas/new.js2
-rw-r--r--app/javascript/packs/time_tables/edit.js2
-rw-r--r--app/javascript/packs/vehicle_journeys/index.js2
-rw-r--r--app/javascript/routes/actions/index.js7
-rw-r--r--app/javascript/routes/components/App.js9
-rw-r--r--app/javascript/routes/components/BSelect2.js12
-rw-r--r--app/javascript/routes/components/OlMap.js30
-rw-r--r--app/javascript/routes/components/StopPoint.js10
-rw-r--r--app/javascript/routes/components/StopPointList.js2
-rw-r--r--app/javascript/routes/containers/AddStopPoint.js2
-rw-r--r--app/javascript/routes/index.js5
-rw-r--r--app/javascript/routes/reducers/stopPoints.js9
-rw-r--r--app/javascript/time_tables/actions/index.js11
-rw-r--r--app/javascript/time_tables/components/Metas.js1
-rw-r--r--app/javascript/time_tables/components/TagsSelect2.js4
-rw-r--r--app/javascript/time_tables/containers/Metas.js1
-rw-r--r--app/javascript/time_tables/reducers/metas.js6
-rw-r--r--app/javascript/vehicle_journeys/actions/index.js55
-rw-r--r--app/javascript/vehicle_journeys/components/Filters.js1
-rw-r--r--app/javascript/vehicle_journeys/components/Tools.js9
-rw-r--r--app/javascript/vehicle_journeys/components/VehicleJourney.js25
-rw-r--r--app/javascript/vehicle_journeys/components/VehicleJourneys.js18
-rw-r--r--app/javascript/vehicle_journeys/components/tools/ConstraintExclusionEditVehicleJourney.js182
-rw-r--r--app/javascript/vehicle_journeys/components/tools/CreateModal.js5
-rw-r--r--app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js2
-rw-r--r--app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js4
-rw-r--r--app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js3
-rw-r--r--app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js1
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/ConstraintZoneSelect2.js37
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js2
-rw-r--r--app/javascript/vehicle_journeys/containers/VehicleJourneysList.js5
-rw-r--r--app/javascript/vehicle_journeys/containers/tools/ConstraintExclusionEditVehicleJourney.js37
-rw-r--r--app/javascript/vehicle_journeys/reducers/modal.js51
-rw-r--r--app/javascript/vehicle_journeys/reducers/vehicleJourneys.js19
-rw-r--r--app/models/calendar/period.rb2
-rw-r--r--app/models/chouette/area_type.rb8
-rw-r--r--app/models/chouette/journey_pattern.rb50
-rw-r--r--app/models/chouette/line.rb4
-rw-r--r--app/models/chouette/purchase_window.rb16
-rw-r--r--app/models/chouette/route.rb18
-rw-r--r--app/models/chouette/routing_constraint_zone.rb12
-rw-r--r--app/models/chouette/stop_area.rb6
-rw-r--r--app/models/chouette/stop_point.rb5
-rw-r--r--app/models/chouette/time_table.rb7
-rw-r--r--app/models/chouette/trident_active_record.rb6
-rw-r--r--app/models/chouette/vehicle_journey.rb13
-rw-r--r--app/models/clean_up.rb54
-rw-r--r--app/models/compliance_check_message_export.rb2
-rw-r--r--app/models/concerns/checksum_support.rb25
-rw-r--r--app/models/concerns/custom_fields_support.rb46
-rw-r--r--app/models/concerns/line_referential_support.rb4
-rw-r--r--app/models/concerns/metadata_support.rb4
-rw-r--r--app/models/concerns/stop_area_referential_support.rb4
-rw-r--r--app/models/custom_field.rb51
-rw-r--r--app/models/import/gtfs.rb23
-rw-r--r--app/models/import/message_export.rb2
-rw-r--r--app/models/import/netex.rb11
-rw-r--r--app/models/merge.rb121
-rw-r--r--app/models/referential.rb46
-rw-r--r--app/models/referential_cloning.rb5
-rw-r--r--app/models/referential_metadata.rb4
-rw-r--r--app/policies/merge_policy.rb4
-rw-r--r--app/views/api/v1/journey_patterns/show.rabl2
-rw-r--r--app/views/companies/_form.html.slim4
-rw-r--r--app/views/compliance_control_blocks/_form.html.slim6
-rw-r--r--app/views/journey_patterns_collections/show.html.slim3
-rw-r--r--app/views/layouts/application.html.slim6
-rw-r--r--app/views/layouts/devise.html.slim28
-rw-r--r--app/views/layouts/navigation/_main_nav.html.slim6
-rw-r--r--app/views/layouts/navigation/_main_nav_left_content.html.slim64
-rw-r--r--app/views/layouts/navigation/_main_nav_left_content_stif.html.slim196
-rw-r--r--app/views/line_referentials/show.html.slim60
-rw-r--r--app/views/lines/_filters.html.slim10
-rw-r--r--app/views/lines/index.html.slim6
-rw-r--r--app/views/lines/show.html.slim20
-rw-r--r--app/views/referential_companies/_form.html.slim2
-rw-r--r--app/views/referential_companies/edit.html.slim5
-rw-r--r--app/views/referential_lines/show.html.slim4
-rw-r--r--app/views/referential_stop_areas/_form.html.slim2
-rw-r--r--app/views/referential_stop_areas/show.html.slim14
-rw-r--r--app/views/referentials/_period_fields.html.slim4
-rw-r--r--app/views/referentials/show.html.slim4
-rw-r--r--app/views/routes/show.html.slim5
-rw-r--r--app/views/stif/dashboards/_dashboard.html.slim9
-rw-r--r--app/views/stop_area_referentials/show.html.slim54
-rw-r--r--app/views/stop_areas/_filters.html.slim2
-rw-r--r--app/views/stop_areas/_form.html.slim6
-rw-r--r--app/views/stop_areas/index.html.slim2
-rw-r--r--app/views/stop_areas/show.html.slim21
-rw-r--r--app/views/vehicle_journeys/index.html.slim1
-rw-r--r--app/views/vehicle_journeys/show.rabl4
-rw-r--r--app/workers/route_way_cost_worker.rb11
137 files changed, 1548 insertions, 554 deletions
diff --git a/app/assets/javascripts/smart_date.coffee b/app/assets/javascripts/smart_date.coffee
index 48aa1c2f9..9c8b44207 100644
--- a/app/assets/javascripts/smart_date.coffee
+++ b/app/assets/javascripts/smart_date.coffee
@@ -14,11 +14,16 @@ window.isLeapYear = (year) ->
window.smartCorrectDate = ->
allSelectors = $(@).parent().children('select')
- allVals = allSelectors.map (index, sel) ->
- parseInt($(sel).val())
+
+ yearSelect = allSelectors.filter("[name$='(1i)]']")
+ monthSelect = allSelectors.filter("[name$='(2i)]']")
+ daySelect = allSelectors.filter("[name$='(3i)]']")
+ # We expect [day, month, year], so french
+ allVals = [daySelect, monthSelect, yearSelect].map (sel, index) ->
+ parseInt(sel.val())
+
correctedDay = correctDay allVals
- daySelector = allSelectors.first()
- $(daySelector).val(correctedDay)
+ daySelect.val(correctedDay)
$ ->
$(document).on 'change', '.smart_date select', smartCorrectDate
diff --git a/app/assets/stylesheets/components/_compliance_control_blocks.sass b/app/assets/stylesheets/components/_compliance_control_blocks.sass
new file mode 100644
index 000000000..46880075c
--- /dev/null
+++ b/app/assets/stylesheets/components/_compliance_control_blocks.sass
@@ -0,0 +1,3 @@
+#compliance_control_block_form
+ .condition-attributes-errors
+ margin-bottom: 20px
diff --git a/app/controllers/api/v1/netex_imports_controller.rb b/app/controllers/api/v1/netex_imports_controller.rb
index 186ddc35c..2c9caf8fb 100644
--- a/app/controllers/api/v1/netex_imports_controller.rb
+++ b/app/controllers/api/v1/netex_imports_controller.rb
@@ -31,8 +31,7 @@ module Api
def create_netex_import
attributes = netex_import_params.merge creator: "Webservice"
@netex_import = Import::Netex.new attributes
- @netex_import.save!
- @netex_import.create_referential!
+ @netex_import.create_with_referential!
rescue ActiveRecord::RecordInvalid
render json: {errors: @netex_import.errors}, status: 406
finish_action!
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 8b66e6097..7f071a6a4 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base
# Load helpers in rails engine
helper LanguageEngine::Engine.helpers
+ layout :layout_by_resource
def set_locale
# I18n.locale = session[:language] || I18n.default_locale
@@ -56,4 +57,15 @@ class ApplicationController < ActionController::Base
def after_sign_out_path_for(resource_or_scope)
new_user_session_path
end
+
+ private
+
+ def layout_by_resource
+ if devise_controller?
+ "devise"
+ else
+ "application"
+ end
+ end
+
end
diff --git a/app/controllers/clean_ups_controller.rb b/app/controllers/clean_ups_controller.rb
index ec28aa0fc..c25df1a00 100644
--- a/app/controllers/clean_ups_controller.rb
+++ b/app/controllers/clean_ups_controller.rb
@@ -4,12 +4,12 @@ class CleanUpsController < ChouetteController
belongs_to :referential
def create
- clean_up = CleanUp.new(clean_up_params)
- clean_up.referential = @referential
- if clean_up.valid?
- clean_up.save
+ @clean_up = CleanUp.new(clean_up_params)
+ @clean_up.referential = @referential
+ if @clean_up.valid?
+ @clean_up.save
else
- flash[:alert] = clean_up.errors.full_messages.join("<br/>")
+ flash[:alert] = @clean_up.errors.full_messages.join("<br/>")
end
redirect_to referential_path(@referential)
end
diff --git a/app/controllers/companies_controller.rb b/app/controllers/companies_controller.rb
index a09cab783..2c32ed3a5 100644
--- a/app/controllers/companies_controller.rb
+++ b/app/controllers/companies_controller.rb
@@ -37,6 +37,7 @@ class CompaniesController < ChouetteController
protected
+
def collection
scope = line_referential.companies
@q = scope.search(params[:q])
diff --git a/app/controllers/compliance_control_blocks_controller.rb b/app/controllers/compliance_control_blocks_controller.rb
index 1173a548a..0851e2800 100644
--- a/app/controllers/compliance_control_blocks_controller.rb
+++ b/app/controllers/compliance_control_blocks_controller.rb
@@ -4,14 +4,6 @@ class ComplianceControlBlocksController < ChouetteController
belongs_to :compliance_control_set
actions :all, :except => [:show, :index]
- after_action :display_errors, only: [:create, :update]
-
- def display_errors
- unless @compliance_control_block.errors[:condition_attributes].empty?
- flash[:error] = @compliance_control_block.errors[:condition_attributes].join(', ')
- end
- end
-
private
def compliance_control_block_params
diff --git a/app/controllers/concerns/metadata_controller_support.rb b/app/controllers/concerns/metadata_controller_support.rb
index db83e79ae..4dcbfe5d0 100644
--- a/app/controllers/concerns/metadata_controller_support.rb
+++ b/app/controllers/concerns/metadata_controller_support.rb
@@ -20,7 +20,7 @@ module MetadataControllerSupport
def set_modifier_metadata
_resource = @resources || [resource]
_resource.flatten.each do |r|
- r.try :set_metadata!, :modifier_username, user_for_metadata
+ r.try(:set_metadata!, :modifier_username, user_for_metadata) if r.valid?
end
end
end
diff --git a/app/controllers/journey_patterns_collections_controller.rb b/app/controllers/journey_patterns_collections_controller.rb
index db92d48f3..c1a307464 100644
--- a/app/controllers/journey_patterns_collections_controller.rb
+++ b/app/controllers/journey_patterns_collections_controller.rb
@@ -25,6 +25,8 @@ class JourneyPatternsCollectionsController < ChouetteController
@q = @q.includes(:stop_points)
@ppage = 10
@journey_patterns ||= @q.paginate(page: params[:page], per_page: @ppage).order(:name)
+ @custom_fields = Chouette::JourneyPattern.custom_fields_definitions(referential.workgroup)
+
respond_to do |format|
format.json do
@journey_patterns = @journey_patterns.includes(stop_points: {stop_area: :stop_area_referential})
diff --git a/app/controllers/line_referentials_controller.rb b/app/controllers/line_referentials_controller.rb
index 03dab3f8f..e661fbb04 100644
--- a/app/controllers/line_referentials_controller.rb
+++ b/app/controllers/line_referentials_controller.rb
@@ -2,6 +2,12 @@ class LineReferentialsController < ChouetteController
defaults :resource_class => LineReferential
+ def show
+ show! do
+ @line_referential = LineReferentialDecorator.decorate(@line_referential)
+ end
+ end
+
def sync
authorize resource, :synchronize?
@sync = resource.line_referential_syncs.build
diff --git a/app/controllers/lines_controller.rb b/app/controllers/lines_controller.rb
index ae8c9ed0c..cd8091252 100644
--- a/app/controllers/lines_controller.rb
+++ b/app/controllers/lines_controller.rb
@@ -122,7 +122,7 @@ class LinesController < ChouetteController
end
def line_params
- params.require(:line).permit(
+ out = params.require(:line).permit(
:transport_mode,
:network_id,
:company_id,
@@ -148,6 +148,8 @@ class LinesController < ChouetteController
:secondary_company_ids => [],
footnotes_attributes: [:code, :label, :_destroy, :id]
)
+ out[:secondary_company_ids] = (out[:secondary_company_ids] || []).select(&:present?)
+ out
end
# Fake ransack filter
diff --git a/app/controllers/merges_controller.rb b/app/controllers/merges_controller.rb
index 1ce64ed58..663b6e750 100644
--- a/app/controllers/merges_controller.rb
+++ b/app/controllers/merges_controller.rb
@@ -1,5 +1,5 @@
class MergesController < ChouetteController
- # include PolicyChecker
+ include PolicyChecker
defaults resource_class: Merge
belongs_to :workbench
diff --git a/app/controllers/referential_companies_controller.rb b/app/controllers/referential_companies_controller.rb
index 200e56a89..4f73c4268 100644
--- a/app/controllers/referential_companies_controller.rb
+++ b/app/controllers/referential_companies_controller.rb
@@ -18,6 +18,10 @@ class ReferentialCompaniesController < ChouetteController
@companies = decorate_companies(@companies)
}
+ format.json {
+ render json: companies_maps
+ }
+
format.js {
@companies = decorate_companies(@companies)
}
@@ -85,4 +89,13 @@ class ReferentialCompaniesController < ChouetteController
)
end
+ def companies_maps
+ @companies.collect do |company|
+ { :id => company.id.to_s,
+ :objectid => company.raw_objectid,
+ :name => company.name,
+ }
+ end
+ end
+
end
diff --git a/app/controllers/routing_constraint_zones_controller.rb b/app/controllers/routing_constraint_zones_controller.rb
index 47df211d0..886247e79 100644
--- a/app/controllers/routing_constraint_zones_controller.rb
+++ b/app/controllers/routing_constraint_zones_controller.rb
@@ -13,13 +13,16 @@ class RoutingConstraintZonesController < ChouetteController
def index
index! do |format|
- @routing_constraint_zones = RoutingConstraintZoneDecorator.decorate(
- @routing_constraint_zones,
- context: {
- referential: referential,
- line: parent
- }
- )
+ format.html do
+ @routing_constraint_zones = RoutingConstraintZoneDecorator.decorate(
+ @routing_constraint_zones,
+ context: {
+ referential: referential,
+ line: parent
+ }
+ )
+ end
+ format.json
end
end
diff --git a/app/controllers/stop_area_referentials_controller.rb b/app/controllers/stop_area_referentials_controller.rb
index f2d375e49..0e6a54b49 100644
--- a/app/controllers/stop_area_referentials_controller.rb
+++ b/app/controllers/stop_area_referentials_controller.rb
@@ -1,6 +1,13 @@
class StopAreaReferentialsController < ChouetteController
defaults :resource_class => StopAreaReferential
+
+ def show
+ show! do
+ @stop_area_referential = StopAreaReferentialDecorator.decorate(@stop_area_referential)
+ end
+ end
+
def sync
authorize resource, :synchronize?
@sync = resource.stop_area_referential_syncs.build
diff --git a/app/controllers/stop_areas_controller.rb b/app/controllers/stop_areas_controller.rb
index b2634467d..734152c64 100644
--- a/app/controllers/stop_areas_controller.rb
+++ b/app/controllers/stop_areas_controller.rb
@@ -126,7 +126,18 @@ class StopAreasController < ChouetteController
if sort_column && sort_direction
@stop_areas ||=
begin
- stop_areas = @q.result.order(sort_column + ' ' + sort_direction)
+ if sort_column == "area_type"
+ sorted_area_type_labels = Chouette::AreaType.options(:all, I18n.locale).sort.transpose.last
+ sorted_area_type_labels = sorted_area_type_labels.reverse if sort_direction != 'asc'
+ order_by = ["CASE"]
+ sorted_area_type_labels.each_with_index do |area_type, index|
+ order_by << "WHEN area_type='#{area_type}' THEN #{index}"
+ end
+ order_by << "END"
+ stop_areas = @q.result.order(order_by.join(" "))
+ else
+ stop_areas = @q.result.order(sort_column + ' ' + sort_direction)
+ end
stop_areas = stop_areas.paginate(:page => params[:page], :per_page => @per_page) if @per_page.present?
stop_areas
end
@@ -192,7 +203,7 @@ class StopAreasController < ChouetteController
:kind,
:status,
localized_names: Chouette::StopArea::AVAILABLE_LOCALIZATIONS
- ] + permitted_custom_fields_params(Chouette::StopArea.custom_fields) # XXX filter on the workgroup
+ ] + permitted_custom_fields_params(Chouette::StopArea.custom_fields(stop_area_referential.workgroup))
params.require(:stop_area).permit(fields)
end
diff --git a/app/controllers/time_tables_controller.rb b/app/controllers/time_tables_controller.rb
index 2ac8532e0..4ca2293f0 100644
--- a/app/controllers/time_tables_controller.rb
+++ b/app/controllers/time_tables_controller.rb
@@ -77,7 +77,7 @@ class TimeTablesController < ChouetteController
end
def index
- request.format.kml? ? @per_page = nil : @per_page = 12
+ # request.format.kml? ? @per_page = nil : @per_page = 12
index! do |format|
format.html {
@@ -130,6 +130,7 @@ class TimeTablesController < ChouetteController
@time_tables ||= begin
time_tables = @q.result(:distinct => true)
+ sort_column
if sort_column == "bounding_dates"
time_tables = @q.result(:distinct => false).paginate(page: params[:page], per_page: 10)
ids = time_tables.pluck(:id).uniq
@@ -186,10 +187,13 @@ class TimeTablesController < ChouetteController
private
def sort_column
- valid_cols = referential.time_tables.column_names
- valid_cols << "bounding_dates"
- valid_cols << "vehicle_journeys_count"
- valid_cols.include?(params[:sort]) ? params[:sort] : 'comment'
+ @@valid_cols ||= begin
+ valid_cols = %w(id color comment)
+ valid_cols << "bounding_dates"
+ valid_cols << "vehicle_journeys_count"
+ valid_cols
+ end
+ @@valid_cols.include?(params[:sort]) ? params[:sort] : 'comment'
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
diff --git a/app/controllers/vehicle_journeys_collections_controller.rb b/app/controllers/vehicle_journeys_collections_controller.rb
index 712bcc154..a117888ab 100644
--- a/app/controllers/vehicle_journeys_collections_controller.rb
+++ b/app/controllers/vehicle_journeys_collections_controller.rb
@@ -9,8 +9,8 @@ class VehicleJourneysCollectionsController < ChouetteController
alias_method :route, :parent
def update
- state = JSON.parse request.raw_post
- Chouette::VehicleJourney.state_update route, state
+ state = JSON.parse request.raw_post
+ @resources = Chouette::VehicleJourney.state_update route, state
errors = state.any? {|item| item['errors']}
respond_to do |format|
diff --git a/app/controllers/vehicle_journeys_controller.rb b/app/controllers/vehicle_journeys_controller.rb
index 220f2d29e..95eec7517 100644
--- a/app/controllers/vehicle_journeys_controller.rb
+++ b/app/controllers/vehicle_journeys_controller.rb
@@ -208,11 +208,12 @@ class VehicleJourneysController < ChouetteController
short_id: item.get_objectid.short_id,
full_schedule: item.full_schedule?,
costs: item.costs,
- stop_area_short_descriptions: item.stop_areas.map do |stop|
+ journey_length: item.journey_length,
+ stop_area_short_descriptions: item.stop_points.map do |stop|
{
stop_area_short_description: {
- id: stop.id,
- name: stop.name,
+ id: stop.stop_area_id,
+ name: stop.stop_area.name,
object_id: item.objectid
}
}
diff --git a/app/decorators/line_decorator.rb b/app/decorators/line_decorator.rb
index 0e7b6b9ae..077978c36 100644
--- a/app/decorators/line_decorator.rb
+++ b/app/decorators/line_decorator.rb
@@ -35,11 +35,6 @@ class LineDecorator < AF83::Decorator
edit_action_link do |l|
l.content {|l| l.primary? ? h.t('actions.edit') : h.t('lines.actions.edit') }
end
-
- action_link on: :index, secondary: :index do |l|
- l.content t('lines.actions.new')
- l.href { h.new_line_referential_line_path(context[:line_referential]) }
- end
end
### the option :policy will automatically check for the corresponding method
diff --git a/app/decorators/line_referential_decorator.rb b/app/decorators/line_referential_decorator.rb
new file mode 100644
index 000000000..1ca0312c3
--- /dev/null
+++ b/app/decorators/line_referential_decorator.rb
@@ -0,0 +1,13 @@
+class LineReferentialDecorator < AF83::Decorator
+ decorates LineReferential
+
+ with_instance_decorator do |instance_decorator|
+
+ instance_decorator.action_link policy: :synchronize, primary: :show do |l|
+ l.content t('actions.sync')
+ l.href { h. sync_line_referential_path(object.id) }
+ l.method :post
+ end
+
+ end
+end
diff --git a/app/decorators/stop_area_referential_decorator.rb b/app/decorators/stop_area_referential_decorator.rb
new file mode 100644
index 000000000..d30501ec9
--- /dev/null
+++ b/app/decorators/stop_area_referential_decorator.rb
@@ -0,0 +1,13 @@
+class StopAreaReferentialDecorator < AF83::Decorator
+ decorates StopAreaReferential
+
+ with_instance_decorator do |instance_decorator|
+
+ instance_decorator.action_link policy: :synchronize, primary: :show do |l|
+ l.content t('actions.sync')
+ l.href { h. sync_stop_area_referential_path(object.id) }
+ l.method :post
+ end
+
+ end
+end
diff --git a/app/helpers/line_referential_syncs_helper.rb b/app/helpers/line_referential_syncs_helper.rb
new file mode 100644
index 000000000..37f08b154
--- /dev/null
+++ b/app/helpers/line_referential_syncs_helper.rb
@@ -0,0 +1,31 @@
+module LineReferentialSyncsHelper
+
+ def last_line_ref_sync_message(line_ref_sync)
+ line_ref_sync.line_referential_sync_messages.last
+ end
+
+ def line_referential_sync_created_at(line_ref_sync)
+ l(last_line_ref_sync_message(line_ref_sync).created_at, format: :short_with_time)
+ end
+
+ def line_referential_sync_status(line_ref_sync)
+ status = line_ref_sync.status
+
+ if %w[new pending].include? status
+ content_tag :span, '', class: "fa fa-clock-o"
+ else
+ cls =''
+ cls = 'success' if status == 'successful'
+ cls = 'danger' if status == 'failed'
+
+ content_tag :span, '', class: "fa fa-circle text-#{cls}"
+ end
+ end
+
+ def line_referential_sync_message(line_ref_sync)
+ last_line_ref_sync_message = last_line_ref_sync_message(line_ref_sync)
+ data = last_line_ref_sync_message.message_attributes.symbolize_keys!
+ data[:processing_time] = distance_of_time_in_words(data[:processing_time].to_i)
+ t("line_referential_sync.message.#{last_line_ref_sync_message.message_key}", last_line_ref_sync_message.message_attributes.symbolize_keys!).html_safe
+ end
+end
diff --git a/app/helpers/multiple_selection_toolbox_helper.rb b/app/helpers/multiple_selection_toolbox_helper.rb
index 7e02c6d73..012851b4a 100644
--- a/app/helpers/multiple_selection_toolbox_helper.rb
+++ b/app/helpers/multiple_selection_toolbox_helper.rb
@@ -4,7 +4,7 @@ module MultipleSelectionToolboxHelper
# #5206 method too long
def multiple_selection_toolbox(actions, collection_name:)
links = content_tag :ul do
-
+
# #5206 `if params[:controller]` mieux passer comme parametre si besoin
delete_path = nil
@@ -19,8 +19,7 @@ module MultipleSelectionToolboxHelper
method: :delete,
data: {
path: delete_path,
- # #5206 Missing Translations
- confirm: t('actions.are_you_sure')
+ confirm: t('are_you_sure')
},
title: t("actions.#{action}")
) do
@@ -38,7 +37,7 @@ module MultipleSelectionToolboxHelper
class: 'info-msg'
)
- content_tag :div, '',
+ content_tag :div, '',
class: 'select_toolbox noselect',
id: "selected-#{collection_name}-action-box" do
links + label
diff --git a/app/helpers/referentials_helper.rb b/app/helpers/referentials_helper.rb
index 9c3852322..9b5b13ace 100644
--- a/app/helpers/referentials_helper.rb
+++ b/app/helpers/referentials_helper.rb
@@ -2,12 +2,13 @@ module ReferentialsHelper
# Outputs a green check icon and the text "Oui" or a red exclamation mark
# icon and the text "Non" based on `status`
def line_status(status)
- if status
+ case status
+ when :deactivated
content_tag(:span, nil, class: 'fa fa-exclamation-circle fa-lg text-danger') +
- t('activerecord.attributes.line.deactivated')
+ Chouette::Line.tmf('deactivated')
else
content_tag(:span, nil, class: 'fa fa-check-circle fa-lg text-success') +
- t('activerecord.attributes.line.activated')
+ Chouette::Line.tmf('activated')
end
end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index be70d974d..16081b660 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -15,7 +15,7 @@ module SearchHelper
if val.is_a?(Array)
active = val.any? &:present?
elsif val.is_a?(Hash)
- active = val.values.any? &:present?
+ active = val.values.any? {|v| v.present? && v != "false" }
else
active = true
end
diff --git a/app/helpers/stop_area_referential_syncs_helper.rb b/app/helpers/stop_area_referential_syncs_helper.rb
new file mode 100644
index 000000000..3e2837fda
--- /dev/null
+++ b/app/helpers/stop_area_referential_syncs_helper.rb
@@ -0,0 +1,31 @@
+module StopAreaReferentialSyncsHelper
+
+ def last_stop_area_ref_sync_message(stop_area_ref_sync)
+ stop_area_ref_sync.stop_area_referential_sync_messages.last
+ end
+
+ def stop_area_referential_sync_created_at(stop_area_ref_sync)
+ l(last_stop_area_ref_sync_message(stop_area_ref_sync).created_at, format: :short_with_time)
+ end
+
+ def stop_area_referential_sync_status(stop_area_ref_sync)
+ status = stop_area_ref_sync.status
+
+ if %w[new pending].include? status
+ content_tag :span, '', class: "fa fa-clock-o"
+ else
+ cls =''
+ cls = 'success' if status == 'successful'
+ cls = 'danger' if status == 'failed'
+
+ content_tag :span, '', class: "fa fa-circle text-#{cls}"
+ end
+ end
+
+ def stop_area_referential_sync_message(stop_area_ref_sync)
+ last_stop_area_ref_sync_message = last_stop_area_ref_sync_message(stop_area_ref_sync)
+ data = last_stop_area_ref_sync_message.message_attributes.symbolize_keys!
+ data[:processing_time] = distance_of_time_in_words(data[:processing_time].to_i)
+ t("stop_area_referential_sync.message.#{last_stop_area_ref_sync_message.message_key}", last_stop_area_ref_sync_message.message_attributes.symbolize_keys!).html_safe
+ end
+end
diff --git a/app/helpers/stop_areas_helper.rb b/app/helpers/stop_areas_helper.rb
index 032f68494..314154fb7 100644
--- a/app/helpers/stop_areas_helper.rb
+++ b/app/helpers/stop_areas_helper.rb
@@ -49,7 +49,7 @@ module StopAreasHelper
content_tag :span, "#{sa.projection_x}, #{sa.projection_y}"
elsif !sa.long_lat_type.nil?
- content_tag :span, "#{sa.long_lat_type} : #{sa.longitude}, #{sa.latitude}"
+ content_tag :span, "#{sa.long_lat_type} : #{sa.latitude}, #{sa.longitude}"
end
end
end
diff --git a/app/inputs/full_time_zone_input.rb b/app/inputs/full_time_zone_input.rb
new file mode 100644
index 000000000..f5d8a9ba2
--- /dev/null
+++ b/app/inputs/full_time_zone_input.rb
@@ -0,0 +1,24 @@
+class FullTimeZoneInput < SimpleForm::Inputs::CollectionSelectInput
+ def collection
+ @collection ||= begin
+ collection = options.delete(:collection) || ActiveSupport::TimeZone::MAPPING
+ collection.respond_to?(:call) ? collection.call : collection.to_a
+ end
+ end
+
+ def detect_collection_methods
+ label, value = options.delete(:label_method), options.delete(:value_method)
+
+ label ||= ->(tz) do
+ tz = ActiveSupport::TimeZone[tz.last]
+ "(#{tz.formatted_offset}) #{tz.name}"
+ end
+ value ||= :last
+
+ [label, value]
+ end
+
+ def input(wrapper_options = {})
+ super wrapper_options
+ end
+end
diff --git a/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js b/app/javascript/helpers/CustomFieldsInputs.js
index 827c36b76..9547021eb 100644
--- a/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js
+++ b/app/javascript/helpers/CustomFieldsInputs.js
@@ -16,7 +16,7 @@ export default class CustomFieldsInputs extends Component {
})}
ref={'custom_fields.' + cf.code}
className='form-control'
- defaultValue={cf.value}
+ defaultValue={cf.value || cf.options.default}
disabled={this.props.disabled}
options={{
theme: 'bootstrap',
@@ -34,8 +34,21 @@ export default class CustomFieldsInputs extends Component {
ref={'custom_fields.' + cf.code}
className='form-control'
disabled={this.props.disabled}
- defaultValue={cf.value}
- onChange={(e) => this.props.onUpdate(cf.code, e.target.value) }
+ value={cf.value || cf.options.default}
+ onChange={(e) => {this.props.onUpdate(cf.code, e.target.value); this.forceUpdate()} }
+ />
+ )
+ }
+
+ integerInput(cf){
+ return(
+ <input
+ type='number'
+ ref={'custom_fields.' + cf.code}
+ className='form-control'
+ disabled={this.props.disabled}
+ value={cf.value || cf.options.default}
+ onChange={(e) => {this.props.onUpdate(cf.code, e.target.value); this.forceUpdate()} }
/>
)
}
diff --git a/app/javascript/helpers/polyfills.js b/app/javascript/helpers/polyfills.js
new file mode 100644
index 000000000..93e3e9846
--- /dev/null
+++ b/app/javascript/helpers/polyfills.js
@@ -0,0 +1,4 @@
+import 'promise-polyfill/src/polyfill'
+import 'es6-symbol/implement'
+import 'polyfill-array-includes'
+import 'whatwg-fetch'
diff --git a/app/javascript/journey_patterns/actions/index.js b/app/javascript/journey_patterns/actions/index.js
index ea54f4e05..a813f4b9e 100644
--- a/app/javascript/journey_patterns/actions/index.js
+++ b/app/javascript/journey_patterns/actions/index.js
@@ -1,10 +1,3 @@
-import Promise from 'promise-polyfill'
-
-// To add to window
-if (!window.Promise) {
- window.Promise = Promise;
-}
-
const actions = {
enterEditMode: () => ({
type: "ENTER_EDIT_MODE"
@@ -195,15 +188,19 @@ const actions = {
dispatch(actions.unavailableServer())
} else {
if(json.length != 0){
- let val
- for (val of json){
- for (let stop_point of val.route_short_description.stop_points){
+ let j = 0
+ while(j < json.length){
+ let val = json[j]
+ let i = 0
+ while(i < val.route_short_description.stop_points.length){
+ let stop_point = val.route_short_description.stop_points[i]
stop_point.checked = false
val.stop_area_short_descriptions.map((element) => {
if(element.stop_area_short_description.id === stop_point.id){
stop_point.checked = true
}
})
+ i ++
}
journeyPatterns.push(
_.assign({}, val, {
@@ -212,6 +209,7 @@ const actions = {
deletable: false
})
)
+ j ++
}
}
window.currentItemsLength = journeyPatterns.length
diff --git a/app/javascript/journey_patterns/components/CreateModal.js b/app/javascript/journey_patterns/components/CreateModal.js
index 946c13d9c..51f6f6c1b 100644
--- a/app/javascript/journey_patterns/components/CreateModal.js
+++ b/app/javascript/journey_patterns/components/CreateModal.js
@@ -1,15 +1,17 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import actions from '../actions'
+import CustomFieldsInputs from '../../helpers/CustomFieldsInputs'
export default class CreateModal extends Component {
constructor(props) {
super(props)
+ this.custom_fields = _.assign({}, this.props.custom_fields)
}
handleSubmit() {
if(actions.validateFields(this.refs) == true) {
- this.props.onAddJourneyPattern(this.refs)
+ this.props.onAddJourneyPattern(_.assign({}, this.refs, {custom_fields: this.custom_fields}))
this.props.onModalClose()
$('#NewJourneyPatternModal').modal('hide')
}
@@ -78,8 +80,14 @@ export default class CreateModal extends Component {
/>
</div>
</div>
+ <CustomFieldsInputs
+ values={this.props.custom_fields}
+ onUpdate={(code, value) => this.custom_fields[code]["value"] = value}
+ disabled={false}
+ />
</div>
</div>
+
<div className='modal-footer'>
<button
className='btn btn-link'
diff --git a/app/javascript/journey_patterns/components/EditModal.js b/app/javascript/journey_patterns/components/EditModal.js
index 1960849fb..a23a57f96 100644
--- a/app/javascript/journey_patterns/components/EditModal.js
+++ b/app/javascript/journey_patterns/components/EditModal.js
@@ -1,19 +1,27 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import actions from '../actions'
+import CustomFieldsInputs from '../../helpers/CustomFieldsInputs'
export default class EditModal extends Component {
constructor(props) {
super(props)
+ this.updateValue = this.updateValue.bind(this)
}
handleSubmit() {
if(actions.validateFields(this.refs) == true) {
- this.props.saveModal(this.props.modal.modalProps.index, this.refs)
+ this.props.saveModal(this.props.modal.modalProps.index, _.assign({}, this.refs, {custom_fields: this.custom_fields}))
$('#JourneyPatternModal').modal('hide')
}
}
+ updateValue(attribute, e) {
+ actions.resetValidation(e.currentTarget)
+ this.props.modal.modalProps.journeyPattern[attribute] = e.target.value
+ this.forceUpdate()
+ }
+
renderModalTitle() {
if (this.props.editMode) {
return (
@@ -28,6 +36,9 @@ export default class EditModal extends Component {
}
render() {
+ if(this.props.modal.modalProps.journeyPattern){
+ this.custom_fields = _.assign({}, this.props.modal.modalProps.journeyPattern.custom_fields)
+ }
return (
<div className={ 'modal fade ' + ((this.props.modal.type == 'edit') ? 'in' : '') } id='JourneyPatternModal'>
<div className='modal-container'>
@@ -48,8 +59,8 @@ export default class EditModal extends Component {
className='form-control'
disabled={!this.props.editMode}
id={this.props.modal.modalProps.index}
- defaultValue={this.props.modal.modalProps.journeyPattern.name}
- onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
+ value={this.props.modal.modalProps.journeyPattern.name}
+ onChange={(e) => this.updateValue('name', e)}
required
/>
</div>
@@ -64,8 +75,8 @@ export default class EditModal extends Component {
className='form-control'
disabled={!this.props.editMode}
id={this.props.modal.modalProps.index}
- defaultValue={this.props.modal.modalProps.journeyPattern.published_name}
- onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
+ value={this.props.modal.modalProps.journeyPattern.published_name}
+ onChange={(e) => this.updateValue('published_name', e)}
required
/>
</div>
@@ -79,12 +90,19 @@ export default class EditModal extends Component {
className='form-control'
disabled={!this.props.editMode}
id={this.props.modal.modalProps.index}
- defaultValue={this.props.modal.modalProps.journeyPattern.registration_number}
- onKeyDown={(e) => actions.resetValidation(e.currentTarget)}
+ value={this.props.modal.modalProps.journeyPattern.registration_number}
+ onChange={(e) => this.updateValue('registration_number', e)}
/>
</div>
</div>
</div>
+ <div className='row'>
+ <CustomFieldsInputs
+ values={this.props.modal.modalProps.journeyPattern.custom_fields}
+ onUpdate={(code, value) => this.custom_fields[code]["value"] = value}
+ disabled={!this.props.editMode}
+ />
+ </div>
<div>
<label className='control-label'>{I18n.attribute_name('journey_pattern', 'checksum')}</label>
<input
@@ -92,7 +110,7 @@ export default class EditModal extends Component {
ref='checksum'
className='form-control'
disabled='disabled'
- defaultValue={this.props.modal.modalProps.journeyPattern.checksum}
+ value={this.props.modal.modalProps.journeyPattern.checksum}
/>
</div>
</div>
diff --git a/app/javascript/journey_patterns/containers/AddJourneyPattern.js b/app/javascript/journey_patterns/containers/AddJourneyPattern.js
index b093fd111..9e85afd5e 100644
--- a/app/javascript/journey_patterns/containers/AddJourneyPattern.js
+++ b/app/javascript/journey_patterns/containers/AddJourneyPattern.js
@@ -7,7 +7,8 @@ const mapStateToProps = (state) => {
modal: state.modal,
journeyPatterns: state.journeyPatterns,
editMode: state.editMode,
- status: state.status
+ status: state.status,
+ custom_fields: state.custom_fields
}
}
diff --git a/app/javascript/journey_patterns/containers/Modal.js b/app/javascript/journey_patterns/containers/Modal.js
index 33ee8583c..fc04843e4 100644
--- a/app/javascript/journey_patterns/containers/Modal.js
+++ b/app/javascript/journey_patterns/containers/Modal.js
@@ -7,7 +7,8 @@ const mapStateToProps = (state) => {
return {
editMode: state.editMode,
modal: state.modal,
- journeyPattern: state.journeyPattern
+ journeyPattern: state.journeyPattern,
+ custom_fields: state.custom_fields,
}
}
diff --git a/app/javascript/journey_patterns/reducers/index.js b/app/javascript/journey_patterns/reducers/index.js
index 2ffaf86d4..d3a1d29a2 100644
--- a/app/javascript/journey_patterns/reducers/index.js
+++ b/app/javascript/journey_patterns/reducers/index.js
@@ -12,7 +12,8 @@ const journeyPatternsApp = combineReducers({
journeyPatterns,
pagination,
stopPointsList,
- modal
+ modal,
+ custom_fields: (state = [], action) => state
})
export default journeyPatternsApp
diff --git a/app/javascript/journey_patterns/reducers/journeyPatterns.js b/app/javascript/journey_patterns/reducers/journeyPatterns.js
index b046f2b38..1a6a27da6 100644
--- a/app/javascript/journey_patterns/reducers/journeyPatterns.js
+++ b/app/javascript/journey_patterns/reducers/journeyPatterns.js
@@ -103,7 +103,8 @@ export default function journeyPatterns (state = [], action) {
return _.assign({}, j, {
name: action.data.name.value,
published_name: action.data.published_name.value,
- registration_number: action.data.registration_number.value
+ registration_number: action.data.registration_number.value,
+ custom_fields: action.data.custom_fields,
})
} else {
return j
diff --git a/app/javascript/packs/calendars/edit.js b/app/javascript/packs/calendars/edit.js
index bd09657ec..0c46313b9 100644
--- a/app/javascript/packs/calendars/edit.js
+++ b/app/javascript/packs/calendars/edit.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
diff --git a/app/javascript/packs/exports/new.js b/app/javascript/packs/exports/new.js
index ffe702cdb..b113cc709 100644
--- a/app/javascript/packs/exports/new.js
+++ b/app/javascript/packs/exports/new.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import MasterSlave from "../../helpers/master_slave"
new MasterSlave("form")
diff --git a/app/javascript/packs/journey_patterns/index.js b/app/javascript/packs/journey_patterns/index.js
index 367a8830f..bd7df2634 100644
--- a/app/javascript/packs/journey_patterns/index.js
+++ b/app/javascript/packs/journey_patterns/index.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
@@ -32,7 +34,8 @@ var initialState = {
type: '',
modalProps: {},
confirmModal: {}
- }
+ },
+ custom_fields: window.custom_fields
}
// const loggerMiddleware = createLogger()
diff --git a/app/javascript/packs/referential_lines/show.js b/app/javascript/packs/referential_lines/show.js
index 99c5072ef..523f2040f 100644
--- a/app/javascript/packs/referential_lines/show.js
+++ b/app/javascript/packs/referential_lines/show.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import clone from '../../helpers/clone'
import RoutesMap from '../../helpers/routes_map'
diff --git a/app/javascript/packs/referential_overview/overview.js b/app/javascript/packs/referential_overview/overview.js
index 59c326e9a..03da12ef3 100644
--- a/app/javascript/packs/referential_overview/overview.js
+++ b/app/javascript/packs/referential_overview/overview.js
@@ -1 +1,3 @@
+import '../../helpers/polyfills'
+
import ReferentialOverview from '../../referential_overview'
diff --git a/app/javascript/packs/routes/edit.js b/app/javascript/packs/routes/edit.js
index fc7aa203d..0512b7aff 100644
--- a/app/javascript/packs/routes/edit.js
+++ b/app/javascript/packs/routes/edit.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import React from 'react'
import PropTypes from 'prop-types'
@@ -56,12 +58,25 @@ const getInitialState = () => {
}
var initialState = { stopPoints: getInitialState() }
-const loggerMiddleware = createLogger()
-let store = createStore(
- reducers,
- initialState,
- applyMiddleware(thunkMiddleware, promise, loggerMiddleware)
-)
+let store = null
+
+if(Object.assign){
+ const loggerMiddleware = createLogger()
+ store = createStore(
+ reducers,
+ initialState,
+ applyMiddleware(thunkMiddleware, promise, loggerMiddleware)
+ )
+}
+else{
+ // IE
+ store = createStore(
+ reducers,
+ initialState,
+ applyMiddleware(thunkMiddleware, promise)
+ )
+}
+
render(
<Provider store={store}>
diff --git a/app/javascript/packs/routes/show.js b/app/javascript/packs/routes/show.js
index c20de0800..e8e068ddd 100644
--- a/app/javascript/packs/routes/show.js
+++ b/app/javascript/packs/routes/show.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import clone from '../../helpers/clone'
import RoutesMap from '../../helpers/routes_map'
diff --git a/app/javascript/packs/stop_areas/new.js b/app/javascript/packs/stop_areas/new.js
index ffe702cdb..b113cc709 100644
--- a/app/javascript/packs/stop_areas/new.js
+++ b/app/javascript/packs/stop_areas/new.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import MasterSlave from "../../helpers/master_slave"
new MasterSlave("form")
diff --git a/app/javascript/packs/time_tables/edit.js b/app/javascript/packs/time_tables/edit.js
index cf058d501..873bdea50 100644
--- a/app/javascript/packs/time_tables/edit.js
+++ b/app/javascript/packs/time_tables/edit.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
diff --git a/app/javascript/packs/vehicle_journeys/index.js b/app/javascript/packs/vehicle_journeys/index.js
index 9cad3870e..0b4351d26 100644
--- a/app/javascript/packs/vehicle_journeys/index.js
+++ b/app/javascript/packs/vehicle_journeys/index.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
diff --git a/app/javascript/routes/actions/index.js b/app/javascript/routes/actions/index.js
index 5fbf5bce9..13b2d60b2 100644
--- a/app/javascript/routes/actions/index.js
+++ b/app/javascript/routes/actions/index.js
@@ -56,12 +56,7 @@ const actions = {
unselectMarker: (index) => ({
type: 'UNSELECT_MARKER',
index
- }),
- defaultAttribute: (attribute, stopAreaKind) => {
- if (attribute !== '') return attribute
- if (stopAreaKind === undefined) return ''
- return stopAreaKind === "commercial" ? "normal" : "forbidden"
- }
+ })
}
module.exports = actions
diff --git a/app/javascript/routes/components/App.js b/app/javascript/routes/components/App.js
index 26e69bf53..6f8cdf749 100644
--- a/app/javascript/routes/components/App.js
+++ b/app/javascript/routes/components/App.js
@@ -3,14 +3,9 @@ import PropTypes from 'prop-types'
import AddStopPoint from '../containers/AddStopPoint'
import VisibleStopPoints from'../containers/VisibleStopPoints'
import clone from '../../helpers/clone'
-const I18n = clone(window , "I18n", true)
export default class App extends Component {
- getChildContext() {
- return { I18n }
- }
-
render() {
return (
<div>
@@ -20,7 +15,3 @@ export default class App extends Component {
)
}
}
-
-App.childContextTypes = {
- I18n: PropTypes.object
-}
diff --git a/app/javascript/routes/components/BSelect2.js b/app/javascript/routes/components/BSelect2.js
index 89e1b6cfa..90f288944 100644
--- a/app/javascript/routes/components/BSelect2.js
+++ b/app/javascript/routes/components/BSelect2.js
@@ -10,8 +10,8 @@ var path = window.location.pathname.split('/', 3).join('/')
export default class BSelect3 extends Component {
- constructor(props, context) {
- super(props, context)
+ constructor(props) {
+ super(props)
}
onChange(e) {
this.props.onChange(this.props.index, {
@@ -86,7 +86,7 @@ class BSelect2 extends Component{
onSelect={ this.props.onSelect }
ref='newSelect'
options={{
- placeholder: this.context.I18n.t("routes.edit.select2.placeholder"),
+ placeholder: I18n.t("routes.edit.select2.placeholder"),
allowClear: true,
language: 'fr', /* Doesn't seem to work... :( */
theme: 'bootstrap',
@@ -129,8 +129,4 @@ class BSelect2 extends Component{
/>
)
}
-}
-
-BSelect2.contextTypes = {
- I18n: PropTypes.object
-}
+} \ No newline at end of file
diff --git a/app/javascript/routes/components/OlMap.js b/app/javascript/routes/components/OlMap.js
index 4beb02872..16fec0e87 100644
--- a/app/javascript/routes/components/OlMap.js
+++ b/app/javascript/routes/components/OlMap.js
@@ -3,8 +3,8 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class OlMap extends Component{
- constructor(props, context){
- super(props, context)
+ constructor(props){
+ super(props)
}
fetchApiURL(id){
@@ -115,40 +115,40 @@ export default class OlMap extends Component{
<strong>{this.props.value.olMap.json.name}</strong>
</p>
<p>
- <strong>{this.context.I18n.t('routes.edit.map.stop_point_type')} : </strong>
+ <strong>{I18n.t('routes.edit.map.stop_point_type')} : </strong>
{this.props.value.olMap.json.area_type}
</p>
<p>
- <strong>{this.context.I18n.t('routes.edit.map.short_name')} : </strong>
+ <strong>{I18n.t('routes.edit.map.short_name')} : </strong>
{this.props.value.olMap.json.short_name}
</p>
<p>
- <strong>{this.context.I18n.t('id_reflex')} : </strong>
+ <strong>{I18n.t('id_reflex')} : </strong>
{this.props.value.olMap.json.user_objectid}
</p>
- <p><strong>{this.context.I18n.t('routes.edit.map.coordinates')} : </strong></p>
+ <p><strong>{I18n.t('routes.edit.map.coordinates')} : </strong></p>
<p style={{paddingLeft: 10, marginTop: 0}}>
- <em>{this.context.I18n.t('routes.edit.map.proj')}.: </em>WSG84<br/>
- <em>{this.context.I18n.t('routes.edit.map.lat')}.: </em>{this.props.value.olMap.json.latitude} <br/>
- <em>{this.context.I18n.t('routes.edit.map.lon')}.: </em>{this.props.value.olMap.json.longitude}
+ <em>{I18n.t('routes.edit.map.proj')}.: </em>WSG84<br/>
+ <em>{I18n.t('routes.edit.map.lat')}.: </em>{this.props.value.olMap.json.latitude} <br/>
+ <em>{I18n.t('routes.edit.map.lon')}.: </em>{this.props.value.olMap.json.longitude}
</p>
<p>
- <strong>{this.context.I18n.t('routes.edit.map.postal_code')} : </strong>
+ <strong>{I18n.t('routes.edit.map.postal_code')} : </strong>
{this.props.value.olMap.json.zip_code}
</p>
<p>
- <strong>{this.context.I18n.t('routes.edit.map.city')} : </strong>
+ <strong>{I18n.t('routes.edit.map.city')} : </strong>
{this.props.value.olMap.json.city_name}
</p>
<p>
- <strong>{this.context.I18n.t('routes.edit.map.comment')} : </strong>
+ <strong>{I18n.t('routes.edit.map.comment')} : </strong>
{this.props.value.olMap.json.comment}
</p>
{(this.props.value.stoparea_id != this.props.value.olMap.json.stoparea_id) &&(
<div className='btn btn-outline-primary btn-sm'
onClick= {() => {this.props.onUpdateViaOlMap(this.props.index, this.props.value.olMap.json)}}
- >{this.context.I18n.t('actions.select')}</div>
+ >{I18n.t('actions.select')}</div>
)}
</div>
<div className='map_content'>
@@ -164,7 +164,3 @@ export default class OlMap extends Component{
OlMap.propTypes = {
}
-
-OlMap.contextTypes = {
- I18n: PropTypes.object
-}
diff --git a/app/javascript/routes/components/StopPoint.js b/app/javascript/routes/components/StopPoint.js
index 768d069c0..916052b42 100644
--- a/app/javascript/routes/components/StopPoint.js
+++ b/app/javascript/routes/components/StopPoint.js
@@ -6,7 +6,7 @@ import OlMap from './OlMap'
import { defaultAttribute } from '../actions'
-export default function StopPoint(props, {I18n}) {
+export default function StopPoint(props) {
return (
<div className='nested-fields'>
<div className='wrapper'>
@@ -19,14 +19,14 @@ export default function StopPoint(props, {I18n}) {
</div>
<div>
- <select className='form-control' value={defaultAttribute(props.value.for_boarding, props.value.stoparea_kind)} id="for_boarding" onChange={props.onSelectChange}>
+ <select className='form-control' value={props.value.for_boarding} id="for_boarding" onChange={props.onSelectChange}>
<option value="normal">{I18n.t('routes.edit.stop_point.boarding.normal')}</option>
<option value="forbidden">{I18n.t('routes.edit.stop_point.boarding.forbidden')}</option>
</select>
</div>
<div>
- <select className='form-control' value={defaultAttribute(props.value.for_alighting, props.value.stoparea_kind)} id="for_alighting" onChange={props.onSelectChange}>
+ <select className='form-control' value={props.value.for_alighting} id="for_alighting" onChange={props.onSelectChange}>
<option value="normal">{I18n.t('routes.edit.stop_point.alighting.normal')}</option>
<option value="forbidden">{I18n.t('routes.edit.stop_point.alighting.forbidden')}</option>
</select>
@@ -92,7 +92,3 @@ StopPoint.propTypes = {
index: PropTypes.number,
value: PropTypes.object
}
-
-StopPoint.contextTypes = {
- I18n: PropTypes.object
-}
diff --git a/app/javascript/routes/components/StopPointList.js b/app/javascript/routes/components/StopPointList.js
index b227abdea..9bc5e02d1 100644
--- a/app/javascript/routes/components/StopPointList.js
+++ b/app/javascript/routes/components/StopPointList.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import StopPoint from './StopPoint'
-export default function StopPointList({ stopPoints, onDeleteClick, onMoveUpClick, onMoveDownClick, onChange, onSelectChange, onToggleMap, onToggleEdit, onSelectMarker, onUnselectMarker, onUpdateViaOlMap }, {I18n}) {
+export default function StopPointList({ stopPoints, onDeleteClick, onMoveUpClick, onMoveDownClick, onChange, onSelectChange, onToggleMap, onToggleEdit, onSelectMarker, onUnselectMarker, onUpdateViaOlMap }) {
return (
<div className='subform'>
<div className='nested-head'>
diff --git a/app/javascript/routes/containers/AddStopPoint.js b/app/javascript/routes/containers/AddStopPoint.js
index fd9227ff3..4b169807d 100644
--- a/app/javascript/routes/containers/AddStopPoint.js
+++ b/app/javascript/routes/containers/AddStopPoint.js
@@ -11,7 +11,7 @@ let AddStopPoint = ({ dispatch }) => {
dispatch(actions.addStop())
}}>
<button type="submit" className="btn btn-outline-primary">
- Ajouter un arrêt
+ {I18n.t('stop_areas.actions.new')}
</button>
</form>
</div>
diff --git a/app/javascript/routes/index.js b/app/javascript/routes/index.js
index 3c7322953..fc99a3086 100644
--- a/app/javascript/routes/index.js
+++ b/app/javascript/routes/index.js
@@ -22,6 +22,7 @@ const getInitialState = () => {
let fancyText = v.name.replace("&#39;", "\'")
if(v.zip_code && v.city_name)
fancyText += ", " + v.zip_code + " " + v.city_name.replace("&#39;", "\'")
+ forAlightingAndBoarding = v.stoparea_kind === 'commercial' ? 'normal' : 'forbidden'
state.push({
stoppoint_id: v.stoppoint_id,
@@ -37,8 +38,8 @@ const getInitialState = () => {
name: v.name ? v.name.replace("&#39;", "\'") : '',
registration_number: v.registration_number,
text: fancyText,
- for_boarding: v.for_boarding || '',
- for_alighting: v.for_alighting || '',
+ for_boarding: v.for_boarding || forAlightingAndBoarding,
+ for_alighting: v.for_alighting || forAlightingAndBoarding,
longitude: v.longitude || 0,
latitude: v.latitude || 0,
comment: v.comment ? v.comment.replace("&#39;", "\'") : '',
diff --git a/app/javascript/routes/reducers/stopPoints.js b/app/javascript/routes/reducers/stopPoints.js
index ba183d002..54142338d 100644
--- a/app/javascript/routes/reducers/stopPoints.js
+++ b/app/javascript/routes/reducers/stopPoints.js
@@ -8,8 +8,8 @@ const stopPoint = (state = {}, action, length) => {
text: '',
index: length,
edit: true,
- for_boarding: '',
- for_alighting: '',
+ for_boarding: 'normal',
+ for_alighting: 'normal',
olMap: {
isOpened: false,
json: {}
@@ -61,6 +61,7 @@ const stopPoints = (state = [], action) => {
case 'UPDATE_INPUT_VALUE':
return state.map( (t, i) => {
if (i === action.index) {
+ let forAlightingAndBoarding = action.text.stoparea_kind === 'commercial' ? 'normal' : 'forbidden'
return _.assign(
{},
t,
@@ -77,7 +78,9 @@ const stopPoints = (state = [], action) => {
area_type: action.text.area_type,
city_name: action.text.city_name,
comment: action.text.comment,
- registration_number: action.text.registration_number
+ registration_number: action.text.registration_number,
+ for_alighting: forAlightingAndBoarding,
+ for_boarding: forAlightingAndBoarding
}
)
} else {
diff --git a/app/javascript/time_tables/actions/index.js b/app/javascript/time_tables/actions/index.js
index b56279889..283897b63 100644
--- a/app/javascript/time_tables/actions/index.js
+++ b/app/javascript/time_tables/actions/index.js
@@ -190,10 +190,13 @@ const actions = {
isInPeriod: (periods, date) => {
date = new Date(date)
- for (let period of periods) {
+ let i = 0;
+ while(i < periods.length){
+ let period = periods[i]
let begin = new Date(period.period_start)
let end = new Date(period.period_end)
if (date >= begin && date <= end) return true
+ i++
}
return false
@@ -234,12 +237,14 @@ const actions = {
let error = ''
start = new Date(start)
end = new Date(end)
-
- for (let day of in_days) {
+ let i = 0;
+ while(i < in_days){
+ let day = in_days[i]
if (start <= new Date(day.date) && end >= new Date(day.date)) {
error = I18n.t('time_tables.edit.error_submit.dates_overlaps')
break
}
+ i ++
}
return error
},
diff --git a/app/javascript/time_tables/components/Metas.js b/app/javascript/time_tables/components/Metas.js
index d9746a379..186af540a 100644
--- a/app/javascript/time_tables/components/Metas.js
+++ b/app/javascript/time_tables/components/Metas.js
@@ -76,7 +76,6 @@ export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdat
<label htmlFor="" className="control-label col-sm-4">{I18n.attribute_name('time_table', 'tag_list')}</label>
<div className="col-sm-8">
<TagsSelect2
- initialTags={metas.initial_tags}
tags={metas.tags}
onSelect2Tags={(e) => onSelect2Tags(e)}
onUnselect2Tags={(e) => onUnselect2Tags(e)}
diff --git a/app/javascript/time_tables/components/TagsSelect2.js b/app/javascript/time_tables/components/TagsSelect2.js
index dd8d6e9c0..fe610ed58 100644
--- a/app/javascript/time_tables/components/TagsSelect2.js
+++ b/app/javascript/time_tables/components/TagsSelect2.js
@@ -27,7 +27,7 @@ export default class TagsSelect2 extends Component {
return (
<Select2
value={(this.props.tags.length) ? map(this.props.tags, 'id') : undefined}
- data={(this.props.initialTags.length) ? this.mapKeys(this.props.initialTags) : 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}
@@ -74,4 +74,4 @@ export default class TagsSelect2 extends Component {
const formatRepo = (props) => {
if(props.name) return props.name
-} \ No newline at end of file
+}
diff --git a/app/javascript/time_tables/containers/Metas.js b/app/javascript/time_tables/containers/Metas.js
index ebccf556e..7bc3ef4e1 100644
--- a/app/javascript/time_tables/containers/Metas.js
+++ b/app/javascript/time_tables/containers/Metas.js
@@ -24,6 +24,7 @@ const mapDispatchToProps = (dispatch) => {
},
onSelect2Tags: (e) => {
e.preventDefault()
+ $(e.target).find('[data-select2-tag]').remove()
dispatch(actions.select2Tags(e.params.data))
},
onUnselect2Tags: (e) => {
diff --git a/app/javascript/time_tables/reducers/metas.js b/app/javascript/time_tables/reducers/metas.js
index 51e1ec149..012f29511 100644
--- a/app/javascript/time_tables/reducers/metas.js
+++ b/app/javascript/time_tables/reducers/metas.js
@@ -31,11 +31,13 @@ export default function metas(state = {}, action) {
return assign({}, state, {color: action.color})
case 'UPDATE_SELECT_TAG':
let tags = [...state.tags]
- tags.push(action.selectedItem)
+ if(tags.length == 0 || tags[tags.length-1].name != action.selectedItem.name){
+ 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
}
-} \ No newline at end of file
+}
diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js
index 537dcfc06..c67f9f0cf 100644
--- a/app/javascript/vehicle_journeys/actions/index.js
+++ b/app/javascript/vehicle_journeys/actions/index.js
@@ -1,9 +1,3 @@
-import Promise from 'promise-polyfill'
-
-// To add to window
-if (!window.Promise) {
- window.Promise = Promise;
-}
import { batchActions } from '../batch'
const actions = {
@@ -54,16 +48,10 @@ const actions = {
}),
selectJPCreateModal : (selectedJP) => ({
type : 'SELECT_JP_CREATE_MODAL',
- selectedItem: {
- id: selectedJP.id,
+ selectedItem: _.assign({}, selectedJP, {
objectid: selectedJP.object_id,
- short_id: selectedJP.short_id,
- name: selectedJP.name,
- published_name: selectedJP.published_name,
- stop_areas: selectedJP.stop_area_short_descriptions,
- costs: selectedJP.costs,
- full_schedule: selectedJP.full_schedule
- }
+ stop_areas: selectedJP.stop_area_short_descriptions
+ })
}),
openEditModal : (vehicleJourney) => ({
type : 'EDIT_VEHICLEJOURNEY_MODAL',
@@ -109,10 +97,30 @@ const actions = {
vehicleJourneys,
timetables
}),
+ editVehicleJourneyConstraintZones : (vehicleJourneys, zones) => ({
+ type: 'EDIT_VEHICLEJOURNEYS_CONSTRAINT_ZONES',
+ vehicleJourneys,
+ zones
+ }),
openPurchaseWindowsEditModal : (vehicleJourneys) => ({
type : 'EDIT_PURCHASE_WINDOWS_VEHICLEJOURNEY_MODAL',
vehicleJourneys
}),
+ openConstraintExclusionEditModal : (vehicleJourneys) => ({
+ type : 'EDIT_CONSTRAINT_EXCLUSIONS_VEHICLEJOURNEY_MODAL',
+ vehicleJourneys
+ }),
+ selectConstraintZone: (selectedZone) =>({
+ type: 'SELECT_CONSTRAINT_ZONE_MODAL',
+ selectedZone: {
+ id: selectedZone.id,
+ name: selectedZone.text
+ }
+ }),
+ deleteConstraintZone : (constraintZone) => ({
+ type : 'DELETE_CONSTRAINT_ZONE_MODAL',
+ constraintZone
+ }),
selectPurchaseWindowsModal: (selectedItem) =>({
type: 'SELECT_PURCHASE_WINDOW_MODAL',
selectedItem
@@ -339,16 +347,23 @@ const actions = {
if(hasError == true) {
dispatch(actions.unavailableServer())
} else {
- let val
- for (val of json.vehicle_journeys){
+ let i = 0
+ while(i < json.vehicle_journeys.length){
+ let val = json.vehicle_journeys[i]
+ i++
var timeTables = []
var purchaseWindows = []
- let tt
- for (tt of val.time_tables){
+ let k = 0
+ while(k < val.time_tables.length){
+ let tt = val.time_tables[k]
+ k++
timeTables.push(tt)
}
if(val.purchase_windows){
- for (tt of val.purchase_windows){
+ k = 0
+ while(k < val.purchase_windows.length){
+ let tt = val.purchase_windows[k]
+ k++
purchaseWindows.push(tt)
}
}
diff --git a/app/javascript/vehicle_journeys/components/Filters.js b/app/javascript/vehicle_journeys/components/Filters.js
index 93fe015a8..1e43a490e 100644
--- a/app/javascript/vehicle_journeys/components/Filters.js
+++ b/app/javascript/vehicle_journeys/components/Filters.js
@@ -33,6 +33,7 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
{/* Calendriers */}
<div className='form-group w33'>
<TimetableSelect2
+ placeholder={I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.timetable')}
onSelect2Timetable={onSelect2Timetable}
hasRoute={true}
chunkURL={("/autocomplete_time_tables.json?route_id=" + String(window.route_id))}
diff --git a/app/javascript/vehicle_journeys/components/Tools.js b/app/javascript/vehicle_journeys/components/Tools.js
index 22ea44283..41a521d12 100644
--- a/app/javascript/vehicle_journeys/components/Tools.js
+++ b/app/javascript/vehicle_journeys/components/Tools.js
@@ -9,6 +9,7 @@ import EditVehicleJourney from '../containers/tools/EditVehicleJourney'
import NotesEditVehicleJourney from '../containers/tools/NotesEditVehicleJourney'
import TimetablesEditVehicleJourney from '../containers/tools/TimetablesEditVehicleJourney'
import PurchaseWindowsEditVehicleJourney from '../containers/tools/PurchaseWindowsEditVehicleJourney'
+import ConstraintExclusionEditVehicleJourney from '../containers/tools/ConstraintExclusionEditVehicleJourney'
export default class Tools extends Component {
@@ -35,11 +36,13 @@ export default class Tools extends Component {
<AddVehicleJourney disabled={!this.hasPolicy("create") || !editMode} />
<DuplicateVehicleJourney disabled={!this.hasPolicy("create") || !this.hasPolicy("update") || !editMode}/>
<ShiftVehicleJourney disabled={!this.hasPolicy("update") || !editMode}/>
- <EditVehicleJourney disabled={!this.hasPolicy("update")}/>
- <TimetablesEditVehicleJourney disabled={!this.hasPolicy("update")}/>
+ <EditVehicleJourney disabled={false}/>
+
+ <TimetablesEditVehicleJourney disabled={false}/>
{ this.hasFeature('purchase_windows') &&
- <PurchaseWindowsEditVehicleJourney disabled={!this.hasPolicy("update")}/>
+ <PurchaseWindowsEditVehicleJourney disabled={false}/>
}
+ <ConstraintExclusionEditVehicleJourney disabled={false}/>
<NotesEditVehicleJourney disabled={!this.hasPolicy("update")}/>
<DeleteVehicleJourneys disabled={!this.hasPolicy("destroy") || !editMode}/>
</ul>
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js
index 73d99d120..f7ae9341f 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js
@@ -10,6 +10,10 @@ export default class VehicleJourney extends Component {
this.previousCity = undefined
}
+ journey_length() {
+ return this.props.value.journey_pattern.journey_length + "km"
+ }
+
cityNameChecker(sp) {
return this.props.vehicleJourneys.showHeader(sp.stop_point_objectid)
}
@@ -107,7 +111,21 @@ export default class VehicleJourney extends Component {
}
>
<div className='strong mb-xs'>{this.props.value.short_id || '-'}</div>
- <div>{this.props.value.published_journey_name && this.props.value.published_journey_name != I18n.t('undefined') ? this.props.value.published_journey_name : '-'}</div>
+ <div>
+ <a href="#"
+ onClick={(e) => {
+ if(this.props.disabled){ return }
+ e.stopPropagation(true)
+ e.preventDefault()
+ this.props.onOpenInfoModal(this.props.value)
+ $('#EditVehicleJourneyModal').modal('show')
+ false
+ }
+ }
+ >
+ {this.props.value.published_journey_name && this.props.value.published_journey_name != I18n.t('undefined') ? this.props.value.published_journey_name : '-'}
+ </a>
+ </div>
<div>{this.props.value.journey_pattern.short_id || '-'}</div>
<div>{this.props.value.company ? this.props.value.company.name : '-'}</div>
{
@@ -115,6 +133,11 @@ export default class VehicleJourney extends Component {
<div key={i}>{this.extraHeaderValue(header)}</div>
)
}
+ { this.hasFeature('journey_length_in_vehicle_journeys') &&
+ <div>
+ {this.journey_length()}
+ </div>
+ }
{ this.hasFeature('purchase_windows') &&
<div>
{purchase_windows.slice(0,3).map((tt, i)=>
diff --git a/app/javascript/vehicle_journeys/components/VehicleJourneys.js b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
index c6f59ce9d..0bb00e1ea 100644
--- a/app/javascript/vehicle_journeys/components/VehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/components/VehicleJourneys.js
@@ -87,16 +87,18 @@ export default class VehicleJourneys extends Component {
}
toggleTimetables(e) {
- $('.table-2entries .detailed-timetables').toggleClass('hidden')
- $('.table-2entries .detailed-timetables-bt').toggleClass('active')
+ let root = $(this.refs['vehicleJourneys'])
+ root.find('.table-2entries .detailed-timetables').toggleClass('hidden')
+ root.find('.table-2entries .detailed-timetables-bt').toggleClass('active')
this.componentDidUpdate()
e.preventDefault()
false
}
togglePurchaseWindows(e) {
- $('.table-2entries .detailed-purchase-windows').toggleClass('hidden')
- $('.table-2entries .detailed-purchase-windows-bt').toggleClass('active')
+ let root = $(this.refs['vehicleJourneys'])
+ root.find('.table-2entries .detailed-purchase-windows').toggleClass('hidden')
+ root.find('.table-2entries .detailed-purchase-windows-bt').toggleClass('active')
this.componentDidUpdate()
e.preventDefault()
false
@@ -186,7 +188,7 @@ export default class VehicleJourneys extends Component {
)
} else {
return (
- <div className='row'>
+ <div className='row' ref='vehicleJourneys'>
<div className='col-lg-12'>
{(this.props.status.fetchSuccess == false) && (
<div className='alert alert-danger mt-sm'>
@@ -222,6 +224,11 @@ export default class VehicleJourneys extends Component {
<div key={i}>{this.extraHeaderLabel(header)}</div>
)
}
+ { this.hasFeature('journey_length_in_vehicle_journeys') &&
+ <div>
+ {I18n.attribute_name("vehicle_journey", "journey_length")}
+ </div>
+ }
{ this.hasFeature('purchase_windows') &&
<div>
{ detailed_purchase_windows &&
@@ -288,6 +295,7 @@ export default class VehicleJourneys extends Component {
features={this.props.features}
onUpdateTime={this.props.onUpdateTime}
onSelectVehicleJourney={this.props.onSelectVehicleJourney}
+ onOpenInfoModal={this.props.onOpenInfoModal}
vehicleJourneys={this}
disabled={this.isReturn()}
allTimeTables={this.allTimeTables()}
diff --git a/app/javascript/vehicle_journeys/components/tools/ConstraintExclusionEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/ConstraintExclusionEditVehicleJourney.js
new file mode 100644
index 000000000..bab77926f
--- /dev/null
+++ b/app/javascript/vehicle_journeys/components/tools/ConstraintExclusionEditVehicleJourney.js
@@ -0,0 +1,182 @@
+import _ from 'lodash'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import actions from '../../actions'
+import ConstraintZoneSelect2 from './select2s/ConstraintZoneSelect2'
+
+
+export default class ConstraintExclusionEditVehicleJourney extends Component {
+ constructor(props) {
+ super(props)
+ this.handleSubmit = this.handleSubmit.bind(this)
+ this.constraintZoneUrl = this.constraintZoneUrl.bind(this)
+ this.excluded_constraint_zones = this.excluded_constraint_zones.bind(this)
+ this.constraint_zones = null
+ }
+
+ handleSubmit() {
+ this.props.onConstraintZonesEditVehicleJourney(this.props.modal.modalProps.vehicleJourneys, this.props.modal.modalProps.selectedConstraintZones)
+ this.props.onModalClose()
+ $('#ConstraintExclusionEditVehicleJourney').modal('hide')
+ }
+
+ constraintZoneUrl(contraint_zone) {
+ return window.constraint_zones_routes + "/" + contraint_zone.id
+ }
+
+ excluded_constraint_zones() {
+ let out = []
+ this.props.modal.modalProps.selectedConstraintZones.map((id, _)=>{
+ this.constraint_zones.map((zone, _)=>{
+ if(zone.id == id){
+ out.push(zone)
+ }
+ })
+ })
+ return out
+ }
+
+ fetch_constraint_zones() {
+ let url = window.constraint_zones_routes + ".json"
+ fetch(url, {
+ credentials: 'same-origin',
+ }).then(response => {
+ return response.json()
+ }).then((json) => {
+ this.constraint_zones = []
+ json.map((item, i)=>{
+ this.constraint_zones.push(
+ _.assign({}, item, {text: item.name})
+ )
+ })
+ this.forceUpdate()
+ })
+ }
+
+ render() {
+ if(this.constraint_zones === null) {
+ this.fetch_constraint_zones()
+ return false
+ }
+ if(this.props.status.fetchSuccess == true) {
+ return (
+ <li className='st_action'>
+ <button
+ type='button'
+ disabled={(actions.getSelected(this.props.vehicleJourneys).length < 1 || this.props.disabled)}
+ data-toggle='modal'
+ data-target='#ConstraintExclusionEditVehicleJourney'
+ onClick={() => this.props.onOpenCalendarsEditModal(actions.getSelected(this.props.vehicleJourneys))}
+ title={I18n.t('activerecord.attributes.vehicle_journey.constraint_exclusions')}
+ >
+ <span className='fa fa-ban fa-strong'></span>
+ </button>
+
+ <div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='ConstraintExclusionEditVehicleJourney'>
+ <div className='modal-container'>
+ <div className='modal-dialog'>
+ <div className='modal-content'>
+ <div className='modal-header'>
+ <h4 className='modal-title'>{I18n.t('activerecord.attributes.vehicle_journey.constraint_exclusions')}</h4>
+ <span type="button" className="close modal-close" data-dismiss="modal">&times;</span>
+ </div>
+
+ {(this.props.modal.type == 'constraint_exclusions_edit') && (
+ <form>
+ <div className='modal-body'>
+ <div className='row'>
+ <div className='col-lg-12'>
+ <div className='subform'>
+ <div className='nested-head'>
+ <div className='wrapper'>
+ <div>
+ <div className='form-group'>
+ <label className='control-label'>{this.excluded_constraint_zones().length == 0 ? I18n.t('vehicle_journeys.vehicle_journeys_matrix.no_excluded_constraint_zones') : I18n.t('vehicle_journeys.form.excluded_constraint_zones')}</label>
+ </div>
+ </div>
+ <div></div>
+ </div>
+ </div>
+ {this.excluded_constraint_zones().map((contraint_zone, i) =>
+ <div className='nested-fields' key={i}>
+ <div className='wrapper'>
+ <div> <a href={this.constraintZoneUrl(contraint_zone)} target="_blank">
+ {contraint_zone.name}
+ </a> </div>
+ {
+ this.props.editMode &&
+ <div>
+ <a
+ href='#'
+ title='Supprimer'
+ className='fa fa-trash remove_fields'
+ style={{ height: 'auto', lineHeight: 'normal' }}
+ onClick={(e) => {
+ e.preventDefault()
+ this.props.onDeleteConstraintZone(contraint_zone)
+ }}
+ ></a>
+ </div>
+ }
+ </div>
+ </div>
+ )}
+ {
+ this.props.editMode &&
+ <div className='nested-fields'>
+ <div className='wrapper'>
+ <div>
+ <ConstraintZoneSelect2
+ data={this.constraint_zones}
+ values={this.props.modal.modalProps.constraint_exclusions}
+ placeholder={I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.constraint_zone')}
+ onSelectConstraintZone={this.props.onSelectConstraintZone}
+ />
+ </div>
+ </div>
+ </div>
+ }
+ </div>
+ </div>
+ </div>
+ </div>
+ {
+ this.props.editMode &&
+ <div className='modal-footer'>
+ <button
+ className='btn btn-link'
+ data-dismiss='modal'
+ type='button'
+ onClick={this.props.onModalClose}
+ >
+ {I18n.t('cancel')}
+ </button>
+ <button
+ className='btn btn-primary'
+ type='button'
+ onClick={this.handleSubmit}
+ >
+ {I18n.t('actions.submit')}
+ </button>
+ </div>
+ }
+ </form>
+ )}
+
+ </div>
+ </div>
+ </div>
+ </div>
+ </li>
+ )
+ } else {
+ return false
+ }
+ }
+}
+
+ConstraintExclusionEditVehicleJourney.propTypes = {
+ onOpenCalendarsEditModal: PropTypes.func.isRequired,
+ onModalClose: PropTypes.func.isRequired,
+ disabled: PropTypes.bool.isRequired
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/CreateModal.js b/app/javascript/vehicle_journeys/components/tools/CreateModal.js
index f49b51f08..2806708f4 100644
--- a/app/javascript/vehicle_journeys/components/tools/CreateModal.js
+++ b/app/javascript/vehicle_journeys/components/tools/CreateModal.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import actions from '../../actions'
import MissionSelect2 from './select2s/MissionSelect2'
import CompanySelect2 from './select2s/CompanySelect2'
-import CustomFieldsInputs from './CustomFieldsInputs'
+import CustomFieldsInputs from '../../../helpers/CustomFieldsInputs'
export default class CreateModal extends Component {
constructor(props) {
@@ -14,7 +14,8 @@ export default class CreateModal extends Component {
handleSubmit() {
if(!this.props.modal.modalProps.selectedJPModal){
let field = $('#NewVehicleJourneyModal').find(".vjCreateSelectJP")
- field.parent().parent().addClass('has-error').children('.help-block').remove()
+ field.parent().parent().addClass('has-error')
+ field.parent().children('.help-block').remove()
field.parent().append("<span class='small help-block'>" + I18n.t("simple_form.required.text") + "</span>")
return
}
diff --git a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
index e4e266c79..60d982845 100644
--- a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import actions from '../../actions'
import CompanySelect2 from './select2s/CompanySelect2'
-import CustomFieldsInputs from './CustomFieldsInputs'
+import CustomFieldsInputs from '../../../helpers/CustomFieldsInputs'
export default class EditVehicleJourney extends Component {
constructor(props) {
diff --git a/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js
index 5d300f70c..ef58916f4 100644
--- a/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/NotesEditVehicleJourney.js
@@ -31,13 +31,13 @@ export default class NotesEditVehicleJourney extends Component {
type='button'
className='btn btn-outline-danger btn-xs'
onClick={() => this.props.onToggleFootnoteModal(lf, false)}
- ><span className="fa fa-trash"></span> Retirer</button>
+ ><span className="fa fa-trash"></span>{I18n.t('actions.remove')}</button>
} else {
return <button
type='button'
className='btn btn-outline-primary btn-xs'
onClick={() => this.props.onToggleFootnoteModal(lf, true)}
- ><span className="fa fa-plus"></span> Ajouter</button>
+ ><span className="fa fa-plus"></span>{I18n.t('actions.add')}</button>
}
}
diff --git a/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js
index 30c511302..5fc925f4c 100644
--- a/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js
@@ -44,7 +44,7 @@ export default class PurchaseWindowsEditVehicleJourney extends Component {
<div className='modal-dialog'>
<div className='modal-content'>
<div className='modal-header'>
- <h4 className='modal-title'>{I18n.t('vehicle_journeys.form.purchase_windows')}s</h4>
+ <h4 className='modal-title'>{I18n.t('vehicle_journeys.form.purchase_windows')}</h4>
<span type="button" className="close modal-close" data-dismiss="modal">&times;</span>
</div>
@@ -95,6 +95,7 @@ export default class PurchaseWindowsEditVehicleJourney extends Component {
<div className='wrapper'>
<div>
<TimetableSelect2
+ placeholder={I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.purchase_window')}
onSelect2Timetable={this.props.onSelect2Timetable}
chunkURL={'/autocomplete_purchase_windows.json'}
searchKey={"name_or_objectid_cont_any"}
diff --git a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js
index 9ee2e1849..594140c76 100644
--- a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js
@@ -97,6 +97,7 @@ export default class TimetablesEditVehicleJourney extends Component {
<div className='wrapper'>
<div>
<TimetableSelect2
+ placeholder={I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.timetable')}
onSelect2Timetable={this.props.onSelect2Timetable}
chunkURL={'/autocomplete_time_tables.json'}
searchKey={"unaccented_comment_or_objectid_cont_any"}
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/ConstraintZoneSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/ConstraintZoneSelect2.js
new file mode 100644
index 000000000..1caaf2401
--- /dev/null
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/ConstraintZoneSelect2.js
@@ -0,0 +1,37 @@
+import _ from 'lodash'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import Select2 from 'react-select2-wrapper'
+import actions from '../../../actions'
+
+export default class BSelect4 extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render() {
+ return (
+ <Select2
+ data={this.props.data}
+ value={this.props.value}
+ onSelect={(e) => this.props.onSelectConstraintZone(e) }
+ multiple={false}
+ ref='constraint_zone_id'
+ options={{
+ allowClear: false,
+ theme: 'bootstrap',
+ width: '100%',
+ placeholder: this.props.placeholder,
+ language: require('./language'),
+ minimumInputLength: 1,
+ escapeMarkup: function (markup) { return markup; },
+ templateResult: formatRepo
+ }}
+ />
+ )
+ }
+}
+
+const formatRepo = (props) => {
+ if(props.text) return props.text
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js
index d5aad20d0..919853a71 100644
--- a/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js
@@ -26,7 +26,7 @@ export default class BSelect4 extends Component {
allowClear: false,
theme: 'bootstrap',
width: '100%',
- placeholder: I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.timetable'),
+ placeholder: this.props.placeholder,
language: require('./language'),
ajax: {
url: origin + path + this.props.chunkURL,
diff --git a/app/javascript/vehicle_journeys/containers/VehicleJourneysList.js b/app/javascript/vehicle_journeys/containers/VehicleJourneysList.js
index f21e2c87e..45b061b66 100644
--- a/app/javascript/vehicle_journeys/containers/VehicleJourneysList.js
+++ b/app/javascript/vehicle_journeys/containers/VehicleJourneysList.js
@@ -27,7 +27,10 @@ const mapDispatchToProps = (dispatch) => {
},
onSelectVehicleJourney: (index) => {
dispatch(actions.selectVehicleJourney(index))
- }
+ },
+ onOpenInfoModal: (vj) =>{
+ dispatch(actions.openInfoModal(vj))
+ },
}
}
diff --git a/app/javascript/vehicle_journeys/containers/tools/ConstraintExclusionEditVehicleJourney.js b/app/javascript/vehicle_journeys/containers/tools/ConstraintExclusionEditVehicleJourney.js
new file mode 100644
index 000000000..76d85dfe6
--- /dev/null
+++ b/app/javascript/vehicle_journeys/containers/tools/ConstraintExclusionEditVehicleJourney.js
@@ -0,0 +1,37 @@
+import actions from '../../actions'
+import { connect } from 'react-redux'
+import ConstraintExclusionEditVehicleJourneyComponent from '../../components/tools/ConstraintExclusionEditVehicleJourney'
+
+const mapStateToProps = (state, ownProps) => {
+ return {
+ editMode: state.editMode,
+ modal: state.modal,
+ vehicleJourneys: state.vehicleJourneys,
+ status: state.status,
+ disabled: ownProps.disabled
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ onModalClose: () =>{
+ dispatch(actions.closeModal())
+ },
+ onOpenCalendarsEditModal: (vehicleJourneys) =>{
+ dispatch(actions.openConstraintExclusionEditModal(vehicleJourneys))
+ },
+ onDeleteConstraintZone: (constraint_zone) => {
+ dispatch(actions.deleteConstraintZone(constraint_zone))
+ },
+ onConstraintZonesEditVehicleJourney: (vehicleJourneys, constraint_zones) => {
+ dispatch(actions.editVehicleJourneyConstraintZones(vehicleJourneys, constraint_zones))
+ },
+ onSelectConstraintZone: (e) => {
+ dispatch(actions.selectConstraintZone(e.params.data))
+ },
+ }
+}
+
+const ConstraintExclusionEditVehicleJourney = connect(mapStateToProps, mapDispatchToProps)(ConstraintExclusionEditVehicleJourneyComponent)
+
+export default ConstraintExclusionEditVehicleJourney
diff --git a/app/javascript/vehicle_journeys/reducers/modal.js b/app/javascript/vehicle_journeys/reducers/modal.js
index bcfc6ea0b..75ab2f4ca 100644
--- a/app/javascript/vehicle_journeys/reducers/modal.js
+++ b/app/javascript/vehicle_journeys/reducers/modal.js
@@ -82,6 +82,30 @@ export default function modal(state = {}, action) {
},
confirmModal: {}
}
+ case 'EDIT_CONSTRAINT_EXCLUSIONS_VEHICLEJOURNEY_MODAL':
+ var vehicleJourneys = JSON.parse(JSON.stringify(action.vehicleJourneys))
+ let uniqExclusions = []
+ vehicleJourneys.map((vj, i) => {
+ vj.ignored_routing_contraint_zone_ids.map((exclusion, j) =>{
+ let found = false
+ uniqExclusions.map((id, i)=>{
+ if(id == parseInt(exclusion)){
+ found = true
+ }
+ })
+ if(!found){
+ uniqExclusions.push(parseInt(exclusion))
+ }
+ })
+ })
+ return {
+ type: 'constraint_exclusions_edit',
+ modalProps: {
+ vehicleJourneys: vehicleJourneys,
+ selectedConstraintZones: uniqExclusions
+ },
+ confirmModal: {}
+ }
case 'SELECT_CP_EDIT_MODAL':
vehicleJourney = _.assign({}, state.modalProps.vehicleJourney, {company: action.selectedItem})
newModalProps = _.assign({}, state.modalProps, {vehicleJourney})
@@ -93,9 +117,28 @@ export default function modal(state = {}, action) {
case 'SELECT_TT_CALENDAR_MODAL':
newModalProps = _.assign({}, state.modalProps, {selectedTimetable : action.selectedItem})
return _.assign({}, state, {modalProps: newModalProps})
- case 'SELECT_PURCHASE_WINDOW_MODAL':
- newModalProps = _.assign({}, state.modalProps, {selectedPurchaseWindow : action.selectedItem})
+ case 'SELECT_CONSTRAINT_ZONE_MODAL':
+ let selectedConstraintZones = state.modalProps.selectedConstraintZones
+ let already_present = false
+ selectedConstraintZones.map((zone_id, i)=>{
+ if(zone_id == parseInt(action.selectedZone.id)){
+ already_present = true
+ }
+ })
+ if(already_present){ return state }
+ selectedConstraintZones.push(parseInt(action.selectedZone.id))
+ newModalProps = _.assign({}, state.modalProps, {selectedConstraintZones})
return _.assign({}, state, {modalProps: newModalProps})
+ case 'DELETE_CONSTRAINT_ZONE_MODAL':
+ newModalProps = JSON.parse(JSON.stringify(state.modalProps))
+ selectedConstraintZones = state.modalProps.selectedConstraintZones.slice(0)
+ selectedConstraintZones.map((zone_id, i) =>{
+ if(zone_id == parseInt(action.constraintZone.id)){
+ selectedConstraintZones.splice(i, 1)
+ }
+ })
+ newModalProps.selectedConstraintZones = selectedConstraintZones
+ return _.assign({}, state, {modalProps: newModalProps})
case 'ADD_SELECTED_TIMETABLE':
if(state.modalProps.selectedTimetable){
newModalProps = JSON.parse(JSON.stringify(state.modalProps))
@@ -164,7 +207,9 @@ export default function modal(state = {}, action) {
confirmModal: {}
}
case 'SELECT_JP_CREATE_MODAL':
- newModalProps = _.assign({}, state.modalProps, {selectedJPModal : action.selectedItem})
+ let selected = action.selectedItem
+ delete selected["element"]
+ newModalProps = _.assign({}, state.modalProps, {selectedJPModal : selected})
return _.assign({}, state, {modalProps: newModalProps})
case 'SHIFT_VEHICLEJOURNEY_MODAL':
return {
diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
index b02c19a69..121be6a00 100644
--- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
@@ -40,6 +40,7 @@ const vehicleJourney= (state = {}, action, keep) => {
}
let offsetHours = sp.time_zone_offset / 3600
let offsetminutes = sp.time_zone_offset/60 - 60*offsetHours
+
newVjas = {
delta: 0,
arrival_time:{
@@ -53,6 +54,7 @@ const vehicleJourney= (state = {}, action, keep) => {
if(sp.waiting_time && inJourney){
current_time = actions.addMinutesToTime(current_time, parseInt(sp.waiting_time))
+ newVjas.delta = parseInt(sp.waiting_time)
}
newVjas.departure_time = {
@@ -96,6 +98,7 @@ const vehicleJourney= (state = {}, action, keep) => {
let lastStop = action.selectedJourneyPattern.stop_areas && action.selectedJourneyPattern.stop_areas[action.selectedJourneyPattern.stop_areas.length - 1]
if(lastStop && lastStop.stop_area_short_description.id == sp.id){
newVjas.departure_time = newVjas.arrival_time
+ newVjas.delta = 0
}
if(newVjas.dummy){
@@ -116,6 +119,7 @@ const vehicleJourney= (state = {}, action, keep) => {
footnotes: [],
time_tables: [],
purchase_windows: [],
+ ignored_routing_contraint_zone_ids: [],
vehicle_journey_at_stops: pristineVjasList,
selected: false,
deletable: false,
@@ -232,6 +236,21 @@ export default function vehicleJourneys(state = [], action) {
return vj
}
})
+ case 'EDIT_VEHICLEJOURNEYS_CONSTRAINT_ZONES':
+ let newExclusions = JSON.parse(JSON.stringify(action.zones))
+ return state.map((vj,i) =>{
+ if(vj.selected){
+ let updatedVJ = _.assign({}, vj)
+ action.vehicleJourneys.map((vjm, j) =>{
+ if(vj.objectid == vjm.objectid){
+ updatedVJ.ignored_routing_contraint_zone_ids = newExclusions
+ }
+ })
+ return updatedVJ
+ }else{
+ return vj
+ }
+ })
case 'EDIT_VEHICLEJOURNEYS_PURCHASE_WINDOWS':
let newWindows = JSON.parse(JSON.stringify(action.purchase_windows))
return state.map((vj,i) =>{
diff --git a/app/models/calendar/period.rb b/app/models/calendar/period.rb
index 07926e818..c549a7575 100644
--- a/app/models/calendar/period.rb
+++ b/app/models/calendar/period.rb
@@ -16,7 +16,7 @@ class Calendar < ApplicationModel
alias_method :period_end=, :end=
def check_end_greather_than_begin
- if self.begin && self.end && self.begin >= self.end
+ if self.begin && self.end && self.begin > self.end
errors.add(:base, I18n.t('calendars.errors.short_period'))
end
end
diff --git a/app/models/chouette/area_type.rb b/app/models/chouette/area_type.rb
index e17d2ee8d..4feb5c914 100644
--- a/app/models/chouette/area_type.rb
+++ b/app/models/chouette/area_type.rb
@@ -34,9 +34,9 @@ class Chouette::AreaType
@@options = {}
end
- def self.options(kind=:all)
+ def self.options(kind=:all, locale=nil)
@@options ||= {}
- @@options[kind] ||= self.send(kind).map { |c| find(c) }.map { |t| [ t.label, t.code ] }
+ @@options[kind] ||= self.send(kind).map { |c| find(c) }.map { |t| [ t.label(locale), t.code ] }
end
attr_reader :code
@@ -48,8 +48,8 @@ class Chouette::AreaType
all.index(code) <=> all.index(other.code)
end
- def label
- I18n.translate code, scope: 'area_types.label'
+ def label locale=nil
+ I18n.translate code, scope: 'area_types.label', locale: locale
end
end
diff --git a/app/models/chouette/journey_pattern.rb b/app/models/chouette/journey_pattern.rb
index 830a6a808..8bdf72dfb 100644
--- a/app/models/chouette/journey_pattern.rb
+++ b/app/models/chouette/journey_pattern.rb
@@ -2,6 +2,7 @@ module Chouette
class JourneyPattern < Chouette::TridentActiveRecord
has_metadata
include ChecksumSupport
+ include CustomFieldsSupport
include JourneyPatternRestrictions
include ObjectidSupport
@@ -28,6 +29,8 @@ module Chouette
values.flatten
end
+ has_checksum_children StopPoint
+
def self.state_update route, state
transaction do
state.each do |item|
@@ -52,12 +55,19 @@ module Chouette
end
def self.state_permited_attributes item
- {
+ attrs = {
name: item['name'],
published_name: item['published_name'],
registration_number: item['registration_number'],
costs: item['costs']
}
+ attrs["custom_field_values"] = Hash[
+ *(item["custom_fields"] || {})
+ .map { |k, v| [k, v["value"]] }
+ .flatten
+ ]
+
+ attrs
end
def self.state_create_instance route, item
@@ -78,10 +88,8 @@ module Chouette
def state_stop_points_update item
item['stop_points'].each do |sp|
- exist = stop_area_ids.include?(sp['id'])
- next if exist && sp['checked']
-
- stop_point = route.stop_points.find_by(stop_area_id: sp['id'])
+ stop_point = route.stop_points.find_by(stop_area_id: sp['id'], position: sp['position'])
+ exist = stop_points.include?(stop_point)
if !exist && sp['checked']
stop_points << stop_point
end
@@ -161,18 +169,18 @@ module Chouette
next finish unless start.present?
costs = costs_between(start, finish)
full = false unless costs.present?
- full = false unless costs[:distance] && costs[:distance] > 0
full = false unless costs[:time] && costs[:time] > 0
finish
end
full
end
- def distance_to stop
+ def distance_between start, stop
+ return 0 unless start.position < stop.position
val = 0
- i = 0
- _end = stop_points.first
- while _end != stop
+ i = stop_points.index(start)
+ _end = start
+ while _end && _end != stop
i += 1
_start = _end
_end = stop_points[i]
@@ -181,6 +189,28 @@ module Chouette
val
end
+ def distance_to stop
+ distance_between stop_points.first, stop
+ end
+
+ def journey_length
+ i = 0
+ j = stop_points.length - 1
+ start = stop_points[i]
+ stop = stop_points[j]
+ while i < j && start.kind == "non_commercial"
+ i+= 1
+ start = stop_points[i]
+ end
+
+ while i < j && stop.kind == "non_commercial"
+ j-= 1
+ stop = stop_points[j]
+ end
+ return 0 unless start && stop
+ distance_between start, stop
+ end
+
def set_distances distances
raise "inconsistent data: #{distances.count} values for #{stop_points.count} stops" unless distances.count == stop_points.count
prev = distances[0].to_i
diff --git a/app/models/chouette/line.rb b/app/models/chouette/line.rb
index 4b5d1a68d..3ef2d8e1d 100644
--- a/app/models/chouette/line.rb
+++ b/app/models/chouette/line.rb
@@ -114,5 +114,9 @@ module Chouette
def activated?
!deactivated
end
+
+ def status
+ activated? ? :activated : :deactivated
+ end
end
end
diff --git a/app/models/chouette/purchase_window.rb b/app/models/chouette/purchase_window.rb
index e10b106ec..bd7cbb41e 100644
--- a/app/models/chouette/purchase_window.rb
+++ b/app/models/chouette/purchase_window.rb
@@ -21,6 +21,13 @@ module Chouette
scope :overlap_dates, ->(date_range) { where('daterange(?, ?) && any (date_ranges)', date_range.first, date_range.last + 1.day) }
scope :matching_dates, ->(date_range) { where('ARRAY[daterange(?, ?)] = date_ranges', date_range.first, date_range.last + 1.day) }
+ # VehicleJourneys include PurchaseWindow checksums in their checksums
+ # OPTIMIZEME
+ def update_vehicle_journey_checksums
+ vehicle_journeys.find_each(&:update_checksum!)
+ end
+ after_commit :update_vehicle_journey_checksums
+
def self.ransackable_scopes(auth_object = nil)
[:contains_date]
end
@@ -35,7 +42,7 @@ module Chouette
def checksum_attributes
attrs = ['name', 'color', 'referential_id']
- ranges_attrs = date_ranges.map{|r| [r.first, r.last]}.flatten.sort
+ ranges_attrs = date_ranges.map{|r| [r.min, r.max]}.flatten.sort
self.slice(*attrs).values + ranges_attrs
end
@@ -46,8 +53,9 @@ module Chouette
]
end
- # def checksum_attributes
- # end
-
+ def color
+ _color = read_attribute(:color)
+ _color.present? ? _color : nil
+ end
end
end
diff --git a/app/models/chouette/route.rb b/app/models/chouette/route.rb
index 14bfa47b6..7a8d043e0 100644
--- a/app/models/chouette/route.rb
+++ b/app/models/chouette/route.rb
@@ -7,11 +7,12 @@ module Chouette
include ObjectidSupport
extend Enumerize
- if Rails.env.development?
+ if ENV["CHOUETTE_ROUTE_POSITION_CHECK"] == "true" || !Rails.env.production?
after_commit do
positions = stop_points.pluck(:position)
+ Rails.logger.debug "Check positions in Route #{id} : #{positions.inspect}"
if positions.size != positions.uniq.size
- raise "DUPLICATED stop_points positions: #{positions}"
+ raise "DUPLICATED stop_points positions in Route #{id} : #{positions.inspect}"
end
end
end
@@ -77,7 +78,13 @@ module Chouette
validates_presence_of :published_name
validates_presence_of :line
validates :wayback, inclusion: { in: self.wayback.values }
- after_save :calculate_costs!, if: ->() { TomTom.enabled? }
+ after_commit :calculate_costs!,
+ on: [:create, :update],
+ if: ->() {
+ # Ensure the call back doesn't run during a referential merge
+ !referential.in_referential_suite? &&
+ TomTom.enabled?
+ }
def duplicate opposite=false
overrides = {
@@ -141,10 +148,13 @@ module Chouette
values = self.slice(*['name', 'published_name', 'wayback']).values
values.tap do |attrs|
attrs << self.stop_points.sort_by(&:position).map{|sp| [sp.stop_area.user_objectid, sp.for_boarding, sp.for_alighting]}
- attrs << self.routing_constraint_zones.map(&:checksum)
+ attrs << self.routing_constraint_zones.map(&:checksum).uniq.sort
end
end
+ has_checksum_children StopPoint
+ has_checksum_children RoutingConstraintZone
+
def geometry
points = stop_areas.map(&:to_lat_lng).compact.map do |loc|
[loc.lng, loc.lat]
diff --git a/app/models/chouette/routing_constraint_zone.rb b/app/models/chouette/routing_constraint_zone.rb
index 886eadc6c..671ce2871 100644
--- a/app/models/chouette/routing_constraint_zone.rb
+++ b/app/models/chouette/routing_constraint_zone.rb
@@ -7,6 +7,13 @@ module Chouette
belongs_to :route
has_array_of :stop_points, class_name: 'Chouette::StopPoint'
+ belongs_to_array_in_many :vehicle_journeys, class_name: 'Chouette::VehicleJourney', array_name: :ignored_routing_contraint_zones
+
+ def update_vehicle_journey_checksums
+ vehicle_journeys.each(&:update_checksum!)
+ end
+ after_save :update_vehicle_journey_checksums
+
validates_presence_of :name, :stop_points, :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
@@ -30,6 +37,11 @@ module Chouette
]
end
+ def update_route_checksum
+ route.update_checksum!
+ end
+ after_commit :update_route_checksum
+
def stop_points_belong_to_route
return unless route
diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb
index 4ddc7403b..b933e1944 100644
--- a/app/models/chouette/stop_area.rb
+++ b/app/models/chouette/stop_area.rb
@@ -436,6 +436,12 @@ module Chouette
ActiveSupport::TimeZone[time_zone]&.utc_offset
end
+ def full_time_zone_name
+ return unless time_zone.present?
+ return unless ActiveSupport::TimeZone[time_zone].present?
+ ActiveSupport::TimeZone[time_zone].tzinfo.name
+ end
+
def country
return unless country_code
country = ISO3166::Country[country_code]
diff --git a/app/models/chouette/stop_point.rb b/app/models/chouette/stop_point.rb
index 1df1a664a..edb0e81fd 100644
--- a/app/models/chouette/stop_point.rb
+++ b/app/models/chouette/stop_point.rb
@@ -9,15 +9,14 @@ module Chouette
include ForAlightingEnumerations
include ObjectidSupport
-
belongs_to :stop_area
belongs_to :route, inverse_of: :stop_points
+ has_many :journey_patterns, through: :route
has_many :vehicle_journey_at_stops, :dependent => :destroy
has_many :vehicle_journeys, -> {uniq}, :through => :vehicle_journey_at_stops
acts_as_list :scope => :route, top_of_list: 0
-
validates_presence_of :stop_area
validate :stop_area_id_validation
def stop_area_id_validation
@@ -28,7 +27,7 @@ module Chouette
scope :default_order, -> { order("position") }
- delegate :name, to: :stop_area
+ delegate :name, :registration_number, :kind, :area_type, to: :stop_area
before_destroy :remove_dependent_journey_pattern_stop_points
def remove_dependent_journey_pattern_stop_points
diff --git a/app/models/chouette/time_table.rb b/app/models/chouette/time_table.rb
index b59c95665..29e3808e7 100644
--- a/app/models/chouette/time_table.rb
+++ b/app/models/chouette/time_table.rb
@@ -16,7 +16,7 @@ module Chouette
end
ransacker :unaccented_comment, formatter: ->(val){ val.parameterize } do
- Arel.sql('unaccent(comment)')
+ Arel.sql('unaccent(time_tables.comment)')
end
has_and_belongs_to_many :vehicle_journeys, :class_name => 'Chouette::VehicleJourney'
@@ -81,6 +81,11 @@ module Chouette
chunk.values.delete_if {|dates| dates.count < 2}
end
+ def color
+ _color = read_attribute(:color)
+ _color.present? ? _color : nil
+ end
+
def convert_continuous_dates_to_periods
chunks = self.continuous_dates
diff --git a/app/models/chouette/trident_active_record.rb b/app/models/chouette/trident_active_record.rb
index 18b7bbf9b..475589e13 100644
--- a/app/models/chouette/trident_active_record.rb
+++ b/app/models/chouette/trident_active_record.rb
@@ -7,6 +7,10 @@ module Chouette
@referential ||= Referential.where(:slug => Apartment::Tenant.current).first!
end
+ def workgroup
+ referential&.workgroup
+ end
+
def hub_restricted?
referential.data_format == "hub"
end
@@ -16,4 +20,4 @@ module Chouette
end
end
-end \ No newline at end of file
+end
diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb
index 54aad290c..8a29057e2 100644
--- a/app/models/chouette/vehicle_journey.rb
+++ b/app/models/chouette/vehicle_journey.rb
@@ -25,6 +25,7 @@ module Chouette
has_and_belongs_to_many :footnotes, :class_name => 'Chouette::Footnote'
has_and_belongs_to_many :purchase_windows, :class_name => 'Chouette::PurchaseWindow'
+ has_array_of :ignored_routing_contraint_zones, class_name: 'Chouette::RoutingConstraintZone'
validates_presence_of :route
validates_presence_of :journey_pattern
@@ -140,9 +141,13 @@ module Chouette
attrs << self.published_journey_identifier
attrs << self.try(:company).try(:get_objectid).try(:local_id)
attrs << self.footnotes.map(&:checksum).sort
+
vjas = self.vehicle_journey_at_stops
vjas += VehicleJourneyAtStop.where(vehicle_journey_id: self.id) unless self.new_record?
- attrs << vjas.uniq.sort_by { |s| s.stop_point&.position }.map(&:checksum).sort
+ attrs << vjas.uniq.sort_by { |s| s.stop_point&.position }.map(&:checksum)
+
+ attrs << self.purchase_windows.map(&:checksum).sort if purchase_windows.present?
+ attrs << ignored_routing_contraint_zones.map(&:checksum).sort if ignored_routing_contraint_zones.present?
end
end
@@ -244,11 +249,13 @@ module Chouette
end
def self.state_update route, state
+ objects = []
transaction do
state.each do |item|
item.delete('errors')
vj = find_by(objectid: item['objectid']) || state_create_instance(route, item)
next if item['deletable'] && vj.persisted? && vj.destroy
+ objects << vj
if vj.state_update_vjas?(item['vehicle_journey_at_stops'])
vj.update_vjas_from_state(item['vehicle_journey_at_stops'])
@@ -276,6 +283,7 @@ module Chouette
item['vehicle_journey_at_stops'].map {|vjas| vjas.delete('new_record') }
end
state.delete_if {|item| item['deletable']}
+ objects
end
def self.state_create_instance route, item
@@ -293,7 +301,8 @@ module Chouette
'published_journey_identifier',
'published_journey_name',
'journey_pattern_id',
- 'company_id'
+ 'company_id',
+ 'ignored_routing_contraint_zone_ids'
).to_hash
if item['journey_pattern']
diff --git a/app/models/clean_up.rb b/app/models/clean_up.rb
index ec47489e9..761fc47be 100644
--- a/app/models/clean_up.rb
+++ b/app/models/clean_up.rb
@@ -23,17 +23,29 @@ class CleanUp < ApplicationModel
end
def clean
+ referential.switch
+
{}.tap do |result|
- processed = send("destroy_time_tables_#{self.date_type}")
- if processed
- result['time_table'] = processed[:time_tables].try(:count)
- result['vehicle_journey'] = processed[:vehicle_journeys].try(:count)
- end
- result['time_table_date'] = send("destroy_time_tables_dates_#{self.date_type}").try(:count)
- result['time_table_period'] = send("destroy_time_tables_periods_#{self.date_type}").try(:count)
- self.overlapping_periods.each do |period|
- exclude_dates_in_overlapping_period(period)
+ if date_type
+ processed = send("destroy_time_tables_#{self.date_type}")
+ if processed
+ result['time_table'] = processed[:time_tables].try(:count)
+ result['vehicle_journey'] = processed[:vehicle_journeys].try(:count)
+ end
+ result['time_table_date'] = send("destroy_time_tables_dates_#{self.date_type}").try(:count)
+ result['time_table_period'] = send("destroy_time_tables_periods_#{self.date_type}").try(:count)
+ self.overlapping_periods.each do |period|
+ exclude_dates_in_overlapping_period(period)
+ end
end
+
+ destroy_vehicle_journeys_outside_referential
+ # Disabled for the moment. See #5372
+ # destroy_time_tables_outside_referential
+
+ destroy_vehicle_journeys
+ destroy_journey_patterns
+ destroy_routes
end
end
@@ -76,6 +88,30 @@ class CleanUp < ApplicationModel
Chouette::TimeTablePeriod.where('period_start > ? AND period_end < ?', self.begin_date, self.end_date).destroy_all
end
+ def destroy_time_tables_outside_referential
+ # For the moment, only timetable outside of metadatas min/max dates are removed
+ metadatas_period = referential.metadatas_period
+ time_tables = Chouette::TimeTable.where('end_date < ? or start_date > ?', metadatas_period.min, metadatas_period.max)
+ destroy_time_tables(time_tables)
+ end
+
+ def destroy_vehicle_journeys_outside_referential
+ line_ids = referential.metadatas.pluck(:line_ids).flatten.uniq
+ Chouette::VehicleJourney.joins(:route).where(["routes.line_id not in (?)", line_ids]).destroy_all
+ end
+
+ def destroy_vehicle_journeys
+ Chouette::VehicleJourney.where("id not in (select distinct vehicle_journey_id from time_tables_vehicle_journeys)").destroy_all
+ end
+
+ def destroy_journey_patterns
+ Chouette::JourneyPattern.where("id not in (select distinct journey_pattern_id from vehicle_journeys)").destroy_all
+ end
+
+ def destroy_routes
+ Chouette::Route.where("id not in (select distinct route_id from journey_patterns)").destroy_all
+ end
+
def overlapping_periods
self.end_date = self.begin_date if self.date_type != 'between'
Chouette::TimeTablePeriod.where('(period_start, period_end) OVERLAPS (?, ?)', self.begin_date, self.end_date)
diff --git a/app/models/compliance_check_message_export.rb b/app/models/compliance_check_message_export.rb
index bbaaa8e3f..9b7f90fac 100644
--- a/app/models/compliance_check_message_export.rb
+++ b/app/models/compliance_check_message_export.rb
@@ -22,7 +22,7 @@ class ComplianceCheckMessageExport
end
def column_names
- ["criticity", "message key", "resource objectid", "link", "message"]
+ ["criticity", "message_key", "resource_objectid", "link", "message"].map {|c| ComplianceCheckMessage.tmf(c)}
end
def to_csv(options = {})
diff --git a/app/models/concerns/checksum_support.rb b/app/models/concerns/checksum_support.rb
index 92103798e..fe52604bb 100644
--- a/app/models/concerns/checksum_support.rb
+++ b/app/models/concerns/checksum_support.rb
@@ -12,10 +12,16 @@ module ChecksumSupport
module ClassMethods
def has_checksum_children klass, opts={}
parent_class = self
- relation = opts[:relation] || self.model_name.singular
+ belongs_to = opts[:relation] || self.model_name.singular
+ has_many = opts[:relation] || self.model_name.plural
+
+ Rails.logger.debug "Define callback in #{klass} to update checksums #{self.model_name} (via #{has_many}/#{belongs_to})"
klass.after_save do
- parent = self.send(relation)
- parent&.update_checksum_without_callbacks!
+ parents = []
+ parents << self.send(belongs_to) if klass.reflections[belongs_to].present?
+ parents += self.send(has_many) if klass.reflections[has_many].present?
+ Rails.logger.debug "Request from #{klass.name} checksum updates for #{parents.count} #{parent_class} parent(s)"
+ parents.compact.each &:update_checksum_without_callbacks!
end
end
end
@@ -40,6 +46,7 @@ module ChecksumSupport
def current_checksum_source
source = checksum_replace_nil_or_empty_values(self.checksum_attributes)
+ source += self.custom_fields_checksum if self.respond_to?(:custom_fields_checksum)
source.map{ |item|
if item.kind_of?(Array)
item.map{ |x| x.kind_of?(Array) ? "(#{x.join(',')})" : x }.join(',')
@@ -56,22 +63,24 @@ module ChecksumSupport
def update_checksum
if self.checksum_source_changed?
self.checksum = Digest::SHA256.new.hexdigest(self.checksum_source)
+ Rails.logger.debug("Changed #{self.class.name}:#{id} checksum: #{self.checksum}")
end
end
def update_checksum!
- set_current_checksum_source
- if checksum_source_changed?
- update checksum: Digest::SHA256.new.hexdigest(checksum_source)
- end
+ _checksum_source = current_checksum_source
+ update checksum_source: _checksum_source, checksum: Digest::SHA256.new.hexdigest(_checksum_source)
+ Rails.logger.debug("Updated #{self.class.name}:#{id} checksum: #{self.checksum}")
end
def update_checksum_without_callbacks!
set_current_checksum_source
_checksum = Digest::SHA256.new.hexdigest(checksum_source)
+ Rails.logger.debug("Compute checksum for #{self.class.name}:#{id} checksum_source:'#{checksum_source}' checksum: #{_checksum}")
if _checksum != self.checksum
self.checksum = _checksum
- self.class.where(id: self.id).update_all(checksum: _checksum) unless self.new_record?
+ self.class.where(id: self.id).update_all(checksum: _checksum, checksum_source: checksum_source) unless self.new_record?
+ Rails.logger.debug("Updated #{self.class.name}:#{id} checksum: #{self.checksum}")
end
end
end
diff --git a/app/models/concerns/custom_fields_support.rb b/app/models/concerns/custom_fields_support.rb
index 46fc8e73d..6e744d550 100644
--- a/app/models/concerns/custom_fields_support.rb
+++ b/app/models/concerns/custom_fields_support.rb
@@ -5,18 +5,19 @@ module CustomFieldsSupport
validate :custom_fields_values_are_valid
after_initialize :initialize_custom_fields
- def self.custom_fields workgroup=:all
+ def self.custom_fields workgroup
+ return [] unless workgroup
fields = CustomField.where(resource_type: self.name.split("::").last)
- fields = fields.where(workgroup_id: workgroup&.id) if workgroup != :all
+ fields = fields.where(workgroup_id: workgroup.id)
fields
end
- def self.custom_fields_definitions workgroup=:all
+ def self.custom_fields_definitions workgroup
Hash[*custom_fields(workgroup).map{|cf| [cf.code, cf]}.flatten]
end
def method_missing method_name, *args
- if method_name =~ /custom_field_*/ && method_name.to_sym != :custom_field_values && !@custom_fields_initialized
+ if !@custom_fields_initialized && method_name =~ /custom_field_*/ && method_name.to_sym != :custom_field_values
initialize_custom_fields
send method_name, *args
else
@@ -24,26 +25,47 @@ module CustomFieldsSupport
end
end
- def custom_fields workgroup=:all
- CustomField::Collection.new self, workgroup
+ def custom_fields deprecated_workgroup=nil
+ _workgroup = deprecated_workgroup || self.workgroup
+ CustomField::Collection.new self, _workgroup
+ end
+
+ def custom_fields_checksum
+ custom_fields.values.map(&:checksum)
end
def custom_field_values= vals
- out = {}
- custom_fields.each do |code, field|
- out[code] = field.preprocess_value_for_assignment(vals.symbolize_keys[code.to_sym])
+ if custom_fields_initialized?
+ out = {}
+ custom_fields.each do |code, field|
+ out[code] = field.preprocess_value_for_assignment(vals.symbolize_keys[code.to_sym])
+ end
+ @custom_fields_values_initialized = true
+ else
+ out = vals
end
write_attribute :custom_field_values, out
end
+ def custom_fields_initialized?
+ !!@custom_fields_initialized
+ end
+
+ def custom_fields_values_initialized?
+ !!@custom_fields_values_initialized
+ end
+
def initialize_custom_fields
+ return if custom_fields_initialized?
return unless self.attributes.has_key?("custom_field_values")
+ return unless self.workgroup.present?
self.custom_field_values ||= {}
- custom_fields(:all).values.each &:initialize_custom_field
- custom_fields(:all).each do |k, v|
+ custom_fields.values.each &:initialize_custom_field
+ custom_fields.each do |k, v|
custom_field_values[k] ||= v.default_value
end
@custom_fields_initialized = true
+ self.custom_field_values = self.custom_field_values unless custom_fields_values_initialized?
end
def custom_field_value key
@@ -52,7 +74,7 @@ module CustomFieldsSupport
private
def custom_fields_values_are_valid
- custom_fields(:all).values.all?{|cf| cf.valid?}
+ custom_fields.values.all?{|cf| cf.valid?}
end
end
end
diff --git a/app/models/concerns/line_referential_support.rb b/app/models/concerns/line_referential_support.rb
index 5eade3557..b77a178eb 100644
--- a/app/models/concerns/line_referential_support.rb
+++ b/app/models/concerns/line_referential_support.rb
@@ -7,6 +7,10 @@ module LineReferentialSupport
alias_method :referential, :line_referential
end
+ def workgroup
+ line_referential&.workgroup
+ end
+
def hub_restricted?
false
end
diff --git a/app/models/concerns/metadata_support.rb b/app/models/concerns/metadata_support.rb
index c4bedbcda..182ab8310 100644
--- a/app/models/concerns/metadata_support.rb
+++ b/app/models/concerns/metadata_support.rb
@@ -66,6 +66,10 @@ module MetadataSupport
"#{name}_updated_at".to_sym
end
+ def as_json
+ @table.as_json
+ end
+
def method_missing(mid, *args)
out = super(mid, *args)
owner.send :write_attribute, attribute_name, @table
diff --git a/app/models/concerns/stop_area_referential_support.rb b/app/models/concerns/stop_area_referential_support.rb
index f29397b3a..fb9edd7d5 100644
--- a/app/models/concerns/stop_area_referential_support.rb
+++ b/app/models/concerns/stop_area_referential_support.rb
@@ -7,6 +7,10 @@ module StopAreaReferentialSupport
alias_method :referential, :stop_area_referential
end
+ def workgroup
+ stop_area_referential&.workgroup
+ end
+
def hub_restricted?
false
end
diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb
index 22118a15a..15aee9a41 100644
--- a/app/models/custom_field.rb
+++ b/app/models/custom_field.rb
@@ -7,12 +7,8 @@ class CustomField < ApplicationModel
validates :name, uniqueness: {scope: [:resource_type, :workgroup_id]}
validates :code, uniqueness: {scope: [:resource_type, :workgroup_id], case_sensitive: false}, presence: true
- scope :for_workgroup, ->(workgroup){ where workgroup_id: workgroup.id }
-
- scope :for_workgroup, ->(workgroup){ where workgroup_id: workgroup.id }
-
class Collection < HashWithIndifferentAccess
- def initialize object, workgroup=:all
+ def initialize object, workgroup=nil
vals = object.class.custom_fields(workgroup).map do |v|
[v.code, CustomField::Instance.new(object, v, object.custom_field_value(v.code))]
end
@@ -67,6 +63,10 @@ class CustomField < ApplicationModel
@raw_value
end
+ def checksum
+ @raw_value
+ end
+
def input form_helper
@input ||= begin
klass_name = field_type && "CustomField::Instance::#{field_type.classify}::Input"
@@ -147,6 +147,10 @@ class CustomField < ApplicationModel
@raw_value&.to_i
end
+ def preprocess_value_for_assignment val
+ val&.to_i
+ end
+
def validate
@valid = true
return if @raw_value.is_a?(Fixnum) || @raw_value.is_a?(Float)
@@ -167,6 +171,10 @@ class CustomField < ApplicationModel
end
end
+ def preprocess_value_for_assignment val
+ val
+ end
+
def display_value
return unless value
k = options["list_values"].is_a?(Hash) ? value.to_s : value.to_i
@@ -191,9 +199,10 @@ class CustomField < ApplicationModel
custom_field_code = self.code
_attr_name = attr_name
_uploader_name = uploader_name
+ _digest_name = digest_name
owner.send :define_singleton_method, "read_uploader" do |attr|
if attr.to_s == _attr_name
- custom_field_values[custom_field_code]
+ custom_field_values[custom_field_code] && custom_field_values[custom_field_code]["path"]
else
read_attribute attr
end
@@ -201,16 +210,28 @@ class CustomField < ApplicationModel
owner.send :define_singleton_method, "write_uploader" do |attr, val|
if attr.to_s == _attr_name
- custom_field_values[custom_field_code] = val
+ self.custom_field_values[custom_field_code] ||= {}
+ self.custom_field_values[custom_field_code]["path"] = val
+ self.custom_field_values[custom_field_code]["digest"] = self.send _digest_name
else
write_attribute attr, val
end
end
owner.send :define_singleton_method, "#{_attr_name}_will_change!" do
+ self.send "#{_digest_name}=", nil
custom_field_values_will_change!
end
+ owner.send :define_singleton_method, _digest_name do
+ val = instance_variable_get "@#{_digest_name}"
+ if val.nil? && (file = send(_uploader_name)).present?
+ val = CustomField::Instance::Attachment.digest(file)
+ instance_variable_set "@#{_digest_name}", val
+ end
+ val
+ end
+
_extension_whitelist = options["extension_whitelist"]
owner.send :define_singleton_method, "#{_uploader_name}_extension_whitelist" do
@@ -219,7 +240,15 @@ class CustomField < ApplicationModel
unless owner.class.uploaders.has_key? _uploader_name.to_sym
owner.class.mount_uploader _uploader_name, CustomFieldAttachmentUploader, mount_on: "custom_field_#{code}_raw_value"
+ owner.class.send :attr_accessor, _digest_name
end
+
+ digest = @raw_value && @raw_value["digest"]
+ owner.send "#{_digest_name}=", digest
+ end
+
+ def self.digest file
+ Digest::SHA256.file(file.path).hexdigest
end
def preprocess_value_for_assignment val
@@ -230,6 +259,10 @@ class CustomField < ApplicationModel
end
end
+ def checksum
+ owner.send digest_name
+ end
+
def value
owner.send "custom_field_#{code}"
end
@@ -246,6 +279,10 @@ class CustomField < ApplicationModel
"custom_field_#{code}"
end
+ def digest_name
+ "#{uploader_name}_digest"
+ end
+
def display_value
render_partial
end
diff --git a/app/models/import/gtfs.rb b/app/models/import/gtfs.rb
index 70f448132..a20c468c1 100644
--- a/app/models/import/gtfs.rb
+++ b/app/models/import/gtfs.rb
@@ -56,12 +56,16 @@ class Import::Gtfs < Import::Base
attr_accessor :download_host
def download_host
- @download_host ||= Rails.application.config.rails_host.gsub("http://","")
+ @download_host ||= Rails.application.config.rails_host
end
def local_temp_directory
- Rails.application.config.try(:import_temporary_directory) ||
- Rails.root.join('tmp', 'imports')
+ @local_temp_directory ||=
+ begin
+ directory = Rails.application.config.try(:import_temporary_directory) || Rails.root.join('tmp', 'imports')
+ FileUtils.mkdir_p directory
+ directory
+ end
end
def local_temp_file(&block)
@@ -75,11 +79,20 @@ class Import::Gtfs < Import::Base
Rails.application.routes.url_helpers.download_workbench_import_path(workbench, id, token: token_download)
end
+ def download_uri
+ @download_uri ||=
+ begin
+ host = download_host
+ host = "http://#{host}" unless host =~ %r{https?://}
+ URI.join(host, download_path)
+ end
+ end
+
def download_local_file
local_temp_file do |file|
begin
- Net::HTTP.start(download_host) do |http|
- http.request_get(download_path) do |response|
+ Net::HTTP.start(download_uri.host, download_uri.port) do |http|
+ http.request_get(download_uri.request_uri) do |response|
response.read_body do |segment|
file.write segment
end
diff --git a/app/models/import/message_export.rb b/app/models/import/message_export.rb
index 7a7add08c..7d03783ed 100644
--- a/app/models/import/message_export.rb
+++ b/app/models/import/message_export.rb
@@ -22,7 +22,7 @@ class Import::MessageExport
end
def column_names
- ["criticity", "message key", "message", "file name", "line", "column"]
+ ["criticity", "message_key", "message", "filename", "line", "column"].map {|c| Import::Message.tmf(c)}
end
def to_csv(options = {})
diff --git a/app/models/import/netex.rb b/app/models/import/netex.rb
index 93604c5f9..f19fde435 100644
--- a/app/models/import/netex.rb
+++ b/app/models/import/netex.rb
@@ -10,7 +10,7 @@ class Import::Netex < Import::Base
validates_presence_of :parent
- def create_referential!
+ def create_with_referential!
self.referential =
Referential.new(
name: self.name,
@@ -19,15 +19,16 @@ class Import::Netex < Import::Base
metadatas: [referential_metadata]
)
self.referential.save
- unless self.referential.valid?
+ if self.referential.invalid?
Rails.logger.info "Can't create referential for import #{self.id}: #{referential.inspect} #{referential.metadatas.inspect} #{referential.errors.messages}"
- if referential.metadatas.all?{|m| m.line_ids.empty?}
+ if referential.metadatas.all?{|m| m.line_ids.present? && m.line_ids.empty?}
parent.messages.create criticity: :error, message_key: "referential_creation_missing_lines", message_attributes: {referential_name: referential.name}
else
parent.messages.create criticity: :error, message_key: "referential_creation", message_attributes: {referential_name: referential.name}
end
+ else
+ save!
end
- save!
end
private
@@ -45,7 +46,7 @@ class Import::Netex < Import::Base
def referential_metadata
metadata = ReferentialMetadata.new
- if self.file
+ if self.file && self.file.path
netex_file = STIF::NetexFile.new(self.file.path)
frame = netex_file.frames.first
diff --git a/app/models/merge.rb b/app/models/merge.rb
index 6e2a7036a..be1bbedcb 100644
--- a/app/models/merge.rb
+++ b/app/models/merge.rb
@@ -50,7 +50,7 @@ class Merge < ApplicationModel
new =
if workbench.output.current
Rails.logger.debug "Clone current output"
- Referential.new_from(workbench.output.current, fixme_functional_scope).tap do |clone|
+ Referential.new_from(workbench.output.current, workbench.organisation).tap do |clone|
clone.inline_clone = true
end
else
@@ -135,6 +135,14 @@ class Merge < ApplicationModel
referential_stop_points_by_route = referential_stop_points.group_by(&:route_id)
+ referential_routing_constraint_zones = referential.switch do
+ referential.routing_constraint_zones.each_with_object(Hash.new { |h,k| h[k] = {}}) do |routing_constraint_zone, hash|
+ hash[routing_constraint_zone.route_id][routing_constraint_zone.checksum] = routing_constraint_zone
+ end
+ end
+
+ referential_routing_constraint_zones_new_ids = {}
+
new.switch do
referential_routes.each do |route|
existing_route = new.routes.find_by line_id: route.line_id, checksum: route.checksum
@@ -164,11 +172,53 @@ class Merge < ApplicationModel
new_route.stop_points.build attributes
end
+ # We need to create StopPoints to known new primary keys
+ new_route.save!
+
+ old_stop_point_ids = route_stop_points.sort_by(&:position).map(&:id)
+ new_stop_point_ids = new_route.stop_points.sort_by(&:position).map(&:id)
+
+ stop_point_ids_mapping = Hash[[old_stop_point_ids, new_stop_point_ids].transpose]
+
+ # RoutingConstraintZones
+ routing_constraint_zones = referential_routing_constraint_zones[route.id]
+
+ routing_constraint_zones.values.each do |routing_constraint_zone|
+ objectid = new.routing_constraint_zones.where(objectid: routing_constraint_zone.objectid).exists? ? nil : routing_constraint_zone.objectid
+ stop_point_ids = routing_constraint_zone.stop_point_ids.map { |id| stop_point_ids_mapping[id] }.compact
+
+ if stop_point_ids.size != routing_constraint_zone.stop_point_ids.size
+ raise "Can't find all required StopPoints for RoutingConstraintZone #{routing_constraint_zone.inspect}"
+ end
+
+ attributes = routing_constraint_zone.attributes.merge(
+ id: nil,
+ route_id: nil,
+ objectid: objectid,
+ stop_point_ids: stop_point_ids,
+ )
+ new_route.routing_constraint_zones.build attributes
+
+ end
+
new_route.save!
if new_route.checksum != route.checksum
raise "Checksum has changed: \"#{route.checksum}\", \"#{route.checksum_source}\" -> \"#{new_route.checksum}\", \"#{new_route.checksum_source}\""
end
+
+ if new_route.routing_constraint_zones.map(&:checksum).sort != routing_constraint_zones.keys.sort
+ raise "Checksum has changed in RoutingConstraintZones: \"#{new_route.routing_constraint_zones.map(&:checksum).sort}\" -> \"#{route.routing_constraint_zones.map(&:checksum).sort}\""
+ end
+
+ new_route.routing_constraint_zones.each do |new_routing_constraint_zone|
+ routing_constraint_zone = routing_constraint_zones[new_routing_constraint_zone.checksum]
+ if routing_constraint_zone
+ referential_routing_constraint_zones_new_ids[routing_constraint_zone.id] = new_routing_constraint_zone.id
+ else
+ raise "Can't find RoutingConstraintZone for checksum #{new_routing_constraint_zone.checksum} into #{routing_constraint_zones.inspect}"
+ end
+ end
end
end
end
@@ -224,7 +274,7 @@ class Merge < ApplicationModel
new_journey_pattern = new.journey_patterns.create! attributes
if new_journey_pattern.checksum != journey_pattern.checksum
- raise "Checksum has changed for #{journey_pattern.inspect}: \"#{journey_pattern.checksum_source}\" -> \"#{new_journey_pattern.checksum_source}\""
+ raise "Checksum has changed for #{journey_pattern.inspect} (to #{new_journey_pattern.inspect}): \"#{journey_pattern.checksum_source}\" -> \"#{new_journey_pattern.checksum_source}\""
end
end
end
@@ -236,17 +286,36 @@ class Merge < ApplicationModel
referential.vehicle_journeys.includes(:vehicle_journey_at_stops).all.to_a
end
+ referential_purchase_windows_by_checksum, referential_vehicle_journey_purchase_window_checksums = referential.switch do
+ purchase_windows_by_checksum = referential.purchase_windows.each_with_object({}) do |purchase_window, hash|
+ hash[purchase_window.checksum] = purchase_window
+ end
+
+ vehicle_journey_purchase_window_checksums = Hash.new { |h,k| h[k] = [] }
+ referential.purchase_windows.joins(:vehicle_journeys).pluck("vehicle_journeys.id", :checksum).each do |vehicle_journey_id, checksum|
+ vehicle_journey_purchase_window_checksums[vehicle_journey_id] << checksum
+ end
+
+ [purchase_windows_by_checksum, vehicle_journey_purchase_window_checksums]
+ end
+
+ new_vehicle_journey_ids = {}
+
new.switch do
referential_vehicle_journeys.each do |vehicle_journey|
# find parent journey pattern by checksum
# TODO add line_id for security
+ associated_route_checksum = referential_routes_checksums[vehicle_journey.route_id]
associated_journey_pattern_checksum = referential_journey_patterns_checksums[vehicle_journey.journey_pattern_id]
- existing_associated_journey_pattern = new.journey_patterns.find_by checksum: associated_journey_pattern_checksum
+
+ existing_associated_route = new.routes.find_by checksum: associated_route_checksum
+ existing_associated_journey_pattern = existing_associated_route.journey_patterns.find_by checksum: associated_journey_pattern_checksum
existing_vehicle_journey = new.vehicle_journeys.find_by journey_pattern_id: existing_associated_journey_pattern.id, checksum: vehicle_journey.checksum
if existing_vehicle_journey
existing_vehicle_journey.merge_metadata_from vehicle_journey
+ new_vehicle_journey_ids[vehicle_journey.id] = existing_vehicle_journey.id
else
objectid = Chouette::VehicleJourney.where(objectid: vehicle_journey.objectid).exists? ? nil : vehicle_journey.objectid
attributes = vehicle_journey.attributes.merge(
@@ -256,6 +325,7 @@ class Merge < ApplicationModel
# all other primary must be changed
route_id: existing_associated_journey_pattern.route_id,
journey_pattern_id: existing_associated_journey_pattern.id,
+ ignored_routing_contraint_zone_ids: []
)
new_vehicle_journey = new.vehicle_journeys.build attributes
@@ -269,11 +339,41 @@ class Merge < ApplicationModel
new_vehicle_journey.vehicle_journey_at_stops.build at_stop_attributes
end
+ # Associate (and create if needed) PurchaseWindows
+
+ referential_vehicle_journey_purchase_window_checksums[vehicle_journey.id].each do |purchase_window_checksum|
+ associated_purchase_window = new.purchase_windows.find_by(checksum: purchase_window_checksum)
+
+ unless associated_purchase_window
+ purchase_window = referential_purchase_windows_by_checksum[purchase_window_checksum]
+
+ objectid = new.purchase_windows.where(objectid: purchase_window.objectid).exists? ? nil : purchase_window.objectid
+ attributes = purchase_window.attributes.merge(
+ id: nil,
+ objectid: objectid
+ )
+ new_purchase_window = new.purchase_windows.build attributes
+ new_purchase_window.save!
+
+ if new_purchase_window.checksum != purchase_window.checksum
+ raise "Checksum has changed: #{purchase_window.checksum_source} #{new_purchase_window.checksum_source}"
+ end
+
+ associated_purchase_window = new_purchase_window
+ end
+
+ new_vehicle_journey.purchase_windows << associated_purchase_window
+ end
+
+ # Rewrite ignored_routing_contraint_zone_ids
+ new_vehicle_journey.ignored_routing_contraint_zone_ids = referential_routing_constraint_zones_new_ids.values_at(*vehicle_journey.ignored_routing_contraint_zone_ids).compact
new_vehicle_journey.save!
if new_vehicle_journey.checksum != vehicle_journey.checksum
- raise "Checksum has changed: #{vehicle_journey.checksum_source} #{new_vehicle_journey.checksum_source}"
+ raise "Checksum has changed: \"#{vehicle_journey.checksum_source}\" \"#{vehicle_journey.checksum}\" -> \"#{new_vehicle_journey.checksum_source}\" \"#{new_vehicle_journey.checksum}\""
end
+
+ new_vehicle_journey_ids[vehicle_journey.id] = new_vehicle_journey.id
end
end
@@ -285,14 +385,14 @@ class Merge < ApplicationModel
time_tables_by_id = Hash[referential.time_tables.includes(:dates, :periods).all.to_a.map { |t| [t.id, t] }]
time_tables_with_associated_lines =
- referential.time_tables.joins(vehicle_journeys: {route: :line}).pluck("lines.id", :id, "vehicle_journeys.checksum")
+ referential.time_tables.joins(vehicle_journeys: {route: :line}).pluck("lines.id", :id, "vehicle_journeys.id")
# Because TimeTables will be modified according metadata periods
# we're loading timetables per line (line is associated to a period list)
#
# line_id: [ { time_table.id, vehicle_journey.checksum } ]
time_tables_by_lines = time_tables_with_associated_lines.inject(Hash.new { |h,k| h[k] = [] }) do |hash, row|
- hash[row.shift] << {id: row.first, vehicle_journey_checksum: row.second}
+ hash[row.shift] << {id: row.first, vehicle_journey_id: row.second}
hash
end
@@ -362,7 +462,12 @@ class Merge < ApplicationModel
# associate VehicleJourney
- associated_vehicle_journey = line.vehicle_journeys.find_by!(checksum: properties[:vehicle_journey_checksum])
+ new_vehicle_journey_id = new_vehicle_journey_ids[properties[:vehicle_journey_id]]
+ unless new_vehicle_journey_id
+ raise "TimeTable #{existing_time_table.inspect} associated to a not-merged VehicleJourney: #{properties[:vehicle_journey_id]}"
+ end
+
+ associated_vehicle_journey = line.vehicle_journeys.find(new_vehicle_journey_id)
associated_vehicle_journey.time_tables << existing_time_table
end
end
@@ -371,7 +476,7 @@ class Merge < ApplicationModel
def save_current
output.update current: new, new: nil
- output.current.update referential_suite: output
+ output.current.update referential_suite: output, ready: true
referentials.update_all merged_at: created_at, archived_at: created_at
end
diff --git a/app/models/referential.rb b/app/models/referential.rb
index 1794126a2..78b719fab 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -78,31 +78,29 @@ class Referential < ApplicationModel
alias_method_chain :save, :table_lock_timeout
- if Rails.env.development?
- def self.force_register_models_with_checksum
- paths = Rails.application.paths['app/models'].to_a
- Rails.application.railties.each do |tie|
- next unless tie.respond_to? :paths
- paths += tie.paths['app/models'].to_a
- end
+ def self.force_register_models_with_checksum
+ paths = Rails.application.paths['app/models'].to_a
+ Rails.application.railties.each do |tie|
+ next unless tie.respond_to? :paths
+ paths += tie.paths['app/models'].to_a
+ end
- paths.each do |path|
- next unless File.directory?(path)
- Dir.chdir path do
- Dir['**/*.rb'].each do |src|
- next if src =~ /^concerns/
- # thanks for inconsistent naming ...
- if src == "route_control/zdl_stop_area.rb"
- RouteControl::ZDLStopArea
- next
- end
- Rails.logger.info "Loading #{src}"
- begin
- src[0..-4].classify.safe_constantize
- rescue => e
- Rails.logger.info "Failed: #{e.message}"
- nil
- end
+ paths.each do |path|
+ next unless File.directory?(path)
+ Dir.chdir path do
+ Dir['**/*.rb'].each do |src|
+ next if src =~ /^concerns/
+ # thanks for inconsistent naming ...
+ if src == "route_control/zdl_stop_area.rb"
+ RouteControl::ZDLStopArea
+ next
+ end
+ Rails.logger.info "Loading #{src}"
+ begin
+ src[0..-4].classify.safe_constantize
+ rescue => e
+ Rails.logger.info "Failed: #{e.message}"
+ nil
end
end
end
diff --git a/app/models/referential_cloning.rb b/app/models/referential_cloning.rb
index f2c81009a..6e102a807 100644
--- a/app/models/referential_cloning.rb
+++ b/app/models/referential_cloning.rb
@@ -25,6 +25,11 @@ class ReferentialCloning < ApplicationModel
.clone_schema
end
target_referential.check_migration_count(report)
+ clean
+ end
+
+ def clean
+ CleanUp.new(referential: target_referential).clean
end
private
diff --git a/app/models/referential_metadata.rb b/app/models/referential_metadata.rb
index 7a8a01774..a4e6333d7 100644
--- a/app/models/referential_metadata.rb
+++ b/app/models/referential_metadata.rb
@@ -44,8 +44,8 @@ class ReferentialMetadata < ApplicationModel
validate :check_end_greather_than_begin
def check_end_greather_than_begin
- if self.begin and self.end and self.begin >= self.end
- errors.add(:base, I18n.t('referentials.errors.short_period'))
+ if self.begin and self.end and self.begin > self.end
+ errors.add(:base, I18n.t('referentials.errors.invalid_period'))
end
end
diff --git a/app/policies/merge_policy.rb b/app/policies/merge_policy.rb
index 82eb72e08..154dc63f5 100644
--- a/app/policies/merge_policy.rb
+++ b/app/policies/merge_policy.rb
@@ -8,8 +8,4 @@ class MergePolicy < ApplicationPolicy
def create?
user.has_permission?('merges.create')
end
-
- def update?
- user.has_permission?('merges.update')
- end
end
diff --git a/app/views/api/v1/journey_patterns/show.rabl b/app/views/api/v1/journey_patterns/show.rabl
index aac66b6f3..d02781cfa 100644
--- a/app/views/api/v1/journey_patterns/show.rabl
+++ b/app/views/api/v1/journey_patterns/show.rabl
@@ -1,7 +1,7 @@
object @journey_pattern
extends "api/v1/trident_objects/show"
-[:id, :name, :published_name, :registration_number, :comment, :checksum].each do |attr|
+[:id, :name, :published_name, :registration_number, :comment, :checksum, :custom_fields].each do |attr|
attributes attr, :unless => lambda { |m| m.send( attr).nil?}
end
diff --git a/app/views/companies/_form.html.slim b/app/views/companies/_form.html.slim
index e8b3fcede..4aa08e267 100644
--- a/app/views/companies/_form.html.slim
+++ b/app/views/companies/_form.html.slim
@@ -9,10 +9,10 @@
= f.input :phone
= f.input :fax
= f.input :email, as: :email
- = f.input :time_zone, include_blank: true
+ = f.input :time_zone, as: :full_time_zone, include_blank: true
= f.input :url
= f.input :registration_number, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@line_referential)}.company.registration_number")}
- - if resource.custom_fields(current_referential.workgroup).any?
+ - if resource.custom_fields.present?
- resource.custom_fields.each do |code, field|
= field.input(f).to_s
.separator
diff --git a/app/views/compliance_control_blocks/_form.html.slim b/app/views/compliance_control_blocks/_form.html.slim
index 2e87a877e..e8ae63384 100644
--- a/app/views/compliance_control_blocks/_form.html.slim
+++ b/app/views/compliance_control_blocks/_form.html.slim
@@ -1,6 +1,12 @@
= simple_form_for [@compliance_control_set, @compliance_control_block], html: { class: 'form-horizontal', id: 'compliance_control_block_form' }, wrapper: :horizontal_form do |f|
.row
.col-lg-12
+ - if @compliance_control_block.errors.has_key? :condition_attributes
+ .row.condition-attributes-errors
+ .col-lg-12
+ .alert.alert-danger
+ - @compliance_control_block.errors[:condition_attributes].each do |msg|
+ p.small = "- #{msg}"
.form-group
= f.input :transport_mode, as: :select, collection: ComplianceControlBlock.sorted_transport_modes, label: t('activerecord.attributes.compliance_control_blocks.transport_mode'), label_method: lambda {|t| ("<span>" + t("enumerize.transport_mode.#{t}") + "</span>").html_safe }
= f.input :transport_submode, as: :select, collection: ComplianceControlBlock.sorted_transport_submodes, label: t('activerecord.attributes.compliance_control_blocks.transport_submode'), label_method: lambda {|t| ("<span>" + t("enumerize.transport_submode.#{t}") + "</span>").html_safe }
diff --git a/app/views/journey_patterns_collections/show.html.slim b/app/views/journey_patterns_collections/show.html.slim
index b389a1da7..38c7f1b1b 100644
--- a/app/views/journey_patterns_collections/show.html.slim
+++ b/app/views/journey_patterns_collections/show.html.slim
@@ -20,5 +20,6 @@
| window.perms = #{raw @perms};
| window.features = #{raw @features};
| window.routeCostsUrl = "#{costs_referential_line_route_url(@referential, @route.line, @route, format: :json).html_safe}";
-
+ | window.custom_fields = #{(@custom_fields.to_json).html_safe};
+
= javascript_pack_tag 'journey_patterns/index.js'
diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim
index 3921c8701..abf39c089 100644
--- a/app/views/layouts/application.html.slim
+++ b/app/views/layouts/application.html.slim
@@ -17,7 +17,11 @@ html lang=I18n.locale
| I18n.locale = '#{I18n.locale}'
body
- = render 'layouts/navigation/main_nav'
+ nav#main_nav
+ // Left menu content
+ = render 'layouts/navigation/main_nav_left'
+ // Top menu content
+ = render 'layouts/navigation/main_nav_top'
= render 'layouts/flash_messages', flash: flash
= render 'layouts/navigation/page_header'
= yield
diff --git a/app/views/layouts/devise.html.slim b/app/views/layouts/devise.html.slim
new file mode 100644
index 000000000..34a3a3f11
--- /dev/null
+++ b/app/views/layouts/devise.html.slim
@@ -0,0 +1,28 @@
+doctype html
+html lang=I18n.locale
+ head
+ meta charset="utf-8"
+ meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
+
+ = csrf_meta_tag
+
+ title = t('brandname')
+
+ = stylesheet_link_tag 'base'
+ = stylesheet_link_tag 'application'
+
+ = javascript_pack_tag 'application'
+ = javascript_include_tag 'application'
+ = javascript_tag do
+ | I18n.locale = '#{I18n.locale}'
+
+ body
+ nav#main_nav
+ // Top menu content
+ = render 'layouts/navigation/main_nav_top'
+ = render 'layouts/flash_messages', flash: flash
+ = render 'layouts/navigation/page_header'
+ = yield
+
+ = render 'shared/development_toolbar'
+ = yield :javascript
diff --git a/app/views/layouts/navigation/_main_nav.html.slim b/app/views/layouts/navigation/_main_nav.html.slim
deleted file mode 100644
index 806290223..000000000
--- a/app/views/layouts/navigation/_main_nav.html.slim
+++ /dev/null
@@ -1,6 +0,0 @@
-nav#main_nav
- // Left menu content
- = render 'layouts/navigation/main_nav_left'
-
- // Top menu content
- = render 'layouts/navigation/main_nav_top'
diff --git a/app/views/layouts/navigation/_main_nav_left_content.html.slim b/app/views/layouts/navigation/_main_nav_left_content.html.slim
index e69de29bb..0b55578a7 100644
--- a/app/views/layouts/navigation/_main_nav_left_content.html.slim
+++ b/app/views/layouts/navigation/_main_nav_left_content.html.slim
@@ -0,0 +1,64 @@
+
+- current_organisation.workbenches.each do |workbench|
+ #menu-items.panel-group
+ .menu-item.panel
+ .panel-heading
+ h4.panel-title
+ = link_to '#miOne', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
+ = t('layouts.navbar.current_offer.other')
+
+ #miOne.panel-collapse.collapse
+ .list-group
+ = link_to root_path, class: "list-group-item" do
+ span = t('layouts.navbar.dashboard')
+ = link_to workbench_output_path(workbench), class: 'list-group-item' do
+ span = t('layouts.navbar.workbench_outputs.organisation')
+ = link_to '#', class: 'list-group-item disabled' do
+ span = t('layouts.navbar.workbench_outputs.workgroup')
+
+ .menu-item.panel
+ .panel-heading
+ h4.panel-title
+ = link_to '#miTwo', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
+ - t('activerecord.models.workbench.one').capitalize
+
+ #miTwo.panel-collapse.collapse
+ .list-group
+ = link_to workbench_path(workbench), class: "list-group-item" do
+ span = t('activerecord.models.referential.other').capitalize
+ = link_to workbench_imports_path(workbench), class: "list-group-item" do
+ span = t('activerecord.models.import.other').capitalize
+ = link_to workbench_exports_path(workbench), class: "list-group-item" do
+ span = t('activerecord.models.export.other').capitalize
+ = link_to workgroup_calendars_path(workbench.workgroup), class: 'list-group-item' do
+ span = t('activerecord.models.calendar.other').capitalize
+ = link_to workbench_compliance_check_sets_path(workbench), class: 'list-group-item' do
+ span = t('activerecord.models.compliance_check_set.other').capitalize
+ = link_to compliance_control_sets_path, class: 'list-group-item' do
+ span = t('activerecord.models.compliance_control_set.other').capitalize
+
+ .menu-item.panel
+ .panel-heading
+ h4.panel-title
+ = link_to '#miFour', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
+ = t('layouts.navbar.line_referential')
+
+ #miFour.panel-collapse.collapse
+ .list-group
+ = link_to line_referential_lines_path(workbench.line_referential), class: "list-group-item" do
+ span = Chouette::Line.t.capitalize
+ = link_to line_referential_networks_path(workbench.line_referential), class: "list-group-item" do
+ span = Chouette::Network.t.capitalize
+ = link_to line_referential_companies_path(workbench.line_referential), class: "list-group-item" do
+ span = Chouette::Company.t.capitalize
+
+ .menu-item.panel
+ .panel-heading
+ h4.panel-title
+ = link_to '#miFive', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
+ = t('layouts.navbar.stop_area_referential')
+
+ #miFive.panel-collapse.collapse
+ .list-group
+ = link_to stop_area_referential_stop_areas_path(workbench.stop_area_referential), class: "list-group-item" do
+ span = Chouette::StopArea.t.capitalize
diff --git a/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim b/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim
index 02614dcab..9404eeae6 100644
--- a/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim
+++ b/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim
@@ -1,109 +1,95 @@
-- @localizationUrl = "#{params[:controller]}##{params[:action]}"
-
-#menu-items.panel-group
- .menu-item.panel
- .panel-heading
- h4.panel-title
- = link_to '#miOne', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
- |Offres courantes
-
- #miOne.panel-collapse.collapse
- .list-group
- = link_to root_path, class: "list-group-item #{(@localizationUrl == 'workbenches#index') ? 'active' : ''}" do
- span Tableau de bord
- = link_to '#', class: 'list-group-item' do
- span Offre de mon organisation
- = link_to '#', class: 'list-group-item' do
- span Offre IDF
-
- .menu-item.panel
- .panel-heading
- h4.panel-title
- = link_to '#miTwo', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
- |Espace de travail
-
- #miTwo.panel-collapse.collapse
- .list-group
- - current_user.workbenches.each do |current_workbench|
- = link_to workbench_path(current_workbench), class: "list-group-item #{params[:controller] == 'workbenches' ? 'active' : ''}" do
- span Jeux de données
- = link_to workbench_imports_path(current_workbench), class: "list-group-item #{(params[:controller] == 'imports') ? 'active' : ''}" do
- span Import
- = link_to workbench_exports_path(current_workbench), class: "list-group-item #{(params[:controller] == 'exports') ? 'active' : ''}" do
- span Export
- = link_to workgroup_calendars_path(current_workbench.workgroup), class: 'list-group-item' do
- span Modèles de calendrier
- = link_to workbench_compliance_check_sets_path(current_workbench), class: 'list-group-item' do
- span Rapport de contrôle
+- current_organisation.workbenches.each do |workbench|
+ #menu-items.panel-group
+ .menu-item.panel
+ .panel-heading
+ h4.panel-title
+ = link_to '#miOne', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
+ = t('layouts.navbar.current_offer.other')
+
+ #miOne.panel-collapse.collapse
+ .list-group
+ = link_to root_path, class: "list-group-item" do
+ span = t('layouts.navbar.dashboard')
+ = link_to workbench_output_path(workbench), class: 'list-group-item' do
+ span = t('layouts.navbar.workbench_outputs.organisation')
+ = link_to '#', class: 'list-group-item disabled' do
+ span = t('layouts.navbar.workbench_outputs.workgroup')
+
+ .menu-item.panel
+ .panel-heading
+ h4.panel-title
+ = link_to '#miTwo', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
+ - t('activerecord.models.workbench.one').capitalize
+
+ #miTwo.panel-collapse.collapse
+ .list-group
+ = link_to workbench_path(workbench), class: "list-group-item" do
+ span = t('activerecord.models.referential.other').capitalize
+ = link_to workbench_imports_path(workbench), class: "list-group-item" do
+ span = t('activerecord.models.import.other').capitalize
+ = link_to workbench_exports_path(workbench), class: "list-group-item" do
+ span = t('activerecord.models.export.other').capitalize
+ = link_to workgroup_calendars_path(workbench.workgroup), class: 'list-group-item' do
+ span = t('activerecord.models.calendar.other').capitalize
+ = link_to workbench_compliance_check_sets_path(workbench), class: 'list-group-item' do
+ span = t('activerecord.models.compliance_check_set.other').capitalize
= link_to compliance_control_sets_path, class: 'list-group-item' do
- span Jeux de contrôle
+ span = t('activerecord.models.compliance_control_set.other').capitalize
- .menu-item.panel
- .panel-heading
- h4.panel-title
- = link_to '#miThree', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
- |Données
+ .menu-item.panel
+ .panel-heading
+ h4.panel-title
+ = link_to '#miFour', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
+ = t('layouts.navbar.line_referential')
- #miThree.panel-collapse.collapse
- - if @referential.try(:id) && respond_to?(:current_referential)
+ #miFour.panel-collapse.collapse
.list-group
- .list-group-item
- = (current_referential.name).upcase
- .list-group
- = link_to referential_networks_path(current_referential), class: 'list-group-item' do
- span = t('networks.index.title')
-
- = link_to referential_companies_path(current_referential), class: 'list-group-item' do
- span = t('companies.index.title')
-
- = link_to '#', class: 'list-group-item disabled' do
- span Tracés
-
- = link_to referential_time_tables_path(current_referential), class: 'list-group-item' do
- span = t('time_tables.index.title')
-
- - else
- .panel-body
- em.text-muted
- = "Sélectionnez un jeu de données pour accéder à plus de fonctionnalités"
-
- .menu-item.panel
- .panel-heading
- h4.panel-title
- = link_to '#miFour', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
- |Synchronisation
-
- #miFour.panel-collapse.collapse
- .list-group
- = link_to line_referential_path(1), class: "list-group-item #{(@localizationUrl == 'line_referentials#show') ? 'active' : ''}" do
- span Synchronisation iLICO
- = link_to stop_area_referential_path(1), class: "list-group-item #{(@localizationUrl == 'stop_area_referentials#show') ? 'active' : ''}" do
- span Synchronisation iCAR
-
- .menu-item.panel
- .panel-heading
- h4.panel-title
- = link_to '#miFive', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
- |Outils
-
- #miFive.panel-collapse.collapse
- .list-group
- = link_to Rails.application.config.try(:portal_url), target: '_blank', class: 'list-group-item' do
- span
- span.fa.fa-2x.fa-circle
- |Portail (POSTIF)
-
- = link_to Rails.application.config.try(:codifligne_url), target: '_blank', class: 'list-group-item' do
- span
- span.fa.fa-2x.fa-circle
- |iLICO
-
- = link_to Rails.application.config.try(:reflex_url), target: '_blank', class: 'list-group-item' do
- span
- span.fa.fa-2x.fa-circle
- |iCAR
-
- = link_to '#', target: '_blank', class: 'list-group-item' do
- span
- span.fa.fa-2x.fa-circle
- |Support
+ = link_to line_referential_path(workbench.line_referential), class: "list-group-item" do
+ span = t('layouts.navbar.sync_ilico')
+ = link_to line_referential_lines_path(workbench.line_referential), class: "list-group-item" do
+ span = Chouette::Line.t.capitalize
+ = link_to line_referential_networks_path(workbench.line_referential), class: "list-group-item" do
+ span = Chouette::Network.t.capitalize
+ = link_to line_referential_companies_path(workbench.line_referential), class: "list-group-item" do
+ span = Chouette::Company.t.capitalize
+
+ .menu-item.panel
+ .panel-heading
+ h4.panel-title
+ = link_to '#miFive', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
+ = t('layouts.navbar.stop_area_referential')
+
+ #miFive.panel-collapse.collapse
+ .list-group
+ = link_to stop_area_referential_path(workbench.stop_area_referential), class: "list-group-item" do
+ span = t('layouts.navbar.sync_icar')
+ = link_to stop_area_referential_stop_areas_path(workbench.stop_area_referential), class: "list-group-item" do
+ span = Chouette::StopArea.t.capitalize
+
+ .menu-item.panel
+ .panel-heading
+ h4.panel-title
+ = link_to '#miSix', data: {toggle: 'collapse', parent: '#menu-items'}, 'aria-expanded' => 'false' do
+ = t('layouts.navbar.tools')
+
+ #miSix.panel-collapse.collapse
+ .list-group
+ = link_to Rails.application.config.try(:portal_url), target: '_blank', class: 'list-group-item' do
+ span
+ span.fa.fa-2x.fa-circle
+ = t('layouts.navbar.portal')
+
+ = link_to Rails.application.config.try(:codifligne_url), target: '_blank', class: 'list-group-item' do
+ span
+ span.fa.fa-2x.fa-circle
+ = t('layouts.navbar.ilico')
+
+ = link_to Rails.application.config.try(:reflex_url), target: '_blank', class: 'list-group-item' do
+ span
+ span.fa.fa-2x.fa-circle
+ = t('layouts.navbar.icar')
+
+ = link_to '#', target: '_blank', class: 'list-group-item' do
+ span
+ span.fa.fa-2x.fa-circle
+ = t('layouts.navbar.support')
diff --git a/app/views/line_referentials/show.html.slim b/app/views/line_referentials/show.html.slim
index 763eb076e..1f184b6f2 100644
--- a/app/views/line_referentials/show.html.slim
+++ b/app/views/line_referentials/show.html.slim
@@ -1,47 +1,29 @@
- breadcrumb :line_referential, @line_referential
- page_header_content_for @line_referential
-- if policy(@line_referential).synchronize?
- - content_for :page_header_actions do
- = link_to(t('actions.sync'), sync_line_referential_path(@line_referential), method: :post, class: 'btn btn-default')
-
-- content_for :page_header_content do
- .row.mb-md
- .col-lg-12.text-right
- = link_to line_referential_companies_path(@line_referential), class: 'btn btn-primary' do
- = Referential.human_attribute_name(:companies)
- em.small = " (#{@line_referential.companies.size})"
- = link_to line_referential_networks_path(@line_referential), class: 'btn btn-primary' do
- = Referential.human_attribute_name(:networks)
- em.small = " (#{@line_referential.networks.size})"
- = link_to line_referential_lines_path(@line_referential), class: 'btn btn-primary' do
- = Referential.human_attribute_name(:lines)
- em.small = " (#{@line_referential.lines.size})"
.page_content
.container-fluid
.row
.col-lg-12
- - unless @line_referential.line_referential_syncs.empty?
- table.table
- thead
- tr
- th = t('.synchronized')
- th = t('.status')
- th = t('.message')
+ = table_builder_2 @line_referential.line_referential_syncs,
+ [ \
+ TableBuilderHelper::Column.new( \
+ name: t('.synchronized'), \
+ attribute: Proc.new { |sync| line_referential_sync_created_at(sync) }, \
+ ), \
+ TableBuilderHelper::Column.new( \
+ name: t('.status'), \
+ attribute: Proc.new { |sync| line_referential_sync_status(sync) }, \
+ ), \
+ TableBuilderHelper::Column.new( \
+ name: t('.message'), \
+ attribute: Proc.new { |sync| line_referential_sync_message(sync) }, \
+ ), \
+ ],
+ sortable: false,
+ cls: 'table'
- tbody
- - @line_referential.line_referential_syncs.each_with_index do |sync, i|
- / Display only 10 msgs
- - if i < 10
- - unless sync.line_referential_sync_messages.empty?
- - sync.line_referential_sync_messages.last.tap do |log|
- - if log.criticity = log.criticity
- tr
- td style='width: 150px'
- = l(log.created_at, format: :short_with_time)
- td.text-center
- .fa.fa-circle class="text-#{criticity_class(log.criticity)}"
- td
- - data = log.message_attributes.symbolize_keys!
- - data[:processing_time] = distance_of_time_in_words(data[:processing_time].to_i)
- = t("line_referential_sync.message.#{log.message_key}", log.message_attributes.symbolize_keys!).html_safe
+ - unless @line_referential.line_referential_syncs.any?
+ .row.mt-xs
+ .col-lg-12
+ = replacement_msg t('line_referential_syncs.search_no_results')
diff --git a/app/views/lines/_filters.html.slim b/app/views/lines/_filters.html.slim
index f745d10a4..992d163fe 100644
--- a/app/views/lines/_filters.html.slim
+++ b/app/views/lines/_filters.html.slim
@@ -8,23 +8,23 @@
.ffg-row
.form-group.togglable class=filter_item_class(params[:q], :network_id_eq_any)
- = f.label Chouette::Line.human_attribute_name(:network_id), required: false, class: 'control-label'
+ = f.label Chouette::Line.tmf(:network_id), required: false, class: 'control-label'
= f.input :network_id_eq_any, collection: @line_referential.networks.order(name: :asc), as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + l.name + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list'}
.form-group.togglable class=filter_item_class(params[:q], :company_id_eq_any)
- = f.label Chouette::Line.human_attribute_name(:company_id), required: false, class: 'control-label'
+ = f.label Chouette::Line.tmf(:company_id), required: false, class: 'control-label'
= f.input :company_id_eq_any, collection: @line_referential.companies.order(name: :asc), as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + l.name + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list'}
.form-group.togglable class=filter_item_class(params[:q], :transport_mode_eq_any)
- = f.label Chouette::Line.human_attribute_name(:transport_mode), required: false, class: 'control-label'
+ = f.label Chouette::Line.tmf(:transport_mode), required: false, class: 'control-label'
= f.input :transport_mode_eq_any, collection: StifTransportModeEnumerations.sorted_transport_modes, as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + t("enumerize.transport_mode.#{l}") + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list'}
.form-group.togglable class=filter_item_class(params[:q], :transport_submode_eq_any)
- = f.label Chouette::Line.human_attribute_name(:transport_submode), required: false, class: 'control-label'
+ = f.label Chouette::Line.tmf(:transport_submode), required: false, class: 'control-label'
= f.input :transport_submode_eq_any, collection: StifTransportSubmodeEnumerations.sorted_transport_submodes, as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + t("enumerize.transport_submode.#{l}") + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list'}
.form-group.togglable class=filter_item_class(params[:q], :status)
- = f.label Chouette::Line.human_attribute_name(:state), required: false, class: 'control-label'
+ = f.label Chouette::Line.tmf(:status), required: false, class: 'control-label'
.form-group.checkbox_list
= f.simple_fields_for :status do |p|
= p.input :activated,
diff --git a/app/views/lines/index.html.slim b/app/views/lines/index.html.slim
index 9d491ace4..02bb5ec6e 100644
--- a/app/views/lines/index.html.slim
+++ b/app/views/lines/index.html.slim
@@ -29,9 +29,9 @@
end \
), \
TableBuilderHelper::Column.new( \
- name: t('activerecord.attributes.line.state'), \
+ key: :status, \
class: :state, \
- attribute: Proc.new { |n| line_status(n.deactivated) } \
+ attribute: Proc.new { |n| line_status(n.status) } \
), \
TableBuilderHelper::Column.new( \
key: 'networks.name', \
@@ -57,4 +57,4 @@
- unless @lines.any?
.row.mt-xs
.col-lg-12
- = replacement_msg t('referential_lines.search_no_results')
+ = replacement_msg 'referential_lines.search_no_results'.t
diff --git a/app/views/lines/show.html.slim b/app/views/lines/show.html.slim
index 9e1ae6d6f..fae32fb5d 100644
--- a/app/views/lines/show.html.slim
+++ b/app/views/lines/show.html.slim
@@ -7,13 +7,13 @@
.col-lg-6.col-md-6.col-sm-12.col-xs-12
= definition_list t('metadatas'),
{ t('objectid') => @line.get_objectid.short_id,
- @line.human_attribute_name(:deactivated) => (@line.deactivated? ? t('false') : t('true')),
- @line.human_attribute_name(:network_id) => (@line.network.nil? ? t('lines.index.unset') : @line.network.name),
- @line.human_attribute_name(:company_id) => (@line.company.nil? ? t('lines.index.unset') : @line.company.name),
- @line.human_attribute_name(:secondary_companies) => (@line.secondary_companies.nil? ? t('lines.index.unset') : array_to_html_list(@line.secondary_companies.collect(&:name))),
- @line.human_attribute_name(:number) => @line.number,
- @line.human_attribute_name(:registration_number) => (@line.registration_number ? @line.registration_number : '-'),
- @line.human_attribute_name(:transport_mode) => (@line.transport_mode.present? ? t("enumerize.transport_mode.#{@line.transport_mode}") : '-'),
- @line.human_attribute_name(:transport_submode) => (@line.transport_submode.present? ? t("enumerize.transport_submode.#{@line.transport_submode}") : '-'),
- @line.human_attribute_name(:url) => (@line.url ? @line.url : '-'),
- @line.human_attribute_name(:seasonal) => (@line.seasonal? ? t('true') : t('false')),}
+ Chouette::Line.tmf(:status) => line_status(@line.status),
+ Chouette::Line.tmf(:network_id) => (@line.network.nil? ? t('lines.index.unset') : @line.network.name),
+ Chouette::Line.tmf(:company_id) => (@line.company.nil? ? t('lines.index.unset') : @line.company.name),
+ Chouette::Line.tmf(:secondary_companies) => (@line.secondary_companies.nil? ? t('lines.index.unset') : array_to_html_list(@line.secondary_companies.collect(&:name))),
+ Chouette::Line.tmf(:number) => @line.number,
+ Chouette::Line.tmf(:registration_number) => (@line.registration_number ? @line.registration_number : '-'),
+ Chouette::Line.tmf(:transport_mode) => (@line.transport_mode.present? ? t("enumerize.transport_mode.#{@line.transport_mode}") : '-'),
+ Chouette::Line.tmf(:transport_submode) => (@line.transport_submode.present? ? t("enumerize.transport_submode.#{@line.transport_submode}") : '-'),
+ Chouette::Line.tmf(:url) => (@line.url ? @line.url : '-'),
+ Chouette::Line.tmf(:seasonal) => (@line.seasonal? ? t('true') : t('false')),}
diff --git a/app/views/referential_companies/_form.html.slim b/app/views/referential_companies/_form.html.slim
index 0e7b20af4..bac6d6694 100644
--- a/app/views/referential_companies/_form.html.slim
+++ b/app/views/referential_companies/_form.html.slim
@@ -9,7 +9,7 @@
= f.input :phone
= f.input :fax
= f.input :email, as: :email
- = f.input :time_zone, include_blank: true
+ = f.input :time_zone, as: :full_time_zone, include_blank: true
= f.input :url
= f.input :registration_number, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@line_referential)}.company.registration_number")}
- if resource.custom_fields(@referential.workgroup).any?
diff --git a/app/views/referential_companies/edit.html.slim b/app/views/referential_companies/edit.html.slim
index 95be64aa1..0c9fb1f87 100644
--- a/app/views/referential_companies/edit.html.slim
+++ b/app/views/referential_companies/edit.html.slim
@@ -1,5 +1,8 @@
- breadcrumb :referential_company, @referential, @company
- page_header_content_for @company
+
.page_content
.container-fluid
- = render 'form'
+ .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/referential_lines/show.html.slim b/app/views/referential_lines/show.html.slim
index 91868a002..e387146d7 100644
--- a/app/views/referential_lines/show.html.slim
+++ b/app/views/referential_lines/show.html.slim
@@ -7,10 +7,10 @@
.col-lg-6.col-md-6.col-sm-12.col-xs-12
= definition_list t('metadatas'),
{ t('id_codif') => @line.get_objectid.short_id,
- Chouette::Line.tmf('activated') => (@line.deactivated? ? t('false') : t('true')),
+ Chouette::Line.tmf('status') => line_status(@line.status),
Chouette::Line.tmf('network_id') => (@line.network.nil? ? t('lines.index.unset') : link_to(@line.network.name, [@referential, @line.network]) ),
Chouette::Line.tmf('company') => (@line.company.nil? ? t('lines.index.unset') : link_to(@line.company.name, [@referential, @line.company]) ),
- Chouette::Line.tmf('secondary_company') => (@line.secondary_companies.nil? ? t('lines.index.unset') : @line.secondary_companies.collect(&:name).join(', ')),
+ Chouette::Line.tmf('secondary_companies') => (@line.secondary_companies.nil? ? t('lines.index.unset') : @line.secondary_companies.collect(&:name).join(', ')),
Chouette::Line.tmf('registration_number') => @line.number,
Chouette::Line.tmf('published_name') => (@line.registration_number ? @line.registration_number : '-'),
Chouette::Line.tmf('transport_mode') => (@line.transport_mode.present? ? t("enumerize.transport_mode.#{@line.transport_mode}") : '-'),
diff --git a/app/views/referential_stop_areas/_form.html.slim b/app/views/referential_stop_areas/_form.html.slim
index 3921c8bf1..bf416ebb0 100644
--- a/app/views/referential_stop_areas/_form.html.slim
+++ b/app/views/referential_stop_areas/_form.html.slim
@@ -30,7 +30,7 @@
= form.input :fare_code, as: :number
= form.input :nearest_topic_name, :input_html => { :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.nearest_topic_name")}
= form.input :comment, as: :text, :input_html => { :rows => 5, :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.comment") }
- = form.input :time_zone, :include_blank => true
+ = form.input :time_zone, as: :full_time_zone, :include_blank => true
= form.input :url
.pmr_info
diff --git a/app/views/referential_stop_areas/show.html.slim b/app/views/referential_stop_areas/show.html.slim
index cb04ab7a6..beee0383f 100644
--- a/app/views/referential_stop_areas/show.html.slim
+++ b/app/views/referential_stop_areas/show.html.slim
@@ -7,10 +7,10 @@
.col-lg-6.col-md-6.col-sm-12.col-xs-12
= definition_list t('metadatas'),
{ t('id_reflex') => @stop_area.try(:user_objectid),
- 'Activé' => (@stop_area.deleted_at ? t('false') : t('true')),
- @stop_area.human_attribute_name(:comment) => @stop_area.try(:comment),
- @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,
- '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 }
+ Chouette::StopArea.tmf(:status) => stop_area_status(@stop_area),
+ Chouette::StopArea.tmf(:comment) => @stop_area.try(:comment),
+ Chouette::StopArea.tmf(:stop_area_type) => t("area_types.label.#{@stop_area.stop_area_type}"),
+ Chouette::StopArea.tmf(:registration_number) => @stop_area.registration_number,
+ Chouette::StopArea.tmf(:coordinates) => geo_data(@stop_area, @stop_area_referential),
+ Chouette::StopArea.tmf(:zip_code) => @stop_area.zip_code,
+ Chouette::StopArea.tmf(:city_name) => @stop_area.city_name } \ No newline at end of file
diff --git a/app/views/referentials/_period_fields.html.slim b/app/views/referentials/_period_fields.html.slim
index 4d2372f7b..b0038c6b3 100644
--- a/app/views/referentials/_period_fields.html.slim
+++ b/app/views/referentials/_period_fields.html.slim
@@ -8,8 +8,8 @@
.wrapper
div
- = f.input :begin, as: :date, label: false, wrapper_html: { class: 'date smart_date' }
+ = f.input :begin, as: :date, label: false, start_year: Date.today.year - 15, end_year: Date.today.year + 15, wrapper_html: { class: 'date smart_date' }
div
- = f.input :end, as: :date, label: false, wrapper_html: { class: 'date smart_date' }
+ = f.input :end, as: :date, label: false, start_year: Date.today.year - 15, end_year: Date.today.year + 15, wrapper_html: { class: 'date smart_date' }
div
= link_to_remove_association '', f, class: 'fa fa-trash', data: { confirm: t('are_you_sure')}, title: t('actions.delete')
diff --git a/app/views/referentials/show.html.slim b/app/views/referentials/show.html.slim
index b2a079ab4..3cdcff63b 100644
--- a/app/views/referentials/show.html.slim
+++ b/app/views/referentials/show.html.slim
@@ -40,8 +40,8 @@
end \
), \
TableBuilderHelper::Column.new( \
- key: :state, \
- attribute: Proc.new { |n| line_status(n.deactivated?) } \
+ key: :status, \
+ attribute: Proc.new { |n| line_status(n.status) } \
), \
TableBuilderHelper::Column.new( \
key: :transport_mode, \
diff --git a/app/views/routes/show.html.slim b/app/views/routes/show.html.slim
index d4571c173..aea824a89 100644
--- a/app/views/routes/show.html.slim
+++ b/app/views/routes/show.html.slim
@@ -34,8 +34,9 @@
end \
), \
TableBuilderHelper::Column.new( \
- name: Chouette::Line.tmf('activated'), \
- attribute: Proc.new { |s| line_status(s.try(:stop_area).deleted_at) } \
+ key: :status, \
+ name: Chouette::StopArea.tmf('status'), \
+ attribute: Proc.new { |s| stop_area_status(s.try(:stop_area)) } \
), \
TableBuilderHelper::Column.new( \
key: :zip_code, \
diff --git a/app/views/stif/dashboards/_dashboard.html.slim b/app/views/stif/dashboards/_dashboard.html.slim
index 7538c7fc7..74e607e26 100644
--- a/app/views/stif/dashboards/_dashboard.html.slim
+++ b/app/views/stif/dashboards/_dashboard.html.slim
@@ -5,8 +5,13 @@
h3.panel-title
= t('.organisation')
- .panel-body
- em.small.text-muted = t('.no_content')
+ - if @dashboard.workbench.output.referentials.present?
+ - @dashboard.workbench.output.referentials.first(5).each do |referential|
+ .list-group
+ = link_to referential.name, referential_path(referential), class: 'list-group-item'
+ - else
+ .panel-body
+ em.small.text-muted = t('.no_content')
.panel.panel-default
.panel-heading
diff --git a/app/views/stop_area_referentials/show.html.slim b/app/views/stop_area_referentials/show.html.slim
index 911006c39..bca89a0f4 100644
--- a/app/views/stop_area_referentials/show.html.slim
+++ b/app/views/stop_area_referentials/show.html.slim
@@ -1,41 +1,29 @@
- breadcrumb :stop_area_referential, @stop_area_referential
-- if policy(@stop_area_referential).synchronize?
- - content_for :page_header_actions do
- = link_to(t('actions.sync'), sync_stop_area_referential_path(@stop_area_referential), method: :post, class: 'btn btn-default')
-
-- content_for :page_header_content do
- .row.mb-md
- .col-lg-12.text-right
- = link_to stop_area_referential_stop_areas_path(@stop_area_referential), class: 'btn btn-primary' do
- = Referential.human_attribute_name(:stop_areas)
- em.small = " (#{@stop_area_referential.stop_areas.count})"
- page_header_content_for @stop_area_referential
.page_content
.container-fluid
.row
.col-lg-12
- - unless @stop_area_referential.stop_area_referential_syncs.empty?
- table.table
- thead
- tr
- th Synchronisé
- th Statut
- th Message
+ = table_builder_2 @stop_area_referential.stop_area_referential_syncs,
+ [ \
+ TableBuilderHelper::Column.new( \
+ name: t('.synchronized'), \
+ attribute: Proc.new { |sync| stop_area_referential_sync_created_at(sync) }, \
+ ), \
+ TableBuilderHelper::Column.new( \
+ name: t('.status'), \
+ attribute: Proc.new { |sync| stop_area_referential_sync_status(sync) }, \
+ ), \
+ TableBuilderHelper::Column.new( \
+ name: t('.message'), \
+ attribute: Proc.new { |sync| stop_area_referential_sync_message(sync) }, \
+ ), \
+ ],
+ sortable: false,
+ cls: 'table'
- tbody
- - @stop_area_referential.stop_area_referential_syncs.each_with_index do |sync, i|
- / Display only 10 msgs
- - if i < 10
- - unless sync.stop_area_referential_sync_messages.empty?
- - sync.stop_area_referential_sync_messages.last.tap do |log|
- - if log.criticity = log.criticity
- tr
- td style='width:150px'
- = l(log.created_at, format: :short_with_time)
- td.text-center
- .fa.fa-circle class="text-#{criticity_class(log.criticity)}"
- td
- - data = log.message_attributes.symbolize_keys!
- - data[:processing_time] = distance_of_time_in_words(data[:processing_time].to_i)
- = t("stop_area_referential_sync.message.#{log.message_key}", log.message_attributes.symbolize_keys!).html_safe
+ - unless @stop_area_referential.stop_area_referential_syncs.any?
+ .row.mt-xs
+ .col-lg-12
+ = replacement_msg t('stop_area_referential_syncs.search_no_results')
diff --git a/app/views/stop_areas/_filters.html.slim b/app/views/stop_areas/_filters.html.slim
index c698eaaa5..caa264d5e 100644
--- a/app/views/stop_areas/_filters.html.slim
+++ b/app/views/stop_areas/_filters.html.slim
@@ -15,7 +15,7 @@
= f.input :area_type_eq_any, checked: params[:q] && params[:q][:area_type_eq_any], collection: Chouette::AreaType.options, as: :check_boxes, label: false, label_method: lambda{|w| ("<span>" + w[0] + "</span>").html_safe}, required: false, wrapper_html: { class: 'checkbox_list' }
.form-group.togglable class=filter_item_class(params[:q], :status)
- = f.label Chouette::StopArea.human_attribute_name(:state), required: false, class: 'control-label'
+ = f.label Chouette::StopArea.tmf('status'), required: false, class: 'control-label'
.form-group.checkbox_list
= f.simple_fields_for :status do |p|
= p.input :in_creation,
diff --git a/app/views/stop_areas/_form.html.slim b/app/views/stop_areas/_form.html.slim
index 00f2ad8bb..2ac316632 100644
--- a/app/views/stop_areas/_form.html.slim
+++ b/app/views/stop_areas/_form.html.slim
@@ -52,7 +52,7 @@
= f.input :fare_code
= f.input :nearest_topic_name, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.nearest_topic_name")}
= f.input :comment, as: :text, :input_html => {:rows => 5, :title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.comment")}
- = f.input :time_zone, :include_blank => true
+ = f.input :time_zone, as: :full_time_zone, include_blank: true
= f.input :url
.pmr_info
@@ -62,10 +62,10 @@
= f.input :stairs_availability, as: :select, :collection => [[t("true"), true], [t("false"), false]], :include_blank => true
= f.input :lift_availability, as: :select, :collection => [[t("true"), true], [t("false"), false]], :include_blank => true
- - if resource.custom_fields(resource.stop_area_referential.workgroup).any?
+ - if resource.custom_fields.present?
.custom_fields
h3 = t("stop_areas.stop_area.custom_fields")
- - resource.custom_fields(resource.stop_area_referential.workgroup).each do |code, field|
+ - resource.custom_fields.each do |code, field|
= field.input(f).to_s
.separator
diff --git a/app/views/stop_areas/index.html.slim b/app/views/stop_areas/index.html.slim
index fbdb54e02..62b873c36 100644
--- a/app/views/stop_areas/index.html.slim
+++ b/app/views/stop_areas/index.html.slim
@@ -32,7 +32,7 @@
attribute: 'registration_number' \
), \
TableBuilderHelper::Column.new( \
- name: Chouette::StopArea.tmf('state'), \
+ key: :status, \
attribute: Proc.new { |s| stop_area_status(s) } \
), \
TableBuilderHelper::Column.new( \
diff --git a/app/views/stop_areas/show.html.slim b/app/views/stop_areas/show.html.slim
index 851bd9b82..c10d22bfb 100644
--- a/app/views/stop_areas/show.html.slim
+++ b/app/views/stop_areas/show.html.slim
@@ -10,18 +10,19 @@
- if has_feature?(:stop_area_localized_names)
- @stop_area.localized_names.each do |k, v|
- - attributes.merge!({label_for_country(k, @stop_area.human_attribute_name(:name)) => v }) if v.present?
- - attributes.merge!({ @stop_area.human_attribute_name(:parent) => @stop_area.parent ? link_to(@stop_area.parent.name, stop_area_referential_stop_area_path(@stop_area_referential, @stop_area.parent)) : "-" }) if @stop_area.commercial?
- - attributes.merge!({ @stop_area.human_attribute_name(:stop_area_type) => Chouette::AreaType.find(@stop_area.area_type).try(:label),
- @stop_area.human_attribute_name(:registration_number) => @stop_area.registration_number,
+ - attributes.merge!({label_for_country(k, Chouette::StopArea.tmf('name')) => v }) if v.present?
+ - attributes.merge!({ Chouette::StopArea.tmf('parent') => @stop_area.parent ? link_to(@stop_area.parent.name, stop_area_referential_stop_area_path(@stop_area_referential, @stop_area.parent)) : "-" }) if @stop_area.commercial?
+ - attributes.merge!({ Chouette::StopArea.tmf('stop_area_type') => Chouette::AreaType.find(@stop_area.area_type).try(:label),
+ Chouette::StopArea.tmf('registration_number') => @stop_area.registration_number,
})
- - attributes.merge!(@stop_area.human_attribute_name(:waiting_time) => @stop_area.waiting_time_text) if has_feature?(:stop_area_waiting_time)
+ - attributes.merge!(Chouette::StopArea.tmf('waiting_time') => @stop_area.waiting_time_text) if has_feature?(:stop_area_waiting_time)
- attributes.merge!({ "Coordonnées" => geo_data(@stop_area, @stop_area_referential),
- @stop_area.human_attribute_name(:zip_code) => @stop_area.zip_code,
- @stop_area.human_attribute_name(:city_name) => @stop_area.city_name,
- @stop_area.human_attribute_name(:country_code) => @stop_area.country_code.presence || '-',
- t('activerecord.attributes.stop_area.state') => stop_area_status(@stop_area),
- @stop_area.human_attribute_name(:comment) => @stop_area.try(:comment),
+ Chouette::StopArea.tmf('zip_code') => @stop_area.zip_code,
+ Chouette::StopArea.tmf('city_name') => @stop_area.city_name,
+ Chouette::StopArea.tmf('country_code') => @stop_area.country_code.presence || '-',
+ Chouette::StopArea.tmf('time_zone') => @stop_area.time_zone.presence || '-',
+ Chouette::StopArea.tmf('status') => stop_area_status(@stop_area),
+ Chouette::StopArea.tmf('comment') => @stop_area.try(:comment),
})
- @stop_area.custom_fields.each do |code, field|
- attributes.merge!(field.name => field.display_value)
diff --git a/app/views/vehicle_journeys/index.html.slim b/app/views/vehicle_journeys/index.html.slim
index 7fcee545f..2af0e5345 100644
--- a/app/views/vehicle_journeys/index.html.slim
+++ b/app/views/vehicle_journeys/index.html.slim
@@ -33,6 +33,7 @@
| window.all_missions = #{(@all_missions.to_json).html_safe};
| window.custom_fields = #{(@custom_fields.to_json).html_safe};
| window.extra_headers = #{(@extra_headers.to_json).html_safe};
+ | window.constraint_zones_routes = "#{url_for([@referential, @route.line, :routing_constraint_zones]).html_safe}";
- if has_feature?(:vehicle_journeys_return_route)
= javascript_tag do
diff --git a/app/views/vehicle_journeys/show.rabl b/app/views/vehicle_journeys/show.rabl
index d218038a6..3a551f237 100644
--- a/app/views/vehicle_journeys/show.rabl
+++ b/app/views/vehicle_journeys/show.rabl
@@ -1,6 +1,6 @@
object @vehicle_journey
-[:objectid, :published_journey_name, :published_journey_identifier, :company_id, :comment, :checksum, :custom_fields].each do |attr|
+[:objectid, :published_journey_name, :published_journey_identifier, :company_id, :comment, :checksum, :custom_fields, :ignored_routing_contraint_zone_ids].each do |attr|
attributes attr, :unless => lambda { |m| m.send( attr).nil?}
end
@@ -17,7 +17,7 @@ child(:route) do |route|
end
child(:journey_pattern) do |journey_pattern|
- attributes :id, :objectid, :name, :published_name
+ attributes :id, :objectid, :name, :published_name, :journey_length
node(:short_id) {journey_pattern.get_objectid.short_id}
end
diff --git a/app/workers/route_way_cost_worker.rb b/app/workers/route_way_cost_worker.rb
index d6bfed592..b62416c3d 100644
--- a/app/workers/route_way_cost_worker.rb
+++ b/app/workers/route_way_cost_worker.rb
@@ -7,10 +7,11 @@ class RouteWayCostWorker
# Prevent recursive worker spawning since this call updates the
# `costs` field of the route.
- Chouette::Route.skip_callback(:save, :after, :calculate_costs!)
-
- RouteWayCostCalculator.new(route).calculate!
-
- Chouette::Route.set_callback(:save, :after, :calculate_costs!)
+ begin
+ Chouette::Route.skip_callback(:commit, :after, :calculate_costs!)
+ RouteWayCostCalculator.new(route).calculate!
+ ensure
+ Chouette::Route.set_callback(:commit, :after, :calculate_costs!)
+ end
end
end