aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuc Donnet2018-01-11 22:19:50 +0100
committerGitHub2018-01-11 22:19:50 +0100
commit266563da6b501c319156c06628b8a3702fd84fd4 (patch)
treef5e54f4d579da66c26328945019a8e263a835ef7
parentd01f7668bf8dca08fc34c7e27e87e6284070fbd7 (diff)
parentdab42556bd956aa07fa2e423e85a647c166b9e0e (diff)
downloadchouette-core-266563da6b501c319156c06628b8a3702fd84fd4.tar.bz2
Merge pull request #227 from af83/5551-handle-custom-fields-in-vjs-editor
5551 Handle custom fields in VJs editor
-rw-r--r--app/controllers/application_controller.rb5
-rw-r--r--app/controllers/vehicle_journeys_controller.rb5
-rw-r--r--app/javascript/packs/vehicle_journeys/index.js3
-rw-r--r--app/javascript/vehicle_journeys/components/tools/CreateModal.js9
-rw-r--r--app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js50
-rw-r--r--app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js17
-rw-r--r--app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js1
-rw-r--r--app/javascript/vehicle_journeys/reducers/custom_fields.js6
-rw-r--r--app/javascript/vehicle_journeys/reducers/index.js4
-rw-r--r--app/javascript/vehicle_journeys/reducers/vehicleJourneys.js5
-rw-r--r--app/models/chouette/vehicle_journey.rb10
-rw-r--r--app/models/workgroup.rb4
-rw-r--r--app/views/vehicle_journeys/index.html.slim1
-rw-r--r--app/views/vehicle_journeys/show.rabl2
-rw-r--r--spec/javascript/vehicle_journeys/components/CustomFieldsInputs_spec.js42
-rw-r--r--spec/javascript/vehicle_journeys/components/__snapshots__/CustomFieldsInputs_spec.js.snap3
-rw-r--r--spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js24
-rw-r--r--spec/models/chouette/vehicle_journey_spec.rb7
-rw-r--r--spec/models/custom_field_spec.rb11
19 files changed, 193 insertions, 16 deletions
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 474277da1..80d194096 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -41,6 +41,11 @@ class ApplicationController < ActionController::Base
end
helper_method :current_offer_workbench
+ def current_workgroup
+ current_offer_workbench.workgroup
+ end
+ helper_method :current_workgroup
+
def current_functional_scope
functional_scope = current_organisation.sso_attributes.try(:[], "functional_scope") if current_organisation
JSON.parse(functional_scope) if functional_scope
diff --git a/app/controllers/vehicle_journeys_controller.rb b/app/controllers/vehicle_journeys_controller.rb
index c5466abe5..eb3367d0c 100644
--- a/app/controllers/vehicle_journeys_controller.rb
+++ b/app/controllers/vehicle_journeys_controller.rb
@@ -49,6 +49,7 @@ class VehicleJourneysController < ChouetteController
end
format.html do
load_missions
+ load_custom_fields
@stop_points_list = []
@stop_points_list = route.stop_points.includes(:stop_area).map do |sp|
{
@@ -177,6 +178,10 @@ class VehicleJourneysController < ChouetteController
end
private
+ def load_custom_fields
+ @custom_fields = current_workgroup.custom_fields_definitions
+ end
+
def load_missions
@all_missions = route.journey_patterns.count > 10 ? [] : route.journey_patterns.map do |item|
{
diff --git a/app/javascript/packs/vehicle_journeys/index.js b/app/javascript/packs/vehicle_journeys/index.js
index ab28371fe..aa5738d59 100644
--- a/app/javascript/packs/vehicle_journeys/index.js
+++ b/app/javascript/packs/vehicle_journeys/index.js
@@ -71,7 +71,8 @@ var initialState = {
modalProps: {},
confirmModal: {}
},
- missions: window.all_missions
+ missions: window.all_missions,
+ custom_fields: window.custom_fields
}
if (window.jpOrigin){
diff --git a/app/javascript/vehicle_journeys/components/tools/CreateModal.js b/app/javascript/vehicle_journeys/components/tools/CreateModal.js
index 07c684760..90328458b 100644
--- a/app/javascript/vehicle_journeys/components/tools/CreateModal.js
+++ b/app/javascript/vehicle_journeys/components/tools/CreateModal.js
@@ -3,15 +3,17 @@ import PropTypes from 'prop-types'
import actions from '../../actions'
import MissionSelect2 from './select2s/MissionSelect2'
import CompanySelect2 from './select2s/CompanySelect2'
+import CustomFieldsInputs from './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, $('.vjCreateSelectJP')[0]) && this.props.modal.modalProps.selectedJPModal) {
- this.props.onAddVehicleJourney(this.refs, this.props.modal.modalProps.selectedJPModal, this.props.stopPointsList, this.props.modal.modalProps.vehicleJourney && this.props.modal.modalProps.vehicleJourney.company)
+ this.props.onAddVehicleJourney(_.assign({}, this.refs, {custom_fields: this.custom_fields}), this.props.modal.modalProps.selectedJPModal, this.props.stopPointsList, this.props.modal.modalProps.vehicleJourney && this.props.modal.modalProps.vehicleJourney.company)
this.props.onModalClose()
$('#NewVehicleJourneyModal').modal('hide')
}
@@ -89,6 +91,11 @@ 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}
+ />
{ this.props.modal.modalProps.selectedJPModal && this.props.modal.modalProps.selectedJPModal.full_schedule && <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12'>
<div className='form-group'>
<label className='control-label'>Heure de départ</label>
diff --git a/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js b/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js
new file mode 100644
index 000000000..90d72a801
--- /dev/null
+++ b/app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs.js
@@ -0,0 +1,50 @@
+import _ from 'lodash'
+import Select2 from 'react-select2-wrapper'
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+
+export default class CustomFieldsInputs extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ listInput(cf){
+ return(
+ <Select2
+ data={_.map(cf.options.list_values, (v, k) => {
+ return {id: k, text: (v.length > 0 ? v : '\u00A0')}
+ })}
+ ref={'custom_fields.' + cf.code}
+ className='form-control'
+ defaultValue={cf.value}
+ disabled={this.props.disabled}
+ options={{
+ theme: 'bootstrap',
+ width: '100%'
+ }}
+ onSelect={(e) => this.props.onUpdate(cf.code, e.params.data.id) }
+ />
+ )
+ }
+
+ render() {
+ return (
+ <div>
+ {_.map(this.props.values, (cf, code) =>
+ <div className='col-lg-6 col-md-6 col-sm-6 col-xs-12' key={code}>
+ <div className='form-group'>
+ <label className='control-label'>{cf.name}</label>
+ {this[cf.field_type + "Input"](cf)}
+ </div>
+ </div>
+ )}
+ </div>
+ )
+ }
+}
+
+CustomFieldsInputs.propTypes = {
+ onUpdate: PropTypes.func.isRequired,
+ values: PropTypes.object.isRequired,
+ disabled: PropTypes.bool.isRequired
+}
diff --git a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
index 08d74baba..2893422f8 100644
--- a/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/components/tools/EditVehicleJourney.js
@@ -2,6 +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'
export default class EditVehicleJourney extends Component {
constructor(props) {
@@ -15,8 +16,8 @@ export default class EditVehicleJourney extends Component {
company = this.props.modal.modalProps.selectedCompany
} else if (typeof this.props.modal.modalProps.vehicleJourney.company === "object") {
company = this.props.modal.modalProps.vehicleJourney.company
- }
- this.props.onEditVehicleJourney(this.refs, company)
+ }
+ this.props.onEditVehicleJourney(_.assign({}, this.refs, {custom_fields: this.custom_fields}), company)
this.props.onModalClose()
$('#EditVehicleJourneyModal').modal('hide')
}
@@ -27,6 +28,9 @@ export default class EditVehicleJourney extends Component {
return false
}
if(this.props.status.fetchSuccess == true) {
+ if(this.props.modal.modalProps.vehicleJourney){
+ this.custom_fields = _.assign({}, this.props.modal.modalProps.vehicleJourney.custom_fields)
+ }
return (
<li className='st_action'>
<button
@@ -140,8 +144,15 @@ export default class EditVehicleJourney extends Component {
defaultValue={this.props.modal.modalProps.vehicleJourney.checksum}
/>
</div>
-
+ <div className='row'>
+ <CustomFieldsInputs
+ values={this.props.modal.modalProps.vehicleJourney.custom_fields}
+ onUpdate={(code, value) => this.custom_fields[code]["value"] = value}
+ disabled={!this.props.editMode}
+ />
+ </div>
</div>
+
{
this.props.editMode &&
<div className='modal-footer'>
diff --git a/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js b/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js
index 0f4a0ea7d..0db7628be 100644
--- a/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js
+++ b/app/javascript/vehicle_journeys/containers/tools/AddVehicleJourney.js
@@ -10,6 +10,7 @@ const mapStateToProps = (state, ownProps) => {
status: state.status,
stopPointsList: state.stopPointsList,
missions: state.missions,
+ custom_fields: state.custom_fields,
}
}
diff --git a/app/javascript/vehicle_journeys/reducers/custom_fields.js b/app/javascript/vehicle_journeys/reducers/custom_fields.js
new file mode 100644
index 000000000..482fd91cb
--- /dev/null
+++ b/app/javascript/vehicle_journeys/reducers/custom_fields.js
@@ -0,0 +1,6 @@
+export default function custom_fields(state = [], action) {
+ switch (action.type) {
+ default:
+ return state
+ }
+}
diff --git a/app/javascript/vehicle_journeys/reducers/index.js b/app/javascript/vehicle_journeys/reducers/index.js
index 862c864ae..1963f7c6d 100644
--- a/app/javascript/vehicle_journeys/reducers/index.js
+++ b/app/javascript/vehicle_journeys/reducers/index.js
@@ -7,6 +7,7 @@ import filters from './filters'
import editMode from './editMode'
import stopPointsList from './stopPointsList'
import missions from './missions'
+import custom_fields from './custom_fields'
const vehicleJourneysApp = combineReducers({
vehicleJourneys,
@@ -16,7 +17,8 @@ const vehicleJourneysApp = combineReducers({
filters,
editMode,
stopPointsList,
- missions
+ missions,
+ custom_fields
})
export default vehicleJourneysApp
diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
index 0549c7adc..62b846d9a 100644
--- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
@@ -54,6 +54,7 @@ const vehicleJourney= (state = {}, action, keep) => {
pristineVjasList.push(newVjas)
})
+
return {
company: action.selectedCompany,
journey_pattern: action.selectedJourneyPattern,
@@ -68,7 +69,8 @@ const vehicleJourney= (state = {}, action, keep) => {
selected: false,
deletable: false,
transport_mode: window.transportMode ? window.transportMode : 'undefined',
- transport_submode: window.transportSubmode ? window.transportSubmode : 'undefined'
+ transport_submode: window.transportSubmode ? window.transportSubmode : 'undefined',
+ custom_fields: action.data.custom_fields
}
case 'DUPLICATE_VEHICLEJOURNEY':
case 'SHIFT_VEHICLEJOURNEY':
@@ -148,6 +150,7 @@ export default function vehicleJourneys(state = [], action) {
company: action.selectedCompany,
published_journey_name: action.data.published_journey_name.value,
published_journey_identifier: action.data.published_journey_identifier.value,
+ custom_fields: action.data.custom_fields,
})
}else{
return vj
diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb
index 67216e422..8a704d8c0 100644
--- a/app/models/chouette/vehicle_journey.rb
+++ b/app/models/chouette/vehicle_journey.rb
@@ -224,6 +224,7 @@ module Chouette
['company', 'journey_pattern'].map do |association|
attrs["#{association}_id"] = item[association]['id'] if item[association]
end
+ attrs["custom_field_values"] = Hash[*(item["custom_fields"] || {}).map{|k, v| [k, v["value"]]}.flatten]
attrs
end
@@ -262,8 +263,15 @@ module Chouette
end
end
+ def self.custom_fields
+ CustomField.where(resource_type: self.name.split("::").last)
+ end
+
+
def custom_fields
- CustomField.where(resource_type: self.class.name.split("::").last)
+ Hash[*self.class.custom_fields.map do |v|
+ [v.code, v.slice(:code, :name, :field_type, :options).update(value: custom_field_value(v.code))]
+ end.flatten]
end
def custom_field_value key
diff --git a/app/models/workgroup.rb b/app/models/workgroup.rb
index 995917fac..511bbfeb0 100644
--- a/app/models/workgroup.rb
+++ b/app/models/workgroup.rb
@@ -11,4 +11,8 @@ class Workgroup < ActiveRecord::Base
validates_presence_of :stop_area_referential_id
has_many :custom_fields
+
+ def custom_fields_definitions
+ Hash[*custom_fields.map{|cf| [cf.code, cf]}.flatten]
+ end
end
diff --git a/app/views/vehicle_journeys/index.html.slim b/app/views/vehicle_journeys/index.html.slim
index 66e90d839..f7796b188 100644
--- a/app/views/vehicle_journeys/index.html.slim
+++ b/app/views/vehicle_journeys/index.html.slim
@@ -27,6 +27,7 @@
| window.perms = #{raw @perms};
| window.features = #{raw @features};
| window.all_missions = #{(@all_missions.to_json).html_safe};
+ | window.custom_fields = #{(@custom_fields.to_json).html_safe};
| 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 df1eca016..fc65e6cb6 100644
--- a/app/views/vehicle_journeys/show.rabl
+++ b/app/views/vehicle_journeys/show.rabl
@@ -1,6 +1,6 @@
object @vehicle_journey
-[:objectid, :published_journey_name, :published_journey_identifier, :company_id, :comment, :checksum].each do |attr|
+[:objectid, :published_journey_name, :published_journey_identifier, :company_id, :comment, :checksum, :custom_fields].each do |attr|
attributes attr, :unless => lambda { |m| m.send( attr).nil?}
end
diff --git a/spec/javascript/vehicle_journeys/components/CustomFieldsInputs_spec.js b/spec/javascript/vehicle_journeys/components/CustomFieldsInputs_spec.js
new file mode 100644
index 000000000..62013354a
--- /dev/null
+++ b/spec/javascript/vehicle_journeys/components/CustomFieldsInputs_spec.js
@@ -0,0 +1,42 @@
+import React, { Component } from 'react'
+import CustomFieldsInputs from '../../../../app/javascript/vehicle_journeys/components/tools/CustomFieldsInputs'
+import renderer from 'react-test-renderer'
+require('select2')
+console.log($().jquery)
+
+describe('CustomFieldsInputs', () => {
+ set('values', () => {
+ return {}
+ })
+
+ set('component', () => {
+ let inputs = renderer.create(
+ <CustomFieldsInputs
+ values={values}
+ disabled={false}
+ onUpdate={()=>{}}
+ />
+ ).toJSON()
+
+ return inputs
+ })
+
+ it('should match the snapshot', () => {
+ expect(component).toMatchSnapshot()
+ })
+
+ context('with fields', () => {
+ set('values', () => {
+ return {
+ foo: {
+ options: { list_values: ["", "1", "2"] },
+ field_type: "list",
+ name: "test"
+ }
+ }
+ })
+ it('should match the snapshot', () => {
+ expect(component).toMatchSnapshot()
+ })
+ })
+})
diff --git a/spec/javascript/vehicle_journeys/components/__snapshots__/CustomFieldsInputs_spec.js.snap b/spec/javascript/vehicle_journeys/components/__snapshots__/CustomFieldsInputs_spec.js.snap
new file mode 100644
index 000000000..c93ec0097
--- /dev/null
+++ b/spec/javascript/vehicle_journeys/components/__snapshots__/CustomFieldsInputs_spec.js.snap
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CustomFieldsInputs should match the snapshot 1`] = `<div />`;
diff --git a/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js b/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js
index 44e11aadf..573eebf4f 100644
--- a/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js
+++ b/spec/javascript/vehicle_journeys/reducers/vehicleJourneys_spec.js
@@ -89,7 +89,12 @@ describe('vehicleJourneys reducer', () => {
}]
let fakeData = {
published_journey_name: {value: 'test'},
- published_journey_identifier: {value : ''}
+ published_journey_identifier: {value : ''},
+ custom_fields: {
+ foo: {
+ value: 12
+ }
+ }
}
let fakeSelectedJourneyPattern = {id: "1"}
let fakeSelectedCompany = {name: "ALBATRANS"}
@@ -115,7 +120,12 @@ describe('vehicleJourneys reducer', () => {
selected: false,
deletable: false,
transport_mode: 'undefined',
- transport_submode: 'undefined'
+ transport_submode: 'undefined',
+ custom_fields: {
+ foo: {
+ value: 12
+ }
+ }
}, ...state])
})
@@ -345,12 +355,18 @@ describe('vehicleJourneys reducer', () => {
})
it('should handle EDIT_VEHICLEJOURNEY', () => {
+ let custom_fields = {
+ foo: {
+ value: 12
+ }
+ }
let fakeData = {
published_journey_name: {value : 'test'},
- published_journey_identifier: {value: 'test'}
+ published_journey_identifier: {value: 'test'},
+ custom_fields: {foo: 12}
}
let fakeSelectedCompany : {name : 'ALBATRANS'}
- let newVJ = Object.assign({}, state[0], {company: fakeSelectedCompany, published_journey_name: fakeData.published_journey_name.value, published_journey_identifier: fakeData.published_journey_identifier.value})
+ let newVJ = Object.assign({}, state[0], {company: fakeSelectedCompany, published_journey_name: fakeData.published_journey_name.value, published_journey_identifier: fakeData.published_journey_identifier.value, custom_fields})
expect(
vjReducer(state, {
type: 'EDIT_VEHICLEJOURNEY',
diff --git a/spec/models/chouette/vehicle_journey_spec.rb b/spec/models/chouette/vehicle_journey_spec.rb
index 0beec2d81..2a88ac3ce 100644
--- a/spec/models/chouette/vehicle_journey_spec.rb
+++ b/spec/models/chouette/vehicle_journey_spec.rb
@@ -82,6 +82,7 @@ describe Chouette::VehicleJourney, :type => :model do
item['purchase_windows'] = []
item['footnotes'] = []
item['purchase_windows'] = []
+ item['custom_fields'] = vj.custom_fields
vj.vehicle_journey_at_stops.each do |vjas|
item['vehicle_journey_at_stops'] << vehicle_journey_at_stop_to_state(vjas)
@@ -96,7 +97,8 @@ describe Chouette::VehicleJourney, :type => :model do
let(:collection) { [state] }
it 'should create new vj from state' do
- new_vj = build(:vehicle_journey, objectid: nil, published_journey_name: 'dummy', route: route, journey_pattern: journey_pattern)
+ create(:custom_field, code: :energy)
+ new_vj = build(:vehicle_journey, objectid: nil, published_journey_name: 'dummy', route: route, journey_pattern: journey_pattern, custom_field_values: {energy: 99})
collection << vehicle_journey_to_state(new_vj)
expect {
Chouette::VehicleJourney.state_update(route, collection)
@@ -112,6 +114,7 @@ describe Chouette::VehicleJourney, :type => :model do
expect(collection.last['objectid']).to eq obj.objectid
expect(obj.published_journey_name).to eq 'dummy'
+ expect(obj.custom_fields["energy"]["value"]).to eq 99
end
it 'should expect local times' do
@@ -231,11 +234,13 @@ describe Chouette::VehicleJourney, :type => :model do
it 'should update vj attributes from state' do
state['published_journey_name'] = 'edited_name'
state['published_journey_identifier'] = 'edited_identifier'
+ state['custom_fields'] = {energy: {value: 99}}
Chouette::VehicleJourney.state_update(route, collection)
expect(state['errors']).to be_nil
expect(vehicle_journey.reload.published_journey_name).to eq state['published_journey_name']
expect(vehicle_journey.reload.published_journey_identifier).to eq state['published_journey_identifier']
+ expect(vehicle_journey.reload.custom_field_value("energy")).to eq 99
end
it 'should return errors when validation failed' do
diff --git a/spec/models/custom_field_spec.rb b/spec/models/custom_field_spec.rb
index 80873683c..6ebf994db 100644
--- a/spec/models/custom_field_spec.rb
+++ b/spec/models/custom_field_spec.rb
@@ -17,8 +17,15 @@ RSpec.describe CustomField, type: :model do
context "custom fields for a resource" do
- let!( :fields ){ (1..2).map{ create :custom_field } }
- it { expect(vj.custom_fields).to eq(fields) }
+ let!( :fields ){ [create(:custom_field), create(:custom_field, code: :energy)] }
+ let!( :instance_fields ){
+ {
+ fields[0].code => fields[0].slice(:code, :name, :field_type, :options).update(value: nil),
+ "energy" => fields[1].slice(:code, :name, :field_type, :options).update(value: 99)
+ }
+ }
+ it { expect(Chouette::VehicleJourney.custom_fields).to eq(fields) }
+ it { expect(vj.custom_fields).to eq(instance_fields) }
end
context "custom field_values for a resource" do