1+ import Icon from '@conveyal/woonerf/components/icon'
2+ import objectPath from 'object-path'
13import React , { Component , PropTypes } from 'react'
24import { Row , Col , Button , Panel , Glyphicon , Radio , FormGroup , ControlLabel , FormControl } from 'react-bootstrap'
35import update from 'react-addons-update'
46import { shallowEqual } from 'react-pure-render'
57
68import { getMessage , getComponentMessages } from '../../common/util/config'
79import OtpServer from './OtpServer'
8- import { BUILD_FIELDS , ROUTER_FIELDS } from '../util/deployment'
10+ import Updater from './Updater'
11+ import { FIELDS , UPDATER_FIELDS } from '../util/deployment'
912
1013export default class DeploymentSettings extends Component {
1114 static propTypes = {
@@ -14,146 +17,171 @@ export default class DeploymentSettings extends Component {
1417 }
1518
1619 state = {
17- deployment : {
18- buildConfig : { } ,
19- routerConfig : { } ,
20- otpServers : this . props . project && this . props . project . otpServers ? this . props . project . otpServers : [ ]
21- }
20+ buildConfig : objectPath . get ( this . props , 'project.buildConfig' ) || { } ,
21+ routerConfig : objectPath . get ( this . props , 'project.routerConfig' ) || { } ,
22+ otpServers : objectPath . get ( this . props , 'project.otpServers' ) || [ ]
2223 }
2324
2425 componentWillReceiveProps ( nextProps ) {
2526 this . setState ( {
26- deployment : {
27- buildConfig : { } ,
28- routerConfig : { } ,
29- otpServers : nextProps . project && nextProps . project . otpServers ? nextProps . project . otpServers : [ ]
30- }
27+ buildConfig : objectPath . get ( nextProps , 'project.buildConfig' ) || { } ,
28+ routerConfig : objectPath . get ( nextProps , 'project.routerConfig' ) || { } ,
29+ otpServers : objectPath . get ( nextProps , 'project.otpServers' ) || [ ]
3130 } )
3231 }
3332
34- _getOnChange = ( evt ) => {
35- let item = BUILD_FIELDS . find ( f => f . name === evt . target . name )
33+ _getOnChange = ( evt , index = null ) => {
34+ let item = FIELDS . find ( f => f . name === evt . target . name )
35+ if ( ! item ) item = UPDATER_FIELDS . find ( f => f . name === evt . target . name )
3636 if ( item ) {
37- // if build field
37+ const stateUpdate = { }
38+ item . effects && item . effects . forEach ( e => {
39+ objectPath . set ( stateUpdate , `${ e . key } .$set` , e . value )
40+ } )
3841 switch ( item . type ) {
39- case 'select' :
40- return this . _onBuildSelectBool ( evt )
42+ case 'select-bool ' :
43+ return this . _onSelectBool ( evt , stateUpdate , index )
4144 case 'number' :
42- return this . _onChangeBuildNumber ( evt )
45+ return this . _onChangeNumber ( evt , stateUpdate , index )
4346 default :
44- return this . _onBuildChange ( evt )
47+ return this . _onChange ( evt , stateUpdate , index )
4548 }
4649 } else {
47- // if router field
48- item = ROUTER_FIELDS . find ( f => f . name === evt . target . name )
49- switch ( item . type ) {
50- case 'number' :
51- return this . _onChangeRouterNumber ( evt )
52- default :
53- return this . _onRouterChange ( evt )
54- }
50+ console . log ( 'no onChange function available' )
5551 }
5652 }
5753
5854 _onAddServer = ( ) => {
59- const stateUpdate = { deployment : { otpServers : { $push : [ { name : '' , publicUrl : '' , internalUrl : [ ] , admin : false } ] } } }
55+ const stateUpdate = { otpServers : { $push : [ { name : '' , publicUrl : '' , internalUrl : [ ] , admin : false } ] } }
6056 this . setState ( update ( this . state , stateUpdate ) )
6157 }
6258
63- _onChangeServer = ( index , props ) => {
64- const stateUpdate = { deployment : { otpServers : { [ index ] : { $merge : { ...props } } } } }
59+ _onAddUpdater = ( ) => {
60+ const stateUpdate = { }
61+ objectPath . set ( stateUpdate ,
62+ `routerConfig.updaters.$${ this . state . routerConfig . updaters ? 'push' : 'set' } ` ,
63+ [ { type : '' , url : '' , frequencySec : '' , sourceType : '' , defaultAgencyId : '' } ]
64+ )
6565 this . setState ( update ( this . state , stateUpdate ) )
6666 }
6767
68- _onRemoveServer = ( index ) => {
69- const stateUpdate = { deployment : { otpServers : { $splice : [ [ index , 1 ] ] } } }
68+ _onRemoveUpdater = ( index ) => {
69+ const stateUpdate = { }
70+ objectPath . set ( stateUpdate , `routerConfig.updaters.$splice` , [ [ index , 1 ] ] )
7071 this . setState ( update ( this . state , stateUpdate ) )
7172 }
7273
73- _onBuildChange = ( evt ) => {
74- const stateUpdate = { deployment : { buildConfig : { [ evt . target . name ] : { $set : evt . target . value } } } }
74+ _onChangeServer = ( index , props ) => {
75+ const stateUpdate = { otpServers : { [ index ] : { $merge : { ... props } } } }
7576 this . setState ( update ( this . state , stateUpdate ) )
7677 }
7778
78- _onChangeBuildNumber = ( evt ) => {
79- const stateUpdate = { deployment : { buildConfig : { [ evt . target . name ] : { $set : + evt . target . value } } } }
79+ _onRemoveServer = ( index ) => {
80+ const stateUpdate = { otpServers : { $splice : [ [ index , 1 ] ] } }
8081 this . setState ( update ( this . state , stateUpdate ) )
8182 }
8283
83- _onChangeRouterNumber = ( evt ) => {
84- const stateUpdate = { deployment : { routerConfig : { [ evt . target . name ] : { $set : + evt . target . value } } } }
84+ _onChange = ( evt , stateUpdate = { } , index = null ) => {
85+ const name = index !== null ? evt . target . name . replace ( '$index' , index ) : evt . target . name
86+ objectPath . set ( stateUpdate , `${ name } .$set` , evt . target . value )
8587 this . setState ( update ( this . state , stateUpdate ) )
8688 }
8789
88- _onRouterChange = ( evt ) => {
89- const stateUpdate = { deployment : { routerConfig : { [ evt . target . name ] : { $set : evt . target . value } } } }
90+ _onChangeNumber = ( evt , stateUpdate = { } , index = null ) => {
91+ const name = index !== null ? evt . target . name . replace ( '$index' , index ) : evt . target . name
92+ objectPath . set ( stateUpdate , `${ name } .$set` , + evt . target . value )
9093 this . setState ( update ( this . state , stateUpdate ) )
9194 }
9295
93- _onBuildSelectBool = ( evt ) => {
94- const stateUpdate = { deployment : { buildConfig : { [ evt . target . name ] : { $set : ( evt . target . value === 'true' ) } } } }
96+ _onSelectBool = ( evt , stateUpdate = { } , index = null ) => {
97+ const name = index !== null ? evt . target . name . replace ( '$index' , index ) : evt . target . name
98+ objectPath . set ( stateUpdate , `${ name } .$set` , ( evt . target . value === 'true' ) )
9599 this . setState ( update ( this . state , stateUpdate ) )
96100 }
97101
98- _onSave = ( evt ) => this . props . updateProjectSettings ( this . props . project , this . state . deployment )
102+ _getFields = ( fields , state , filter , messages ) => {
103+ return fields
104+ . filter ( f => filter ? f . name . startsWith ( filter ) : f )
105+ . map ( ( f , index ) => {
106+ // check for conditional render, e.g. elevationBucket is dependent on fetchElevationUS
107+ if ( f . condition ) {
108+ const val = objectPath . get ( state , `${ f . condition . key } ` )
109+ if ( val !== f . condition . value ) return null
110+ }
111+ return (
112+ < Col key = { index } xs = { f . width || 6 } >
113+ < FormGroup >
114+ < ControlLabel > { getMessage ( messages , `deployment.${ f . name } ` ) } </ ControlLabel >
115+ < FormControl
116+ value = { objectPath . get ( state , `${ f . name } ` ) }
117+ { ...f }
118+ onChange = { this . _getOnChange }
119+ children = { f . children
120+ ? f . children . map ( ( o , i ) => (
121+ < option key = { i } { ...o } />
122+ ) )
123+ : undefined
124+ } />
125+ </ FormGroup >
126+ </ Col >
127+ )
128+ } )
129+ }
130+
131+ _onSave = ( evt ) => this . props . updateProjectSettings ( this . props . project , this . state )
99132
100133 _onToggleCustomBounds = ( evt ) => {
101- const stateUpdate = { deployment : { useCustomOsmBounds : { $set : ( evt . target . value === 'true' ) } } }
134+ const stateUpdate = { useCustomOsmBounds : { $set : ( evt . target . value === 'true' ) } }
102135 this . setState ( update ( this . state , stateUpdate ) )
103136 }
104137
105138 _onChangeBounds = ( evt ) => {
106139 const bBox = evt . target . value . split ( ',' )
107140 if ( bBox . length === 4 ) {
108- const stateUpdate = { deployment : { $merge : { osmWest : bBox [ 0 ] , osmSouth : bBox [ 1 ] , osmEast : bBox [ 2 ] , osmNorth : bBox [ 3 ] } } }
141+ const stateUpdate = { $merge : { osmWest : bBox [ 0 ] , osmSouth : bBox [ 1 ] , osmEast : bBox [ 2 ] , osmNorth : bBox [ 3 ] } }
109142 this . setState ( update ( this . state , stateUpdate ) )
110143 }
111144 }
112145
113- shouldComponentUpdate ( nextProps , nextState ) {
114- return ! shallowEqual ( nextProps , this . props ) || ! shallowEqual ( nextState , this . state )
115- }
116-
117146 render ( ) {
147+ console . log ( this . state )
148+ const updaters = objectPath . get ( this . state , 'routerConfig.updaters' ) || [ ]
118149 const messages = getComponentMessages ( 'ProjectSettings' )
119150 const { project, editDisabled} = this . props
120- const noEdits = Object . keys ( this . state . deployment . buildConfig ) . length === 0 &&
121- Object . keys ( this . state . deployment . routerConfig ) . length === 0 &&
122- shallowEqual ( this . state . deployment . otpServers , project . otpServers )
151+ const noEdits = shallowEqual ( this . state . routerConfig , project . routerConfig ) &&
152+ shallowEqual ( this . state . buildConfig , project . buildConfig ) &&
153+ shallowEqual ( this . state . otpServers , project . otpServers )
123154 return (
124155 < div className = 'deployment-settings-panel' >
125156 { /* Build config settings */ }
126- < Panel header = { < h4 > { getMessage ( messages , 'deployment.buildConfig.title' ) } </ h4 > } >
127- { BUILD_FIELDS . map ( ( f , index ) => (
128- < Col key = { index } xs = { f . width || 6 } >
129- < FormGroup >
130- < ControlLabel > { getMessage ( messages , `deployment.buildConfig.${ f . name } ` ) } </ ControlLabel >
131- < FormControl
132- defaultValue = { project . routerConfig && project . routerConfig [ f . name ] ? project . routerConfig [ f . name ] : '' }
133- { ...f }
134- onChange = { this . _getOnChange }
135- children = { f . children
136- ? f . children . map ( ( o , i ) => (
137- < option key = { i } { ...o } />
138- ) )
139- : undefined
140- } />
141- </ FormGroup >
142- </ Col >
143- ) ) }
157+ < Panel header = { < h4 > < Icon type = 'cog' /> { getMessage ( messages , 'deployment.buildConfig.title' ) } </ h4 > } >
158+ { this . _getFields ( FIELDS , this . state , 'buildConfig' , messages ) }
144159 </ Panel >
145160 { /* Router config settings */ }
146- < Panel header = { < h4 > Router Config</ h4 > } >
147- { ROUTER_FIELDS . map ( ( f , index ) => (
148- < Col key = { index } xs = { f . width || 6 } >
149- < FormGroup >
150- < ControlLabel > { getMessage ( messages , `deployment.routerConfig.${ f . name } ` ) } </ ControlLabel >
151- < FormControl
152- defaultValue = { project . routerConfig && project . routerConfig [ f . name ] ? project . routerConfig [ f . name ] : '' }
153- { ...f }
154- onChange = { this . _getOnChange } />
155- </ FormGroup >
156- </ Col >
161+ < Panel header = { < h4 > < Icon type = 'cog' /> { getMessage ( messages , 'deployment.routerConfig.title' ) } </ h4 > } >
162+ { this . _getFields ( FIELDS , this . state , 'routerConfig' , messages ) }
163+ </ Panel >
164+ { /* Updaters (technically still a part of router config) */ }
165+ < Panel header = {
166+ < h4 >
167+ < Button
168+ className = 'pull-right'
169+ bsStyle = 'success'
170+ bsSize = 'xsmall'
171+ onClick = { this . _onAddUpdater } >
172+ < Glyphicon glyph = 'plus' /> { getMessage ( messages , 'deployment.routerConfig.updaters.new' ) }
173+ </ Button >
174+ < Icon type = 'bolt' /> { getMessage ( messages , 'deployment.routerConfig.updaters.title' ) }
175+ </ h4 >
176+ } >
177+ { updaters . map ( ( u , i ) => (
178+ < Updater
179+ key = { i }
180+ index = { i }
181+ updater = { u }
182+ onRemove = { this . _onRemoveUpdater }
183+ onChange = { this . _getOnChange }
184+ />
157185 ) ) }
158186 </ Panel >
159187 { /* OTP server settings */ }
@@ -166,11 +194,11 @@ export default class DeploymentSettings extends Component {
166194 onClick = { this . _onAddServer } >
167195 < Glyphicon glyph = 'plus' /> { getMessage ( messages , 'deployment.servers.new' ) }
168196 </ Button >
169- { getMessage ( messages , 'deployment.servers.title' ) }
197+ < Icon type = 'server' /> { getMessage ( messages , 'deployment.servers.title' ) }
170198 </ h4 >
171199 } >
172200 < div >
173- { this . state . deployment . otpServers && this . state . deployment . otpServers . map ( ( server , i ) => (
201+ { this . state . otpServers && this . state . otpServers . map ( ( server , i ) => (
174202 < OtpServer
175203 key = { i }
176204 index = { i }
@@ -181,23 +209,23 @@ export default class DeploymentSettings extends Component {
181209 </ div >
182210 </ Panel >
183211 { /* OSM extract settings */ }
184- < Panel header = { < h4 > { getMessage ( messages , 'deployment.osm.title' ) } </ h4 > } >
212+ < Panel header = { < h4 > < Icon type = 'globe' /> { getMessage ( messages , 'deployment.osm.title' ) } </ h4 > } >
185213 < FormGroup
186214 onChange = { this . _onToggleCustomBounds } >
187215 < Radio
188216 name = 'osm-extract'
189- checked = { typeof this . state . deployment . useCustomOsmBounds !== 'undefined' ? ! this . state . deployment . useCustomOsmBounds : ! project . useCustomOsmBounds }
217+ checked = { typeof this . state . useCustomOsmBounds !== 'undefined' ? ! this . state . useCustomOsmBounds : ! project . useCustomOsmBounds }
190218 value = { false } >
191219 { getMessage ( messages , 'deployment.osm.gtfs' ) }
192220 </ Radio >
193221 < Radio
194222 name = 'osm-extract'
195- checked = { typeof this . state . deployment . useCustomOsmBounds !== 'undefined' ? this . state . deployment . useCustomOsmBounds : project . useCustomOsmBounds }
223+ checked = { typeof this . state . useCustomOsmBounds !== 'undefined' ? this . state . useCustomOsmBounds : project . useCustomOsmBounds }
196224 value >
197225 { getMessage ( messages , 'deployment.osm.custom' ) }
198226 </ Radio >
199227 </ FormGroup >
200- { project . useCustomOsmBounds || this . state . deployment . useCustomOsmBounds
228+ { project . useCustomOsmBounds || this . state . useCustomOsmBounds
201229 ? < FormGroup >
202230 < ControlLabel > { ( < span > < Glyphicon glyph = 'fullscreen' /> { getMessage ( messages , 'deployment.osm.bounds' ) } </ span > ) } </ ControlLabel >
203231 < FormControl
0 commit comments