Skip to content

Commit 2e50fef

Browse files
committed
feat(deployment-settings): refactor + add elevationBucket and updaters
1 parent 406e115 commit 2e50fef

File tree

6 files changed

+301
-140
lines changed

6 files changed

+301
-140
lines changed

i18n/english.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ ProjectSettings:
207207
deleteProject: Delete Project?
208208
general:
209209
title: General
210+
name: Project name
210211
location:
211212
title: Location
212213
defaultLocation: Default location (lat, lng)
@@ -221,6 +222,10 @@ ProjectSettings:
221222
buildConfig:
222223
title: Build Config
223224
fetchElevationUS: Fetch Elevation
225+
elevationBucket:
226+
bucketName: S3 Bucket Name
227+
accessKey: Access Key
228+
secretKey: Secret Key
224229
stationTransfers: Sta. Transfers
225230
subwayAccessTime: Subway Access Time
226231
fares: Fares
@@ -232,6 +237,15 @@ ProjectSettings:
232237
carDropoffTime: Car Dropoff Time
233238
brandingUrlRoot: Branding URL Root
234239
requestLogFile: Request log file
240+
updaters:
241+
title: Real-time updaters
242+
new: Add updater
243+
$index:
244+
type: Type
245+
frequencySec: Frequency (in seconds)
246+
sourceType: Source type
247+
url: URL
248+
defaultAgencyId: Default agency ID
235249
servers:
236250
title: Servers
237251
new: Add server

i18n/espanol.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ ProjectSettings:
211211
buildConfig:
212212
title: Build Config
213213
fetchElevationUS: Fetch Elevation
214+
elevationBucket:
215+
bucketName: S3 Bucket Name
216+
accessKey: Access Key
217+
secretKey: Secret Key
214218
stationTransfers: Sta. Transfers
215219
subwayAccessTime: Subway Access Time
216220
fares: Fares
@@ -222,6 +226,15 @@ ProjectSettings:
222226
carDropoffTime: Car Dropoff Time
223227
brandingUrlRoot: Branding URL Root
224228
requestLogFile: Request log file
229+
updaters:
230+
title: Real-time updaters
231+
new: Add updater
232+
$index:
233+
type: Type
234+
frequencySec: Frequency (in seconds)
235+
sourceType: Source type
236+
url: URL
237+
defaultAgencyId: Default agency ID
225238
servers:
226239
title: Servers
227240
new: Add server

i18n/francais.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ ProjectSettings:
211211
buildConfig:
212212
title: Build Config
213213
fetchElevationUS: Fetch Elevation
214+
elevationBucket:
215+
bucketName: S3 Bucket Name
216+
accessKey: Access Key
217+
secretKey: Secret Key
214218
stationTransfers: Sta. Transfers
215219
subwayAccessTime: Subway Access Time
216220
fares: Fares
@@ -222,6 +226,15 @@ ProjectSettings:
222226
carDropoffTime: Car Dropoff Time
223227
brandingUrlRoot: Branding URL Root
224228
requestLogFile: Request log file
229+
updaters:
230+
title: Real-time updaters
231+
new: Add updater
232+
$index:
233+
type: Type
234+
frequencySec: Frequency (in seconds)
235+
sourceType: Source type
236+
url: URL
237+
defaultAgencyId: Default agency ID
225238
servers:
226239
title: Servers
227240
new: Add server

lib/manager/components/DeploymentSettings.js

Lines changed: 114 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
import Icon from '@conveyal/woonerf/components/icon'
2+
import objectPath from 'object-path'
13
import React, {Component, PropTypes} from 'react'
24
import {Row, Col, Button, Panel, Glyphicon, Radio, FormGroup, ControlLabel, FormControl} from 'react-bootstrap'
35
import update from 'react-addons-update'
46
import {shallowEqual} from 'react-pure-render'
57

68
import {getMessage, getComponentMessages} from '../../common/util/config'
79
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'
912

1013
export 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

Comments
 (0)