Skip to content

Commit

Permalink
feat(deployment-settings): refactor + add elevationBucket and updaters
Browse files Browse the repository at this point in the history
  • Loading branch information
landonreed committed Jul 18, 2017
1 parent 406e115 commit 2e50fef
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 140 deletions.
14 changes: 14 additions & 0 deletions i18n/english.yml
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ ProjectSettings:
deleteProject: Delete Project?
general:
title: General
name: Project name
location:
title: Location
defaultLocation: Default location (lat, lng)
Expand All @@ -221,6 +222,10 @@ ProjectSettings:
buildConfig:
title: Build Config
fetchElevationUS: Fetch Elevation
elevationBucket:
bucketName: S3 Bucket Name
accessKey: Access Key
secretKey: Secret Key
stationTransfers: Sta. Transfers
subwayAccessTime: Subway Access Time
fares: Fares
Expand All @@ -232,6 +237,15 @@ ProjectSettings:
carDropoffTime: Car Dropoff Time
brandingUrlRoot: Branding URL Root
requestLogFile: Request log file
updaters:
title: Real-time updaters
new: Add updater
$index:
type: Type
frequencySec: Frequency (in seconds)
sourceType: Source type
url: URL
defaultAgencyId: Default agency ID
servers:
title: Servers
new: Add server
Expand Down
13 changes: 13 additions & 0 deletions i18n/espanol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ ProjectSettings:
buildConfig:
title: Build Config
fetchElevationUS: Fetch Elevation
elevationBucket:
bucketName: S3 Bucket Name
accessKey: Access Key
secretKey: Secret Key
stationTransfers: Sta. Transfers
subwayAccessTime: Subway Access Time
fares: Fares
Expand All @@ -222,6 +226,15 @@ ProjectSettings:
carDropoffTime: Car Dropoff Time
brandingUrlRoot: Branding URL Root
requestLogFile: Request log file
updaters:
title: Real-time updaters
new: Add updater
$index:
type: Type
frequencySec: Frequency (in seconds)
sourceType: Source type
url: URL
defaultAgencyId: Default agency ID
servers:
title: Servers
new: Add server
Expand Down
13 changes: 13 additions & 0 deletions i18n/francais.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ ProjectSettings:
buildConfig:
title: Build Config
fetchElevationUS: Fetch Elevation
elevationBucket:
bucketName: S3 Bucket Name
accessKey: Access Key
secretKey: Secret Key
stationTransfers: Sta. Transfers
subwayAccessTime: Subway Access Time
fares: Fares
Expand All @@ -222,6 +226,15 @@ ProjectSettings:
carDropoffTime: Car Dropoff Time
brandingUrlRoot: Branding URL Root
requestLogFile: Request log file
updaters:
title: Real-time updaters
new: Add updater
$index:
type: Type
frequencySec: Frequency (in seconds)
sourceType: Source type
url: URL
defaultAgencyId: Default agency ID
servers:
title: Servers
new: Add server
Expand Down
200 changes: 114 additions & 86 deletions lib/manager/components/DeploymentSettings.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import Icon from '@conveyal/woonerf/components/icon'
import objectPath from 'object-path'
import React, {Component, PropTypes} from 'react'
import {Row, Col, Button, Panel, Glyphicon, Radio, FormGroup, ControlLabel, FormControl} from 'react-bootstrap'
import update from 'react-addons-update'
import {shallowEqual} from 'react-pure-render'

import {getMessage, getComponentMessages} from '../../common/util/config'
import OtpServer from './OtpServer'
import {BUILD_FIELDS, ROUTER_FIELDS} from '../util/deployment'
import Updater from './Updater'
import {FIELDS, UPDATER_FIELDS} from '../util/deployment'

