From 43dd9a4abc58b9c7cf2203a5e7125a7788bb33b3 Mon Sep 17 00:00:00 2001 From: Zog Date: Wed, 27 Dec 2017 08:36:47 +0100 Subject: Refs #5419; Fix actions policies Fix actions conditions on VehicleJourney#index --- app/javascript/vehicle_journeys/components/Tools.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/javascript/vehicle_journeys/components/Tools.js b/app/javascript/vehicle_journeys/components/Tools.js index 1ef576529..99ce78eb1 100644 --- a/app/javascript/vehicle_journeys/components/Tools.js +++ b/app/javascript/vehicle_journeys/components/Tools.js @@ -25,13 +25,13 @@ export default class Tools extends Component { return (
{actions.getSelected(vehicleJourneys).length} course(s) sélectionnée(s) -- cgit v1.2.3 From 78e2d256f895c1014a3def5f2ef6509086755215 Mon Sep 17 00:00:00 2001 From: Zog Date: Wed, 27 Dec 2017 09:10:56 +0100 Subject: 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 --- app/controllers/vehicle_journeys_controller.rb | 1 + app/javascript/packs/vehicle_journeys/index.js | 3 +- app/javascript/vehicle_journeys/actions/index.js | 34 +++++ .../components/SaveVehicleJourneys.js | 2 +- .../vehicle_journeys/components/Tools.js | 11 +- .../vehicle_journeys/components/VehicleJourney.js | 23 +++- .../vehicle_journeys/components/VehicleJourneys.js | 8 +- .../tools/PurchaseWindowsEditVehicleJourney.js | 150 +++++++++++++++++++++ .../tools/PurchaseWindowsEditVehicleJourney.js | 38 ++++++ app/javascript/vehicle_journeys/reducers/modal.js | 51 ++++++- .../vehicle_journeys/reducers/vehicleJourneys.js | 15 +++ app/models/chouette/vehicle_journey.rb | 5 + .../journey_patterns_collections/show.html.slim | 1 + app/views/vehicle_journeys/index.html.slim | 1 + app/views/vehicle_journeys/show.rabl | 6 + spec/javascript/vehicle_journeys/actions_spec.js | 89 ++++++++++++ .../vehicle_journeys/reducers/modal_spec.js | 82 +++++++++++ .../reducers/vehicleJourneys_spec.js | 13 +- 18 files changed, 525 insertions(+), 8 deletions(-) create mode 100644 app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js create mode 100644 app/javascript/vehicle_journeys/containers/tools/PurchaseWindowsEditVehicleJourney.js 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( , 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 { + { this.hasFeature('purchase_windows') && + + } @@ -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 ( + + ) + } + 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 (
@@ -57,6 +70,14 @@ export default class VehicleJourney extends Component { )} {time_tables.length > 3 && + {time_tables.length - 3}}
+ { this.hasFeature('purchase_windows') && +
+ {purchase_windows.slice(0,3).map((tt, i)=> + {this.purchaseWindowURL(tt)} + )} + {purchase_windows.length > 3 && + {purchase_windows.length - 3}} +
+ }
ID course
ID mission
Calendriers
+ { this.hasFeature('purchase_windows') &&
Calendriers Commerciaux
}
{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 ( +
  • + + +
    +
    +
    +
    +
    +

    Calendriers commerciaux associés

    + × +
    + + {(this.props.modal.type == 'purchase_windows_edit') && ( +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + {this.props.modal.modalProps.purchase_windows.map((tt, i) => + + )} + { + this.props.editMode && +
    +
    +
    + +
    +
    +
    + } +
    +
    +
    +
    + { + this.props.editMode && +
    + + +
    + } +
    + )} + +
    +
    +
    +
    +
  • + ) + } 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 diff --git a/spec/javascript/vehicle_journeys/actions_spec.js b/spec/javascript/vehicle_journeys/actions_spec.js index 789507482..683b64505 100644 --- a/spec/javascript/vehicle_journeys/actions_spec.js +++ b/spec/javascript/vehicle_journeys/actions_spec.js @@ -209,6 +209,13 @@ describe('when clicking on edit notes modal', () => { expect(actions.openNotesEditModal(vehicleJourney)).toEqual(expectedAction) }) }) + + // ___ ___ ___ _____ _ _ ___ _____ ___ ___ + // | __/ _ \ / _ \_ _| \| |/ _ \_ _| __/ __| + // | _| (_) | (_) || | | .` | (_) || | | _|\__ \ + // |_| \___/ \___/ |_| |_|\_|\___/ |_| |___|___/ + // + describe('when clicking on a footnote button inside footnote modal', () => { it('should create an action to toggle this footnote', () => { const footnote = {}, isShown = true @@ -230,6 +237,13 @@ describe('when clicking on validate button inside footnote modal', () => { expect(actions.editVehicleJourneyNotes(footnotes)).toEqual(expectedAction) }) }) + + // _____ ___ __ __ ___ _____ _ ___ _ ___ ___ + // |_ _|_ _| \/ | __|_ _/_\ | _ ) | | __/ __| + // | | | || |\/| | _| | |/ _ \| _ \ |__| _|\__ \ + // |_| |___|_| |_|___| |_/_/ \_\___/____|___|___/ + // + describe('when clicking on calendar button in toolbox', () => { it('should create an action to open calendar modal', () => { const vehicleJourneys = [] @@ -288,6 +302,81 @@ describe('when using select2 to pick a timetable', () => { expect(actions.selectTTCalendarsModal(selectedTT)).toEqual(expectedAction) }) }) + + // ___ _ _ ___ ___ _ _ _ ___ ___ + // | _ \ | | | _ \/ __| || | /_\ / __| __| + // | _/ |_| | / (__| __ |/ _ \\__ \ _| + // |_| \___/|_|_\\___|_||_/_/_\_\___/___|__ + // \ \ / /_ _| \| | \ / _ \ \ / / __| + // \ \/\/ / | || .` | |) | (_) \ \/\/ /\__ \ + // \_/\_/ |___|_|\_|___/ \___/ \_/\_/ |___/ + // + +describe('when clicking on purchase window button in toolbox', () => { + it('should create an action to open purchase window modal', () => { + const vehicleJourneys = [] + const expectedAction = { + type: 'EDIT_PURCHASE_WINDOWS_VEHICLEJOURNEY_MODAL', + vehicleJourneys + } + expect(actions.openPurchaseWindowsEditModal(vehicleJourneys)).toEqual(expectedAction) + }) +}) +describe('when clicking on delete button next to a purchase window inside modal', () => { + it('should create an action to delete purchase window from selected vehicle journeys', () => { + const purchaseWindow = {} + const expectedAction = { + type: 'DELETE_PURCHASE_WINDOW_MODAL', + purchaseWindow + } + expect(actions.deletePurchaseWindowsModal(purchaseWindow)).toEqual(expectedAction) + }) +}) +describe('when clicking on validate button inside purchase windows modal', () => { + it('should create an action to update vj purchase windows', () => { + const vehicleJourneys = [] + const purchase_windows = [] + const expectedAction = { + type: 'EDIT_VEHICLEJOURNEYS_PURCHASE_WINDOWS', + vehicleJourneys, + purchase_windows + } + expect(actions.editVehicleJourneyPurchaseWindows(vehicleJourneys, timetables)).toEqual(expectedAction) + }) +}) +describe('when clicking on add button inside purchase windows modal', () => { + it('should create an action to add the selected purchase window to preselected vjs', () => { + const expectedAction = { + type: 'ADD_SELECTED_PURCHASE_WINDOW', + } + expect(actions.addSelectedPurchaseWindow()).toEqual(expectedAction) + }) +}) +describe('when using select2 to pick a purchase window', () => { + it('should create an action to select a purchase window inside modal', () => { + let selectedTT = { + id: 1, + objectid: 2, + comment: 'test', + } + const expectedAction = { + type: 'SELECT_PURCHASE_WINDOW_MODAL', + selectedItem:{ + id: selectedTT.id, + objectid: selectedTT.objectid, + comment: selectedTT.comment, + } + } + expect(actions.selectPurchaseWindowsModal(selectedTT)).toEqual(expectedAction) + }) +}) + + // ___ ___ _ _____ ___ ___ ___ + // | __|_ _| ||_ _| __| _ \/ __| + // | _| | || |__| | | _|| /\__ \ + // |_| |___|____|_| |___|_|_\|___/ + // + describe('when clicking on reset button inside query filters', () => { it('should create an action to reset the query filters', () => { const expectedAction = { diff --git a/spec/javascript/vehicle_journeys/reducers/modal_spec.js b/spec/javascript/vehicle_journeys/reducers/modal_spec.js index 69de9168b..ea8a002d2 100644 --- a/spec/javascript/vehicle_journeys/reducers/modal_spec.js +++ b/spec/javascript/vehicle_journeys/reducers/modal_spec.js @@ -91,6 +91,12 @@ describe('modal reducer', () => { ).toEqual(newState) }) + // _____ ___ __ __ ___ _____ _ ___ _ ___ ___ + // |_ _|_ _| \/ | __|_ _/_\ | _ ) | | __/ __| + // | | | || |\/| | _| | |/ _ \| _ \ |__| _|\__ \ + // |_| |___|_| |_|___| |_/_/ \_\___/____|___|___/ + // + it('should handle EDIT_CALENDARS_VEHICLEJOURNEY_MODAL', () => { let vehicleJourneys = [] let modalPropsResult = { @@ -158,6 +164,82 @@ describe('modal reducer', () => { ).toEqual(newState) }) + // ___ _ _ ___ ___ _ _ _ ___ ___ + // | _ \ | | | _ \/ __| || | /_\ / __| __| + // | _/ |_| | / (__| __ |/ _ \\__ \ _| + // |_| \___/|_|_\\___|_||_/_/_\_\___/___|__ + // \ \ / /_ _| \| | \ / _ \ \ / / __| + // \ \/\/ / | || .` | |) | (_) \ \/\/ /\__ \ + // \_/\_/ |___|_|\_|___/ \___/ \_/\_/ |___/ + // + + it('should handle EDIT_PURCHASE_WINDOWS_VEHICLEJOURNEY_MODAL', () => { + let vehicleJourneys = [] + let modalPropsResult = { + vehicleJourneys: [], + purchase_windows: [] + } + expect( + modalReducer(state, { + type: 'EDIT_PURCHASE_WINDOWS_VEHICLEJOURNEY_MODAL', + vehicleJourneys + }) + ).toEqual(Object.assign({}, state, {type: 'purchase_windows_edit', modalProps: modalPropsResult})) + }) + + it('should handle SELECT_PURCHASE_WINDOW_MODAL', () => { + let newModalProps = {selectedPurchaseWindow : {id: 1}} + expect( + modalReducer(state, { + type: 'SELECT_PURCHASE_WINDOW_MODAL', + selectedItem: {id: 1} + }) + ).toEqual(Object.assign({}, state, {modalProps: newModalProps})) + }) + + it('should handle ADD_SELECTED_PURCHASE_WINDOW', () => { + let fakeWindows = [{'test': 'test'}, {'test 2': 'test 2'}] + let newWindows = [{'test': 'test'}, {'test 2': 'test 2'}, {'add': 'add'}] + let fakeVehicleJourneys= [{purchase_windows: fakeWindows}, {purchase_windows: newWindows}] + state.modalProps.vehicleJourneys = fakeVehicleJourneys + state.modalProps.purchase_windows = fakeWindows + state.modalProps.selectedPurchaseWindow = {'add': 'add'} + let newState = { + type: '', + modalProps:{ + vehicleJourneys: fakeVehicleJourneys, + purchase_windows: [{'test': 'test'},{'test 2': 'test 2'},{'add': 'add'}], + selectedPurchaseWindow: {'add': 'add'} + }, + confirmModal: {} + } + expect( + modalReducer(state, { + type: 'ADD_SELECTED_PURCHASE_WINDOW', + }) + ).toEqual(newState) + }) + + it('should handle DELETE_PURCHASE_WINDOW_MODAL', () => { + let deletableWindow = {'delete': 'delete'} + let fakeWindows = [{'test': 'test'}, {'test 2': 'test 2'}, deletableWindow] + let newWindows = [{'test': 'test'}, {'test 2': 'test 2'}] + let fakeVehicleJourneys= [{purchase_windows: fakeWindows}, {purchase_windows: newWindows}] + state.modalProps = Object.assign({}, state.modalProps,{vehicleJourneys : fakeVehicleJourneys, purchase_windows: fakeWindows }) + let newState = { + // for the sake of the test, no need to specify the type + type: '', + modalProps:{vehicleJourneys: [{purchase_windows: newWindows},{purchase_windows: newWindows}], purchase_windows: newWindows}, + confirmModal: {} + } + expect( + modalReducer(state, { + type: 'DELETE_PURCHASE_WINDOW_MODAL', + purchaseWindow: deletableWindow + }) + ).toEqual(newState) + }) + it('should handle SELECT_CP_EDIT_MODAL', () => { let newModalProps = {selectedCompany : {name: 'ALBATRANS'}} expect( diff --git a/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js b/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js index 1c2cc1577..c834de1f6 100644 --- a/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js +++ b/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js @@ -254,7 +254,6 @@ describe('vehicleJourneys reducer', () => { ).toEqual([newVJ, state[1]]) }) - it('should handle EDIT_VEHICLEJOURNEYS_TIMETABLES', () => { let newState = JSON.parse(JSON.stringify(state)) newState[0].time_tables = [fakeTimeTables[0]] @@ -266,4 +265,16 @@ describe('vehicleJourneys reducer', () => { }) ).toEqual(newState) }) + + it('should handle EDIT_VEHICLEJOURNEYS_PURCHASE_WINDOWS', () => { + let newState = JSON.parse(JSON.stringify(state)) + newState[0].purchase_windows = [fakeTimeTables[0]] + expect( + vjReducer(state, { + type: 'EDIT_VEHICLEJOURNEYS_PURCHASE_WINDOWS', + vehicleJourneys: state, + purchase_windows: [fakeTimeTables[0]] + }) + ).toEqual(newState) + }) }) -- cgit v1.2.3 From 607fa5e03289a10b60a773bc40af38f1d721bbea Mon Sep 17 00:00:00 2001 From: Zog Date: Wed, 27 Dec 2017 13:42:39 +0100 Subject: Refs #5407 @2h; Model implementation - Link PurchaseWindows to VehicleJourneys in the model - Add an autocompletion endpoint --- .../autocomplete_purchase_windows_controller.rb | 12 ++++++++ app/javascript/vehicle_journeys/actions/index.js | 3 +- .../vehicle_journeys/components/Filters.js | 3 +- .../tools/PurchaseWindowsEditVehicleJourney.js | 1 + .../tools/TimetablesEditVehicleJourney.js | 9 +++--- .../components/tools/select2s/TimetableSelect2.js | 14 ++++----- app/models/calendar/period.rb | 2 +- app/models/chouette/purchase_window.rb | 2 ++ app/models/chouette/vehicle_journey.rb | 6 +--- app/models/concerns/period_support.rb | 4 +-- app/views/autocomplete_purchase_windows/index.rabl | 12 ++++++++ config/routes.rb | 1 + ...join_table_purchase_windows_vehicle_journeys.rb | 10 +++++++ db/schema.rb | 11 ++++++-- ...utocomplete_purchase_windows_controller_spec.rb | 33 ++++++++++++++++++++++ spec/models/chouette/vehicle_journey_spec.rb | 1 + 16 files changed, 99 insertions(+), 25 deletions(-) create mode 100644 app/controllers/autocomplete_purchase_windows_controller.rb create mode 100644 app/views/autocomplete_purchase_windows/index.rabl create mode 100644 db/migrate/20171227113809_create_join_table_purchase_windows_vehicle_journeys.rb create mode 100644 spec/controllers/autocomplete_purchase_windows_controller_spec.rb diff --git a/app/controllers/autocomplete_purchase_windows_controller.rb b/app/controllers/autocomplete_purchase_windows_controller.rb new file mode 100644 index 000000000..70dc5a346 --- /dev/null +++ b/app/controllers/autocomplete_purchase_windows_controller.rb @@ -0,0 +1,12 @@ +class AutocompletePurchaseWindowsController < ChouetteController + respond_to :json, :only => [:index] + + requires_feature :purchase_windows + + include ReferentialSupport + + protected + def collection + @purchase_windows = referential.purchase_windows.search(params[:q]).result.paginate(page: params[:page]) + end +end diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js index d5eda629c..9a5ca940b 100644 --- a/app/javascript/vehicle_journeys/actions/index.js +++ b/app/javascript/vehicle_journeys/actions/index.js @@ -107,7 +107,8 @@ const actions = { type: 'SELECT_PURCHASE_WINDOW_MODAL', selectedItem:{ id: selectedTT.id, - comment: selectedTT.comment, + name: selectedTT.name, + color: selectedTT.color, objectid: selectedTT.objectid } }), diff --git a/app/javascript/vehicle_journeys/components/Filters.js b/app/javascript/vehicle_journeys/components/Filters.js index db6707520..3bc4f7ff7 100644 --- a/app/javascript/vehicle_journeys/components/Filters.js +++ b/app/javascript/vehicle_journeys/components/Filters.js @@ -33,6 +33,7 @@ export default function Filters({filters, pagination, onFilter, onResetFilters, onSelect2Timetable={onSelect2Timetable} hasRoute={true} chunkURL={("/autocomplete_time_tables.json?route_id=" + String(window.route_id))} + searchKey={"comment_or_objectid_cont_any"} filters={filters} isFilter={true} /> @@ -165,4 +166,4 @@ Filters.propTypes = { onSelect2Timetable: PropTypes.func.isRequired, onSelect2JourneyPattern: PropTypes.func.isRequired, onSelect2VehicleJourney: 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 index cf51e50f0..5465127e8 100644 --- a/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/PurchaseWindowsEditVehicleJourney.js @@ -95,6 +95,7 @@ export default class PurchaseWindowsEditVehicleJourney extends Component { diff --git a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js index 6629135dd..26377c0d5 100644 --- a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js @@ -67,7 +67,7 @@ export default class TimetablesEditVehicleJourney extends Component {
    {tt.comment}
    { - this.props.editMode && + this.props.editMode &&
    )} { - this.props.editMode && + this.props.editMode &&
    @@ -103,7 +104,7 @@ export default class TimetablesEditVehicleJourney extends Component {
    { - this.props.editMode && + this.props.editMode &&
    diff --git a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js index 26377c0d5..56f80ebb5 100644 --- a/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/tools/TimetablesEditVehicleJourney.js @@ -33,6 +33,7 @@ export default class TimetablesEditVehicleJourney extends Component { data-toggle='modal' data-target='#CalendarsEditVehicleJourneyModal' onClick={() => this.props.onOpenCalendarsEditModal(actions.getSelected(this.props.vehicleJourneys))} + title='Calendriers' > -- cgit v1.2.3 From 590c63521cc29a3704e93f326e8f9b7c300b71d8 Mon Sep 17 00:00:00 2001 From: Zog Date: Wed, 27 Dec 2017 15:40:25 +0100 Subject: Refs #5407; Add cancel button on VehicleJourneys editor --- .../components/SaveVehicleJourneys.js | 32 +++++++++++++++------- .../containers/SaveVehicleJourneys.js | 4 +++ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js index 285e2d506..5e69af301 100644 --- a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js +++ b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js @@ -14,16 +14,27 @@ export default class SaveVehicleJourneys extends Component{
    {e.preventDefault()}}> - +
    + + {this.props.editMode && + } +
    @@ -38,5 +49,6 @@ SaveVehicleJourneys.propTypes = { status: PropTypes.object.isRequired, filters: PropTypes.object.isRequired, onEnterEditMode: PropTypes.func.isRequired, + onExitEditMode: PropTypes.func.isRequired, onSubmitVehicleJourneys: PropTypes.func.isRequired } diff --git a/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js index 18f9e994e..f5f879ed8 100644 --- a/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js +++ b/app/javascript/vehicle_journeys/containers/SaveVehicleJourneys.js @@ -17,6 +17,10 @@ const mapDispatchToProps = (dispatch) => { onEnterEditMode: () => { dispatch(actions.enterEditMode()) }, + onExitEditMode: () => { + dispatch(actions.cancelSelection()) + dispatch(actions.exitEditMode()) + }, onSubmitVehicleJourneys: (next, state) => { actions.submitVehicleJourneys(dispatch, state, next) } -- cgit v1.2.3 From 6f182a9e12094297818745752e592dc11511563e Mon Sep 17 00:00:00 2001 From: Zog Date: Wed, 27 Dec 2017 15:53:51 +0100 Subject: Refs #5407; Make Journeys easier to select --- app/javascript/vehicle_journeys/components/VehicleJourney.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js index 7a89bcc66..54fe1f1b6 100644 --- a/app/javascript/vehicle_journeys/components/VehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js @@ -61,7 +61,12 @@ export default class VehicleJourney extends Component { return (
    -
    +
    + ($(e.target).parents("a").length == 0) && this.props.editMode && this.props.onSelectVehicleJourney(this.props.index) + } + >
    {this.props.value.short_id || '-'}
    {this.props.value.journey_pattern.short_id || '-'}
    -- cgit v1.2.3 From 3792c128de8a2355ce6b4ceb28e7ee8afdf060c7 Mon Sep 17 00:00:00 2001 From: Zog Date: Wed, 27 Dec 2017 16:03:55 +0100 Subject: Refs #5407; Disable edition mode while editor is loading --- app/javascript/packs/vehicle_journeys/index.js | 2 +- app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/packs/vehicle_journeys/index.js b/app/javascript/packs/vehicle_journeys/index.js index 7e57afb04..53c5d5417 100644 --- a/app/javascript/packs/vehicle_journeys/index.js +++ b/app/javascript/packs/vehicle_journeys/index.js @@ -55,7 +55,7 @@ var initialState = { }, status: { - fetchSuccess: true, + fetchSuccess: false, isFetching: false }, vehicleJourneys: [], diff --git a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js index 5e69af301..8bab5baa9 100644 --- a/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js +++ b/app/javascript/vehicle_journeys/components/SaveVehicleJourneys.js @@ -16,7 +16,7 @@ export default class SaveVehicleJourneys extends Component{
    {e.preventDefault()}}>