diff options
| author | Zog | 2017-12-27 09:10:56 +0100 | 
|---|---|---|
| committer | Zog | 2017-12-27 12:08:07 +0100 | 
| commit | 78e2d256f895c1014a3def5f2ef6509086755215 (patch) | |
| tree | bce880b597b1baa9ce681b444cf6f8219189abb2 /app | |
| parent | 43dd9a4abc58b9c7cf2203a5e7125a7788bb33b3 (diff) | |
| download | chouette-core-78e2d256f895c1014a3def5f2ef6509086755215.tar.bz2 | |
Refs #5407 @4h; First UI implementation
- Add most of the react code
- And the specs where possible
Still remains:
- Link PurchaseWindows to VehicleJourneys in the model
- Add an autocompletion endpoint
Diffstat (limited to 'app')
15 files changed, 342 insertions, 7 deletions
| diff --git a/app/controllers/vehicle_journeys_controller.rb b/app/controllers/vehicle_journeys_controller.rb index c941aeae4..7d16d1c75 100644 --- a/app/controllers/vehicle_journeys_controller.rb +++ b/app/controllers/vehicle_journeys_controller.rb @@ -164,6 +164,7 @@ class VehicleJourneysController < ChouetteController        %w{create destroy update}.inject({}) do | permissions, action |          permissions.merge( "vehicle_journeys.#{action}" => policy.authorizes_action?(action) )        end.to_json +    @features = Hash[*current_organisation.features.map{|f| [f, true]}.flatten].to_json    end    private diff --git a/app/javascript/packs/vehicle_journeys/index.js b/app/javascript/packs/vehicle_journeys/index.js index 38431af1d..7e57afb04 100644 --- a/app/javascript/packs/vehicle_journeys/index.js +++ b/app/javascript/packs/vehicle_journeys/index.js @@ -23,6 +23,7 @@ var initialState = {    filters: {      selectedJourneyPatterns : selectedJP,      policy: window.perms, +    features: window.features,      toggleArrivals: false,      queryString: '',      query: { @@ -99,4 +100,4 @@ render(      <App />    </Provider>,    document.getElementById('vehicle_journeys_wip') -)
\ 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 c82f759d6..d5eda629c 100644 --- a/app/javascript/vehicle_journeys/actions/index.js +++ b/app/javascript/vehicle_journeys/actions/index.js @@ -99,6 +99,30 @@ const actions = {      vehicleJourneys,      timetables    }), +  openPurchaseWindowsEditModal : (vehicleJourneys) => ({ +    type : 'EDIT_PURCHASE_WINDOWS_VEHICLEJOURNEY_MODAL', +    vehicleJourneys +  }), +  selectPurchaseWindowsModal: (selectedTT) =>({ +    type: 'SELECT_PURCHASE_WINDOW_MODAL', +    selectedItem:{ +      id: selectedTT.id, +      comment: selectedTT.comment, +      objectid: selectedTT.objectid +    } +  }), +  addSelectedPurchaseWindow: () => ({ +    type: 'ADD_SELECTED_PURCHASE_WINDOW' +  }), +  deletePurchaseWindowsModal : (purchaseWindow) => ({ +    type : 'DELETE_PURCHASE_WINDOW_MODAL', +    purchaseWindow +  }), +  editVehicleJourneyPurchaseWindows : (vehicleJourneys, purchase_windows) => ({ +    type: 'EDIT_VEHICLEJOURNEYS_PURCHASE_WINDOWS', +    vehicleJourneys, +    purchase_windows +  }),    openShiftModal : () => ({      type : 'SHIFT_VEHICLEJOURNEY_MODAL'    }), @@ -313,6 +337,7 @@ const actions = {            let val            for (val of json.vehicle_journeys){              var timeTables = [] +            var purchaseWindows = []              let tt              for (tt of val.time_tables){                timeTables.push({ @@ -322,6 +347,14 @@ const actions = {                  color: tt.color                })              } +            for (tt of val.purchase_windows){ +              purchaseWindows.push({ +                objectid: tt.objectid, +                name: tt.name, +                id: tt.id, +                color: tt.color +              }) +            }              let vjasWithDelta = val.vehicle_journey_at_stops.map((vjas, i) => {                actions.fillEmptyFields(vjas)                return actions.getDelta(vjas) @@ -333,6 +366,7 @@ const actions = {                short_id: val.short_id,                footnotes: val.footnotes,                time_tables: timeTables, +              purchase_windows: purchaseWindows,                vehicle_journey_at_stops: vjasWithDelta,                deletable: false,                selected: false, diff --git a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js index e8c27f92e..285e2d506 100644 --- a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js +++ b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js @@ -39,4 +39,4 @@ SaveVehicleJourneys.propTypes = {    filters: PropTypes.object.isRequired,    onEnterEditMode: PropTypes.func.isRequired,    onSubmitVehicleJourneys: PropTypes.func.isRequired -}
\ No newline at end of file +} diff --git a/app/javascript/vehicle_journeys/components/Tools.js b/app/javascript/vehicle_journeys/components/Tools.js index 99ce78eb1..be32552b9 100644 --- a/app/javascript/vehicle_journeys/components/Tools.js +++ b/app/javascript/vehicle_journeys/components/Tools.js @@ -7,6 +7,7 @@ import DuplicateVehicleJourney from '../containers/tools/DuplicateVehicleJourney  import EditVehicleJourney from '../containers/tools/EditVehicleJourney'  import NotesEditVehicleJourney from '../containers/tools/NotesEditVehicleJourney'  import TimetablesEditVehicleJourney from '../containers/tools/TimetablesEditVehicleJourney' +import PurchaseWindowsEditVehicleJourney from '../containers/tools/PurchaseWindowsEditVehicleJourney'  export default class Tools extends Component { @@ -20,6 +21,11 @@ export default class Tools extends Component {      return this.props.filters.policy[`vehicle_journeys.${key}`]    } +  hasFeature(key) { +    // Check if the organisation has the given feature +    return this.props.filters.features[key] +  } +    render() {      let { vehicleJourneys, onCancelSelection, editMode } = this.props      return ( @@ -30,6 +36,9 @@ export default class Tools extends Component {            <ShiftVehicleJourney disabled={!this.hasPolicy("update") || !editMode}/>            <EditVehicleJourney disabled={!this.hasPolicy("update")}/>            <TimetablesEditVehicleJourney disabled={!this.hasPolicy("update")}/> +          { this.hasFeature('purchase_windows') && +            <PurchaseWindowsEditVehicleJourney disabled={!this.hasPolicy("update")}/> +          }            <NotesEditVehicleJourney disabled={!this.hasPolicy("update")}/>            <DeleteVehicleJourneys disabled={!this.hasPolicy("destroy") || !editMode}/>          </ul> @@ -44,5 +53,5 @@ export default class Tools extends Component {  Tools.propTypes = {    vehicleJourneys : PropTypes.array.isRequired,    onCancelSelection: PropTypes.func.isRequired, -  filters: PropTypes.object.isRequired +  filters: PropTypes.object.isRequired,  } diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js index bde673345..7a89bcc66 100644 --- a/app/javascript/vehicle_journeys/components/VehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js @@ -17,6 +17,10 @@ export default class VehicleJourney extends Component {      return bool    } +  hasFeature(key) { +    return this.props.filters.features[key] +  } +    timeTableURL(tt) {      let refURL = window.location.pathname.split('/', 3).join('/')      let ttURL = refURL + '/time_tables/' + tt.id @@ -26,6 +30,15 @@ export default class VehicleJourney extends Component {      )    } +  purchaseWindowURL(tt) { +    let refURL = window.location.pathname.split('/', 3).join('/') +    let ttURL = refURL + '/purchase_windows/' + tt.id + +    return ( +      <a href={ttURL} title='Voir le calendrier commercial'><span className='fa fa-calendar' style={{color: (tt.color ? tt.color : '')}}></span></a> +    ) +  } +    columnHasDelta() {      let a = []      this.props.value.vehicle_journey_at_stops.map((vj, i) => { @@ -44,7 +57,7 @@ export default class VehicleJourney extends Component {    render() {      this.previousCity = undefined -    let {time_tables} = this.props.value +    let {time_tables, purchase_windows} = this.props.value      return (        <div className={'t2e-item' + (this.props.value.deletable ? ' disabled' : '') + (this.props.value.errors ? ' has-error': '')}> @@ -57,6 +70,14 @@ export default class VehicleJourney extends Component {              )}              {time_tables.length > 3 && <span className='vj_tt'> + {time_tables.length - 3}</span>}            </div> +          { this.hasFeature('purchase_windows') && +            <div> +              {purchase_windows.slice(0,3).map((tt, i)=> +                <span key={i} className='vj_tt'>{this.purchaseWindowURL(tt)}</span> +              )} +              {purchase_windows.length > 3 && <span className='vj_tt'> + {purchase_windows.length - 3}</span>} +            </div> +          }            <div className={(this.props.value.deletable ? 'disabled ' : '') + 'checkbox'}>              <input                id={this.props.index} diff --git a/app/javascript/vehicle_journeys/components/VehicleJourneys.js b/app/javascript/vehicle_journeys/components/VehicleJourneys.js index 6bce9766b..e16d03f90 100644 --- a/app/javascript/vehicle_journeys/components/VehicleJourneys.js +++ b/app/javascript/vehicle_journeys/components/VehicleJourneys.js @@ -12,6 +12,10 @@ export default class VehicleJourneys extends Component {      this.props.onLoadFirstPage(this.props.filters)    } +  hasFeature(key) { +    return this.props.filters.features[key] +  } +    componentDidUpdate(prevProps, prevState) {      if(this.props.status.isFetching == false){        $('.table-2entries').each(function() { @@ -113,6 +117,7 @@ export default class VehicleJourneys extends Component {                    <div className='strong mb-xs'>ID course</div>                    <div>ID mission</div>                    <div>Calendriers</div> +                  { this.hasFeature('purchase_windows') && <div>Calendriers Commerciaux</div> }                  </div>                  {this.props.stopPointsList.map((sp, i) =>{                    return ( @@ -132,6 +137,7 @@ export default class VehicleJourneys extends Component {                        index={index}                        editMode={this.props.editMode}                        filters={this.props.filters} +                      features={this.props.features}                        onUpdateTime={this.props.onUpdateTime}                        onSelectVehicleJourney={this.props.onSelectVehicleJourney}                        /> @@ -153,4 +159,4 @@ VehicleJourneys.propTypes = {    onLoadFirstPage: PropTypes.func.isRequired,    onUpdateTime: PropTypes.func.isRequired,    onSelectVehicleJourney: PropTypes.func.isRequired -}
\ No newline at end of file +} diff --git a/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js new file mode 100644 index 000000000..cf51e50f0 --- /dev/null +++ b/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js @@ -0,0 +1,150 @@ +import React, { PropTypes, Component } from 'react' +import actions from '../../actions' +import TimetableSelect2 from './select2s/TimetableSelect2' + +export default class PurchaseWindowsEditVehicleJourney extends Component { +  constructor(props) { +    super(props) +    this.handleSubmit = this.handleSubmit.bind(this) +    this.purchaseWindowURL = this.purchaseWindowURL.bind(this) +  } + +  handleSubmit() { +    this.props.onTimetablesEditVehicleJourney(this.props.modal.modalProps.vehicleJourneys, this.props.modal.modalProps.purchase_windows) +    this.props.onModalClose() +    $('#PurchaseWindowsEditVehicleJourneyModal').modal('hide') +  } + +  purchaseWindowURL(tt) { +    let refURL = window.location.pathname.split('/', 3).join('/') +    return refURL + '/purchase_windows/' + tt.id +  } + +  render() { +    if(this.props.status.isFetching == true) { +      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='#PurchaseWindowsEditVehicleJourneyModal' +            onClick={() => this.props.onOpenCalendarsEditModal(actions.getSelected(this.props.vehicleJourneys))} +          > +            <span className='fa fa-calendar'></span> +          </button> + +          <div className={ 'modal fade ' + ((this.props.modal.type == 'duplicate') ? 'in' : '') } id='PurchaseWindowsEditVehicleJourneyModal'> +            <div className='modal-container'> +              <div className='modal-dialog'> +                <div className='modal-content'> +                  <div className='modal-header'> +                    <h4 className='modal-title'>Calendriers commerciaux associés</h4> +                    <span type="button" className="close modal-close" data-dismiss="modal">×</span> +                  </div> + +                  {(this.props.modal.type == 'purchase_windows_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.props.modal.modalProps.purchase_windows.length == 0 ? "Aucun calendrier commercial associé" : "Calendriers commerciaux associés"}</label> +                                    </div> +                                  </div> +                                  <div></div> +                                </div> +                              </div> +                              {this.props.modal.modalProps.purchase_windows.map((tt, i) => +                                <div className='nested-fields' key={i}> +                                  <div className='wrapper'> +                                    <div> <a href={this.purchaseWindowURL(tt)} target="_blank"> +                                      <span className="fa fa-circle mr-xs" style={{color: tt.color}}></span> +                                      {tt.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.onDeleteCalendarModal(tt) +                                          }} +                                        ></a> +                                      </div> +                                    } +                                  </div> +                                </div> +                              )} +                              { +                                this.props.editMode && +                                <div className='nested-fields'> +                                  <div className='wrapper'> +                                    <div> +                                      <TimetableSelect2 +                                        onSelect2Timetable={this.props.onSelect2Timetable} +                                        chunkURL={'/autocomplete_purchase_windows.json'} +                                        isFilter={false} +                                      /> +                                    </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} +                          > +                            Annuler +                          </button> +                          <button +                            className='btn btn-primary' +                            type='button' +                            onClick={this.handleSubmit} +                          > +                            Valider +                          </button> +                        </div> +                      } +                    </form> +                  )} + +                </div> +              </div> +            </div> +          </div> +        </li> +      ) +    } else { +      return false +    } +  } +} + +PurchaseWindowsEditVehicleJourney.propTypes = { +  onOpenCalendarsEditModal: PropTypes.func.isRequired, +  onModalClose: PropTypes.func.isRequired, +  onTimetablesEditVehicleJourney: PropTypes.func.isRequired, +  onDeleteCalendarModal: PropTypes.func.isRequired, +  onSelect2Timetable: PropTypes.func.isRequired, +  disabled: PropTypes.bool.isRequired +} diff --git a/app/javascript/vehicle_journeys/containers/tools/PurchaseWindowsEditVehicleJourney.js b/app/javascript/vehicle_journeys/containers/tools/PurchaseWindowsEditVehicleJourney.js new file mode 100644 index 000000000..f81c8fa72 --- /dev/null +++ b/app/javascript/vehicle_journeys/containers/tools/PurchaseWindowsEditVehicleJourney.js @@ -0,0 +1,38 @@ +import actions from '../../actions' +import { connect } from 'react-redux' +import PurchaseWindowsEditVehicleJourneyComponent from '../../components/tools/PurchaseWindowsEditVehicleJourney' + +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.openPurchaseWindowsEditModal(vehicleJourneys)) +    }, +    onDeleteCalendarModal: (timetable) => { +      dispatch(actions.deletePurchaseWindowsModal(timetable)) +    }, +    onTimetablesEditVehicleJourney: (vehicleJourneys, timetables) =>{ +      dispatch(actions.editVehicleJourneyPurchaseWindows(vehicleJourneys, timetables)) +    }, +    onSelect2Timetable: (e) =>{ +      dispatch(actions.selectPurchaseWindowsModal(e.params.data)) +      dispatch(actions.addSelectedPurchaseWindow()) +    } +  } +} + +const PurchaseWindowsEditVehicleJourney = connect(mapStateToProps, mapDispatchToProps)(PurchaseWindowsEditVehicleJourneyComponent) + +export default PurchaseWindowsEditVehicleJourney diff --git a/app/javascript/vehicle_journeys/reducers/modal.js b/app/javascript/vehicle_journeys/reducers/modal.js index 57f54a144..862e27e1b 100644 --- a/app/javascript/vehicle_journeys/reducers/modal.js +++ b/app/javascript/vehicle_journeys/reducers/modal.js @@ -40,7 +40,6 @@ export default function modal(state = {}, action) {      case 'EDIT_CALENDARS_VEHICLEJOURNEY_MODAL':        vehicleJourneysModal = JSON.parse(JSON.stringify(action.vehicleJourneys))        let uniqTimetables = [] -      let timetable = {}        vehicleJourneysModal.map((vj, i) => {          vj.time_tables.map((tt, j) =>{            if(!(_.find(uniqTimetables, tt))){ @@ -56,6 +55,24 @@ export default function modal(state = {}, action) {          },          confirmModal: {}        } +    case 'EDIT_PURCHASE_WINDOWS_VEHICLEJOURNEY_MODAL': +      var vehicleJourneys = JSON.parse(JSON.stringify(action.vehicleJourneys)) +      let uniqPurchaseWindows = [] +      vehicleJourneys.map((vj, i) => { +        vj.purchase_windows.map((pw, j) =>{ +          if(!(_.find(uniqPurchaseWindows, pw))){ +            uniqPurchaseWindows.push(pw) +          } +        }) +      }) +      return { +        type: 'purchase_windows_edit', +        modalProps: { +          vehicleJourneys: vehicleJourneys, +          purchase_windows: uniqPurchaseWindows +        }, +        confirmModal: {} +      }      case 'SELECT_CP_EDIT_MODAL':        newModalProps = _.assign({}, state.modalProps, {selectedCompany : action.selectedItem})        return _.assign({}, state, {modalProps: newModalProps}) @@ -65,6 +82,9 @@ 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}) +      return _.assign({}, state, {modalProps: newModalProps})      case 'ADD_SELECTED_TIMETABLE':        if(state.modalProps.selectedTimetable){          newModalProps = JSON.parse(JSON.stringify(state.modalProps)) @@ -73,6 +93,14 @@ export default function modal(state = {}, action) {          }          return _.assign({}, state, {modalProps: newModalProps})        } +    case 'ADD_SELECTED_PURCHASE_WINDOW': +      if(state.modalProps.selectedPurchaseWindow){ +        newModalProps = JSON.parse(JSON.stringify(state.modalProps)) +        if (!_.find(newModalProps.purchase_windows, newModalProps.selectedPurchaseWindow)){ +          newModalProps.purchase_windows.push(newModalProps.selectedPurchaseWindow) +        } +        return _.assign({}, state, {modalProps: newModalProps}) +      }      case 'DELETE_CALENDAR_MODAL':        newModalProps = JSON.parse(JSON.stringify(state.modalProps))        let timetablesModal = state.modalProps.timetables.slice(0) @@ -92,6 +120,25 @@ export default function modal(state = {}, action) {        newModalProps.vehicleJourneys = vehicleJourneysModal        newModalProps.timetables = timetablesModal        return _.assign({}, state, {modalProps: newModalProps}) +    case 'DELETE_PURCHASE_WINDOW_MODAL': +        newModalProps = JSON.parse(JSON.stringify(state.modalProps)) +        let purchase_windows = state.modalProps.purchase_windows.slice(0) +        purchase_windows.map((tt, i) =>{ +          if(tt == action.purchaseWindow){ +            purchase_windows.splice(i, 1) +          } +        }) +        vehicleJourneysModal = state.modalProps.vehicleJourneys.slice(0) +        vehicleJourneysModal.map((vj) =>{ +          vj.purchase_windows.map((tt, i) =>{ +            if (_.isEqual(tt, action.purchaseWindow)){ +              vj.purchase_windows.splice(i, 1) +            } +          }) +        }) +        newModalProps.vehicleJourneys = vehicleJourneysModal +        newModalProps.purchase_windows = purchase_windows +        return _.assign({}, state, {modalProps: newModalProps})      case 'CREATE_VEHICLEJOURNEY_MODAL':        let selectedJP = {}        if (window.jpOrigin){ @@ -135,4 +182,4 @@ export default function modal(state = {}, action) {      default:        return state    } -}
\ No newline at end of file +} diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js index 7fed867fa..15d6abe38 100644 --- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js +++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js @@ -155,6 +155,21 @@ export default function vehicleJourneys(state = [], action) {            return vj          }        }) +      case 'EDIT_VEHICLEJOURNEYS_PURCHASE_WINDOWS': +        let newWindows = JSON.parse(JSON.stringify(action.purchase_windows)) +        return state.map((vj,i) =>{ +          if(vj.selected){ +            let updatedVJ = _.assign({}, vj) +            action.vehicleJourneys.map((vjm, j) =>{ +              if(vj.objectid == vjm.objectid){ +                updatedVJ.purchase_windows = newWindows +              } +            }) +            return updatedVJ +          }else{ +            return vj +          } +        })      case 'SHIFT_VEHICLEJOURNEY':        return state.map((vj, i) => {          if (vj.selected){ diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb index 247c30668..8a2435fbc 100644 --- a/app/models/chouette/vehicle_journey.rb +++ b/app/models/chouette/vehicle_journey.rb @@ -40,6 +40,11 @@ module Chouette      before_validation :set_default_values,        :calculate_vehicle_journey_at_stop_day_offset +    # XXX +    def purchase_windows +      Chouette::PurchaseWindow.limit(2) +    end +      # TODO: Remove this validator      # We've eliminated this validation because it prevented vehicle journeys      # from being saved with at-stops having a day offset greater than 0, diff --git a/app/views/journey_patterns_collections/show.html.slim b/app/views/journey_patterns_collections/show.html.slim index 834501da3..97a62f7db 100644 --- a/app/views/journey_patterns_collections/show.html.slim +++ b/app/views/journey_patterns_collections/show.html.slim @@ -18,5 +18,6 @@    | window.journeyPatternLength = #{@journey_patterns.total_entries()};    | window.journeyPatternsPerPage = #{@ppage};    | window.perms = #{raw @perms} +  | window.features = #{raw @features};  = javascript_pack_tag 'journey_patterns/index.js' diff --git a/app/views/vehicle_journeys/index.html.slim b/app/views/vehicle_journeys/index.html.slim index 4ad9d524d..595646808 100644 --- a/app/views/vehicle_journeys/index.html.slim +++ b/app/views/vehicle_journeys/index.html.slim @@ -25,6 +25,7 @@    | window.vehicleJourneysPerPage = #{@ppage};    | window.line_footnotes = #{raw @footnotes};    | window.perms = #{raw @perms}; +  | window.features = #{raw @features};    | window.I18n = #{(I18n.backend.send(:translations).to_json).html_safe};  = javascript_pack_tag 'vehicle_journeys/index.js' diff --git a/app/views/vehicle_journeys/show.rabl b/app/views/vehicle_journeys/show.rabl index 830dee8bd..371b3d812 100644 --- a/app/views/vehicle_journeys/show.rabl +++ b/app/views/vehicle_journeys/show.rabl @@ -28,6 +28,12 @@ child(:time_tables, :object_root => false) do |time_tables|    end  end +if has_feature? :purchase_windows +  child(:purchase_windows, :object_root => false) do |purchase_windows| +    attributes :id, :objectid, :name, :color +  end +end +  child :footnotes, :object_root => false do |footnotes|    attributes :id, :code, :label  end | 