export default class DeploymentSettings extends Component {
static propTypes = {
Expand All @@ -14,146 +17,171 @@ export default class DeploymentSettings extends Component {
}

state = {
deployment: {
buildConfig: {},
routerConfig: {},
otpServers: this.props.project && this.props.project.otpServers ? this.props.project.otpServers : []
}
buildConfig: objectPath.get(this.props, 'project.buildConfig') || {},
routerConfig: objectPath.get(this.props, 'project.routerConfig') || {},
otpServers: objectPath.get(this.props, 'project.otpServers') || []
}

componentWillReceiveProps (nextProps) {
this.setState({
deployment: {
buildConfig: {},
routerConfig: {},
otpServers: nextProps.project && nextProps.project.otpServers ? nextProps.project.otpServers : []
}
buildConfig: objectPath.get(nextProps, 'project.buildConfig') || {},
routerConfig: objectPath.get(nextProps, 'project.routerConfig') || {},
otpServers: objectPath.get(nextProps, 'project.otpServers') || []
})
}

_getOnChange = (evt) => {
let item = BUILD_FIELDS.find(f => f.name === evt.target.name)
_getOnChange = (evt, index = null) => {
let item = FIELDS.find(f => f.name === evt.target.name)
if (!item) item = UPDATER_FIELDS.find(f => f.name === evt.target.name)
if (item) {
// if build field
const stateUpdate = {}
item.effects && item.effects.forEach(e => {
objectPath.set(stateUpdate, `${e.key}.$set`, e.value)
})
switch (item.type) {
case 'select':
return this._onBuildSelectBool(evt)
case 'select-bool':
return this._onSelectBool(evt, stateUpdate, index)
case 'number':
return this._onChangeBuildNumber(evt)
return this._onChangeNumber(evt, stateUpdate, index)
default:
return this._onBuildChange(evt)
return this._onChange(evt, stateUpdate, index)
}
} else {
// if router field
item = ROUTER_FIELDS.find(f => f.name === evt.target.name)
switch (item.type) {
case 'number':
return this._onChangeRouterNumber(evt)
default:
return this._onRouterChange(evt)
}
console.log('no onChange function available')
}
}

_onAddServer = () => {
const stateUpdate = { deployment: { otpServers: { $push: [{name: '', publicUrl: '', internalUrl: [], admin: false}] } } }
const stateUpdate = { otpServers: { $push: [{name: '', publicUrl: '', internalUrl: [], admin: false}] } }
this.setState(update(this.state, stateUpdate))
}

_onChangeServer = (index, props) => {
const stateUpdate = { deployment: { otpServers: { [index]: { $merge: { ...props } } } } }
_onAddUpdater = () => {
const stateUpdate = {}
objectPath.set(stateUpdate,
`routerConfig.updaters.$${this.state.routerConfig.updaters ? 'push' : 'set'}`,
[{type: '', url: '', frequencySec: '', sourceType: '', defaultAgencyId: ''}]
)
this.setState(update(this.state, stateUpdate))
}

_onRemoveServer = (index) => {
const stateUpdate = { deployment: { otpServers: { $splice: [[index, 1]] } } }
_onRemoveUpdater = (index) => {
const stateUpdate = {}
objectPath.set(stateUpdate, `routerConfig.updaters.$splice`, [[index, 1]])
this.setState(update(this.state, stateUpdate))
}

_onBuildChange = (evt) => {
const stateUpdate = { deployment: { buildConfig: { [evt.target.name]: { $set: evt.target.value } } } }
_onChangeServer = (index, props) => {
const stateUpdate = { otpServers: { [index]: { $merge: { ...props } } } }
this.setState(update(this.state, stateUpdate))
}

_onChangeBuildNumber = (evt) => {
const stateUpdate = { deployment: { buildConfig: { [evt.target.name]: { $set: +evt.target.value } } } }
_onRemoveServer = (index) => {
const stateUpdate = { otpServers: { $splice: [[index, 1]] } }
this.setState(update(this.state, stateUpdate))
}

_onChangeRouterNumber = (evt) => {
const stateUpdate = { deployment: { routerConfig: { [evt.target.name]: { $set: +evt.target.value } } } }
_onChange = (evt, stateUpdate = {}, index = null) => {
const name = index !== null ? evt.target.name.replace('$index', index) : evt.target.name
objectPath.set(stateUpdate, `${name}.$set`, evt.target.value)
this.setState(update(this.state, stateUpdate))
}

_onRouterChange = (evt) => {
const stateUpdate = { deployment: { routerConfig: { [evt.target.name]: { $set: evt.target.value } } } }
_onChangeNumber = (evt, stateUpdate = {}, index = null) => {
const name = index !== null ? evt.target.name.replace('$index', index) : evt.target.name
objectPath.set(stateUpdate, `${name}.$set`, +evt.target.value)
this.setState(update(this.state, stateUpdate))
}

_onBuildSelectBool = (evt) => {
const stateUpdate = { deployment: { buildConfig: { [evt.target.name]: { $set: (evt.target.value === 'true') } } } }
_onSelectBool = (evt, stateUpdate = {}, index = null) => {
const name = index !== null ? evt.target.name.replace('$index', index) : evt.target.name
objectPath.set(stateUpdate, `${name}.$set`, (evt.target.value === 'true'))
this.setState(update(this.state, stateUpdate))
}

_onSave = (evt) => this.props.updateProjectSettings(this.props.project, this.state.deployment)
_getFields = (fields, state, filter, messages) => {
return fields
.filter(f => filter ? f.name.startsWith(filter) : f)
.map((f, index) => {
// check for conditional render, e.g. elevationBucket is dependent on fetchElevationUS
if (f.condition) {
const val = objectPath.get(state, `${f.condition.key}`)
if (val !== f.condition.value) return null
}
return (
<Col key={index} xs={f.width || 6}>
<FormGroup>
<ControlLabel>{getMessage(messages, `deployment.${f.name}`)}</ControlLabel>
<FormControl
value={objectPath.get(state, `${f.name}`)}
{...f}
onChange={this._getOnChange}
children={f.children
? f.children.map((o, i) => (
<option key={i} {...o} />
))
: undefined
} />
</FormGroup>
</Col>
)
})
}

_onSave = (evt) => this.props.updateProjectSettings(this.props.project, this.state)

_onToggleCustomBounds = (evt) => {
const stateUpdate = { deployment: { useCustomOsmBounds: { $set: (evt.target.value === 'true') } } }
const stateUpdate = { useCustomOsmBounds: { $set: (evt.target.value === 'true') } }
this.setState(update(this.state, stateUpdate))
}

_onChangeBounds = (evt) => {
const bBox = evt.target.value.split(',')
if (bBox.length === 4) {
const stateUpdate = { deployment: { $merge: { osmWest: bBox[0], osmSouth: bBox[1], osmEast: bBox[2], osmNorth: bBox[3] } } }
const stateUpdate = { $merge: { osmWest: bBox[0], osmSouth: bBox[1], osmEast: bBox[2], osmNorth: bBox[3] } }
this.setState(update(this.state, stateUpdate))
}
}

shouldComponentUpdate (nextProps, nextState) {
return !shallowEqual(nextProps, this.props) || !shallowEqual(nextState, this.state)
}

render () {
console.log(this.state)
const updaters = objectPath.get(this.state, 'routerConfig.updaters') || []
const messages = getComponentMessages('ProjectSettings')
const {project, editDisabled} = this.props
const noEdits = Object.keys(this.state.deployment.buildConfig).length === 0 &&
Object.keys(this.state.deployment.routerConfig).length === 0 &&
shallowEqual(this.state.deployment.otpServers, project.otpServers)
const noEdits = shallowEqual(this.state.routerConfig, project.routerConfig) &&
shallowEqual(this.state.buildConfig, project.buildConfig) &&
shallowEqual(this.state.otpServers, project.otpServers)
return (
<div className='deployment-settings-panel'>
{/* Build config settings */}
<Panel header={<h4>{getMessage(messages, 'deployment.buildConfig.title')}</h4>}>
{BUILD_FIELDS.map((f, index) => (
<Col key={index} xs={f.width || 6}>
<FormGroup>
<ControlLabel>{getMessage(messages, `deployment.buildConfig.${f.name}`)}</ControlLabel>
<FormControl
defaultValue={project.routerConfig && project.routerConfig[f.name] ? project.routerConfig[f.name] : ''}
{...f}
onChange={this._getOnChange}
children={f.children
? f.children.map((o, i) => (
<option key={i} {...o} />
))
: undefined
} />
</FormGroup>
</Col>
))}
<Panel header={<h4><Icon type='cog' /> {getMessage(messages, 'deployment.buildConfig.title')}</h4>}>
{this._getFields(FIELDS, this.state, 'buildConfig', messages)}
</Panel>
{/* Router config settings */}
<Panel header={<h4>Router Config</h4>}>
{ROUTER_FIELDS.map((f, index) => (
<Col key={index} xs={f.width || 6}>
<FormGroup>
<ControlLabel>{getMessage(messages, `deployment.routerConfig.${f.name}`)}</ControlLabel>
<FormControl
defaultValue={project.routerConfig && project.routerConfig[f.name] ? project.routerConfig[f.name] : ''}
{...f}
onChange={this._getOnChange} />
</FormGroup>
</Col>
<Panel header={<h4><Icon type='cog' /> {getMessage(messages, 'deployment.routerConfig.title')}</h4>}>
{this._getFields(FIELDS, this.state, 'routerConfig', messages)}
</Panel>
{/* Updaters (technically still a part of router config) */}
<Panel header={
<h4>
<Button
className='pull-right'
bsStyle='success'
bsSize='xsmall'
onClick={this._onAddUpdater}>
<Glyphicon glyph='plus' /> {getMessage(messages, 'deployment.routerConfig.updaters.new')}
</Button>
<Icon type='bolt' /> {getMessage(messages, 'deployment.routerConfig.updaters.title')}
</h4>
}>
{updaters.map((u, i) => (
<Updater
key={i}
index={i}
updater={u}
onRemove={this._onRemoveUpdater}
onChange={this._getOnChange}
/>
))}
</Panel>
{/* OTP server settings */}
Expand All @@ -166,11 +194,11 @@ export default class DeploymentSettings extends Component {
onClick={this._onAddServer}>
<Glyphicon glyph='plus' /> {getMessage(messages, 'deployment.servers.new')}
</Button>
{getMessage(messages, 'deployment.servers.title')}
<Icon type='server' /> {getMessage(messages, 'deployment.servers.title')}
</h4>
}>
<div>
{this.state.deployment.otpServers && this.state.deployment.otpServers.map((server, i) => (
{this.state.otpServers && this.state.otpServers.map((server, i) => (
<OtpServer
key={i}
index={i}
Expand All @@ -181,23 +209,23 @@ export default class DeploymentSettings extends Component {
</div>
</Panel>
{/* OSM extract settings */}
<Panel header={<h4>{getMessage(messages, 'deployment.osm.title')}</h4>}>
<Panel header={<h4><Icon type='globe' /> {getMessage(messages, 'deployment.osm.title')}</h4>}>
<FormGroup
onChange={this._onToggleCustomBounds}>
<Radio
name='osm-extract'
checked={typeof this.state.deployment.useCustomOsmBounds !== 'undefined' ? !this.state.deployment.useCustomOsmBounds : !project.useCustomOsmBounds}
checked={typeof this.state.useCustomOsmBounds !== 'undefined' ? !this.state.useCustomOsmBounds : !project.useCustomOsmBounds}
value={false}>
{getMessage(messages, 'deployment.osm.gtfs')}
</Radio>
<Radio
name='osm-extract'
checked={typeof this.state.deployment.useCustomOsmBounds !== 'undefined' ? this.state.deployment.useCustomOsmBounds : project.useCustomOsmBounds}
checked={typeof this.state.useCustomOsmBounds !== 'undefined' ? this.state.useCustomOsmBounds : project.useCustomOsmBounds}
value>
{getMessage(messages, 'deployment.osm.custom')}
</Radio>
</FormGroup>
{project.useCustomOsmBounds || this.state.deployment.useCustomOsmBounds
{project.useCustomOsmBounds || this.state.useCustomOsmBounds
? <FormGroup>
<ControlLabel>{(<span><Glyphicon glyph='fullscreen' /> {getMessage(messages, 'deployment.osm.bounds')}</span>)}</ControlLabel>
<FormControl
Expand Down
Loading

0 comments on commit 2e50fef

Please sign in to comment.