1
+ import Icon from '@conveyal/woonerf/components/icon'
2
+ import objectPath from 'object-path'
1
3
import React , { Component , PropTypes } from 'react'
2
4
import { Row , Col , Button , Panel , Glyphicon , Radio , FormGroup , ControlLabel , FormControl } from 'react-bootstrap'
3
5
import update from 'react-addons-update'
4
6
import { shallowEqual } from 'react-pure-render'
5
7
6
8
import { getMessage , getComponentMessages } from '../../common/util/config'
7
9
import 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'
9
12
10
13
export default class DeploymentSettings extends Component {
11
14
static propTypes = {
@@ -14,146 +17,171 @@ export default class DeploymentSettings extends Component {
14
17
}
15
18
16
19
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' ) || [ ]
22
23
}
23
24
24
25
componentWillReceiveProps ( nextProps ) {
25
26
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' ) || [ ]
31
30
} )
32
31
}
33
32
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 )
36
36
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
+ } )
38
41
switch ( item . type ) {
39
- case 'select' :
40
- return this . _onBuildSelectBool ( evt )
42
+ case 'select-bool ' :
43
+ return this . _onSelectBool ( evt , stateUpdate , index )
41
44
case 'number' :
42
- return this . _onChangeBuildNumber ( evt )
45
+ return this . _onChangeNumber ( evt , stateUpdate , index )
43
46
default :
44
- return this . _onBuildChange ( evt )
47
+ return this . _onChange ( evt , stateUpdate , index )
45
48
}
46
49
} 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' )
55
51
}
56
52
}
57
53
58
54
_onAddServer = ( ) => {
59
- const stateUpdate = { deployment : { otpServers : { $push : [ { name : '' , publicUrl : '' , internalUrl : [ ] , admin : false } ] } } }
55
+ const stateUpdate = { otpServers : { $push : [ { name : '' , publicUrl : '' , internalUrl : [ ] , admin : false } ] } }
60
56
this . setState ( update ( this . state , stateUpdate ) )
61
57
}
62
58
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
+ )
65
65
this . setState ( update ( this . state , stateUpdate ) )
66
66
}
67
67
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 ] ] )
70
71
this . setState ( update ( this . state , stateUpdate ) )
71
72
}
72
73
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 } } } }
75
76
this . setState ( update ( this . state , stateUpdate ) )
76
77
}
77
78
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 ] ] } }
80
81
this . setState ( update ( this . state , stateUpdate ) )
81
82
}
82
83
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 )
85
87
this . setState ( update ( this . state , stateUpdate ) )
86
88
}
87
89
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 )
90
93
this . setState ( update ( this . state , stateUpdate ) )
91
94
}
92
95
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' ) )
95
99
this . setState ( update ( this . state , stateUpdate ) )
96
100
}
97
101
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 )
99
132
100
133
_onToggleCustomBounds = ( evt ) => {
101
- const stateUpdate = { deployment : { useCustomOsmBounds : { $set : ( evt . target . value === 'true' ) } } }
134
+ const stateUpdate = { useCustomOsmBounds : { $set : ( evt . target . value === 'true' ) } }
102
135
this . setState ( update ( this . state , stateUpdate ) )
103
136
}
104
137
105
138
_onChangeBounds = ( evt ) => {
106
139
const bBox = evt . target . value . split ( ',' )
107
140
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 ] } }
109
142
this . setState ( update ( this . state , stateUpdate ) )
110
143
}
111
144
}
112
145
113
- shouldComponentUpdate ( nextProps , nextState ) {
114
- return ! shallowEqual ( nextProps , this . props ) || ! shallowEqual ( nextState , this . state )
115
- }
116
-
117
146
render ( ) {
147
+ console . log ( this . state )
148
+ const updaters = objectPath . get ( this . state , 'routerConfig.updaters' ) || [ ]
118
149
const messages = getComponentMessages ( 'ProjectSettings' )
119
150
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 )
123
154
return (
124
155
< div className = 'deployment-settings-panel' >
125
156
{ /* 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 ) }
144
159
</ Panel >
145
160
{ /* 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
+ />
157
185
) ) }
158
186
</ Panel >
159
187
{ /* OTP server settings */ }
@@ -166,11 +194,11 @@ export default class DeploymentSettings extends Component {
166
194
onClick = { this . _onAddServer } >
167
195
< Glyphicon glyph = 'plus' /> { getMessage ( messages , 'deployment.servers.new' ) }
168
196
</ Button >
169
- { getMessage ( messages , 'deployment.servers.title' ) }
197
+ < Icon type = 'server' /> { getMessage ( messages , 'deployment.servers.title' ) }
170
198
</ h4 >
171
199
} >
172
200
< div >
173
- { this . state . deployment . otpServers && this . state . deployment . otpServers . map ( ( server , i ) => (
201
+ { this . state . otpServers && this . state . otpServers . map ( ( server , i ) => (
174
202
< OtpServer
175
203
key = { i }
176
204
index = { i }
@@ -181,23 +209,23 @@ export default class DeploymentSettings extends Component {
181
209
</ div >
182
210
</ Panel >
183
211
{ /* 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 > } >
185
213
< FormGroup
186
214
onChange = { this . _onToggleCustomBounds } >
187
215
< Radio
188
216
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 }
190
218
value = { false } >
191
219
{ getMessage ( messages , 'deployment.osm.gtfs' ) }
192
220
</ Radio >
193
221
< Radio
194
222
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 }
196
224
value >
197
225
{ getMessage ( messages , 'deployment.osm.custom' ) }
198
226
</ Radio >
199
227
</ FormGroup >
200
- { project . useCustomOsmBounds || this . state . deployment . useCustomOsmBounds
228
+ { project . useCustomOsmBounds || this . state . useCustomOsmBounds
201
229
? < FormGroup >
202
230
< ControlLabel > { ( < span > < Glyphicon glyph = 'fullscreen' /> { getMessage ( messages , 'deployment.osm.bounds' ) } </ span > ) } </ ControlLabel >
203
231
< FormControl
0 commit comments