diff options
Diffstat (limited to 'app')
87 files changed, 762 insertions, 388 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/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/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/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/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..921a2cf7f 100644 --- a/app/controllers/vehicle_journeys_controller.rb +++ b/app/controllers/vehicle_journeys_controller.rb @@ -208,6 +208,7 @@ class VehicleJourneysController < ChouetteController short_id: item.get_objectid.short_id, full_schedule: item.full_schedule?, costs: item.costs, + journey_length: item.journey_length, stop_area_short_descriptions: item.stop_areas.map do |stop| { stop_area_short_description: { 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..a01d901e6 100644 --- a/app/helpers/referentials_helper.rb +++ b/app/helpers/referentials_helper.rb @@ -1,13 +1,15 @@ 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) + def line_status(status, verbose=true) if status - content_tag(:span, nil, class: 'fa fa-exclamation-circle fa-lg text-danger') + - t('activerecord.attributes.line.deactivated') + out = content_tag(:span, nil, class: 'fa fa-exclamation-circle fa-lg text-danger') + out += t('activerecord.attributes.line.deactivated') if verbose + out else - content_tag(:span, nil, class: 'fa fa-check-circle fa-lg text-success') + - t('activerecord.attributes.line.activated') + out = content_tag(:span, nil, class: 'fa fa-check-circle fa-lg text-success') + out += t('activerecord.attributes.line.activated') if verbose + out 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/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js b/app/javascript/helpers/CustomFieldsInputs.js index 827c36b76..abc8097d5 100644 --- a/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js +++ b/app/javascript/helpers/CustomFieldsInputs.js @@ -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} + 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} + 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/StopPoint.js b/app/javascript/routes/components/StopPoint.js index 768d069c0..908e97263 100644 --- a/app/javascript/routes/components/StopPoint.js +++ b/app/javascript/routes/components/StopPoint.js @@ -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> 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("'", "\'") if(v.zip_code && v.city_name) fancyText += ", " + v.zip_code + " " + v.city_name.replace("'", "\'") + 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("'", "\'") : '', 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("'", "\'") : '', 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 7c79dfe52..a5c454a18 100644 --- a/app/javascript/time_tables/actions/index.js +++ b/app/javascript/time_tables/actions/index.js @@ -191,10 +191,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 @@ -235,12 +238,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..70d6e953a 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', @@ -339,16 +327,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/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js index 73d99d120..5eb73de0e 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) } @@ -115,6 +119,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..27e147b37 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 && diff --git a/app/javascript/vehicle_journeys/components/tools/CreateModal.js b/app/javascript/vehicle_journeys/components/tools/CreateModal.js index f49b51f08..1d470cd43 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) { 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/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/journey_pattern.rb b/app/models/chouette/journey_pattern.rb index 830a6a808..4b4cc2c73 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 @@ -52,12 +53,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 +86,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 +167,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 +187,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/purchase_window.rb b/app/models/chouette/purchase_window.rb index e10b106ec..d22674637 100644 --- a/app/models/chouette/purchase_window.rb +++ b/app/models/chouette/purchase_window.rb @@ -46,8 +46,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 9c7a3e6d9..a5eab3002 100644 --- a/app/models/chouette/route.rb +++ b/app/models/chouette/route.rb @@ -7,6 +7,16 @@ module Chouette include ObjectidSupport extend Enumerize + 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 in Route #{id} : #{positions.inspect}" + end + end + end + enumerize :direction, in: %i(straight_forward backward clockwise counter_clockwise north north_west west south_west south south_east east north_east) enumerize :wayback, in: %i(outbound inbound), default: :outbound @@ -68,8 +78,14 @@ 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 = { 'opposite_route_id' => nil, 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..6f2d89578 100644 --- a/app/models/chouette/stop_point.rb +++ b/app/models/chouette/stop_point.rb @@ -9,7 +9,6 @@ module Chouette include ForAlightingEnumerations include ObjectidSupport - belongs_to :stop_area belongs_to :route, inverse_of: :stop_points has_many :vehicle_journey_at_stops, :dependent => :destroy @@ -17,7 +16,6 @@ module Chouette 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 +26,7 @@ module Chouette scope :default_order, -> { order("position") } - delegate :name, to: :stop_area + delegate :name, :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/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb index 54aad290c..c269d478e 100644 --- a/app/models/chouette/vehicle_journey.rb +++ b/app/models/chouette/vehicle_journey.rb @@ -244,11 +244,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 +278,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 diff --git a/app/models/concerns/checksum_support.rb b/app/models/concerns/checksum_support.rb index 92103798e..de3a6e16b 100644 --- a/app/models/concerns/checksum_support.rb +++ b/app/models/concerns/checksum_support.rb @@ -40,6 +40,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(',') diff --git a/app/models/concerns/custom_fields_support.rb b/app/models/concerns/custom_fields_support.rb index 46fc8e73d..c39dfd1fc 100644 --- a/app/models/concerns/custom_fields_support.rb +++ b/app/models/concerns/custom_fields_support.rb @@ -28,6 +28,10 @@ module CustomFieldsSupport 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| diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index 22118a15a..88783b5b4 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -7,10 +7,6 @@ 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 vals = object.class.custom_fields(workgroup).map do |v| @@ -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" @@ -191,9 +191,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 +202,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 +232,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 +251,10 @@ class CustomField < ApplicationModel end end + def checksum + owner.send digest_name + end + def value owner.send "custom_field_#{code}" end @@ -246,6 +271,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/merge.rb b/app/models/merge.rb index 6e2a7036a..8d661f209 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 @@ -371,7 +371,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/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/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/index.html.slim b/app/views/lines/index.html.slim index 9d491ace4..4d4ba938d 100644 --- a/app/views/lines/index.html.slim +++ b/app/views/lines/index.html.slim @@ -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..b683b9be6 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(:state) => line_status(@line.deactivated), + 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/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..4804da527 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('state') => line_status(@line.deactivated), 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/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/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/vehicle_journeys/show.rabl b/app/views/vehicle_journeys/show.rabl index d218038a6..6c588416c 100644 --- a/app/views/vehicle_journeys/show.rabl +++ b/app/views/vehicle_journeys/show.rabl @@ -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 |
