Skip to content

Commit a106298

Browse files
authored
Merge pull request #536 from ibi-group/deploy-improvements
Deploy improvements
2 parents f24497a + 3d16208 commit a106298

File tree

11 files changed

+188
-67
lines changed

11 files changed

+188
-67
lines changed

.flowconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
.*/node_modules/config-chain/.*
33
.*/node_modules/fbjs/flow/.*
44
.*/node_modules/immutable/.*
5+
.*/node_modules/jju/examples.*
56
.*/node_modules/mapbox.js/docs/examples/.*
67
.*/node_modules/nock/node_modules/changelog/examples/.*
78
.*/node_modules/npmconf/.*

i18n/english.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,16 @@ components:
282282
delete: Remove
283283
ec2Info:
284284
amiId: AMI ID
285+
buildAmiId: Graph build AMI ID
286+
buildImageDescription: New Image Description
287+
buildImageName: New Image Name
288+
buildInstanceType: Graph build instance type
285289
instanceCount: Instance count
286290
instanceType: Instance type
287291
iamInstanceProfileArn: IAM Instance Profile ARN
288292
keyName: Key file name
293+
recreateBuildImage: Recreate Build Image after Graph Build?
294+
region: Region name
289295
securityGroupId: Security Group ID
290296
subnetId: Subnet ID
291297
targetGroupArn: Target Group ARN (load balancer)

lib/admin/components/ServerSettings.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,16 @@ class ServerSettings extends Component<Props, State> {
218218
{otpServers && otpServers.length
219219
? otpServers.map((server, index) => (
220220
<CollapsiblePanel
221-
key={`server-${index}`}
222-
index={index}
223-
fields={SERVER_FIELDS}
221+
data={server}
224222
defaultExpanded={!server.name}
223+
fields={SERVER_FIELDS}
224+
index={index}
225+
key={`server-${index}`}
226+
onChange={this._getOnChange}
227+
onRemove={this._onDeleteServer}
228+
onSave={this._onSaveServer}
229+
saveDisabled={!this.state.hasEdits}
230+
showButtonsOnBottom
225231
testId={server.name ||
226232
`[${this.messages('deployment.otpServers.serverPlaceholder')}]`}
227233
title={server.name
@@ -231,11 +237,7 @@ class ServerSettings extends Component<Props, State> {
231237
</span>
232238
: `[${this.messages('deployment.otpServers.serverPlaceholder')}]`
233239
}
234-
data={server}
235-
saveDisabled={!this.state.hasEdits}
236-
onRemove={this._onDeleteServer}
237-
onSave={this._onSaveServer}
238-
onChange={this._getOnChange}>
240+
>
239241
<ServerSpecialFields
240242
index={index}
241243
getOnChange={this._getOnChange}

lib/common/components/FormInput.js

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
import React from 'react'
44
import {
5+
Checkbox,
56
Col,
6-
FormGroup,
77
ControlLabel,
8-
FormControl
8+
FormControl,
9+
FormGroup
910
} from 'react-bootstrap'
1011

1112
import {getComponentMessages} from '../../common/util/config'
@@ -26,44 +27,69 @@ export default class FormInput extends React.Component<Props> {
2627

2728
messages = getComponentMessages('FormInput')
2829

29-
render () {
30-
const {field, messageRoot, shouldRender, value} = this.props
31-
const prefix = messageRoot ? `${messageRoot}.` : ''
30+
getPrefix = () => {
31+
const {messageRoot} = this.props
32+
return messageRoot ? `${messageRoot}.` : ''
33+
}
34+
35+
renderCheckbox = () => {
36+
const { field, onChange, value } = this.props
37+
return (
38+
<FormGroup>
39+
<Checkbox checked={value} name={field.name} onChange={onChange}>
40+
{this.messages(`${this.getPrefix()}${field.name}`)}
41+
{field.required ? ' *' : ''}
42+
</Checkbox>
43+
</FormGroup>
44+
)
45+
}
46+
47+
renderLabelAndFormControl = () => {
48+
const {field, onChange, value} = this.props
3249
const {effects, split, ...fieldProps} = field
50+
const prefix = this.getPrefix()
51+
const isSelect = field.type.indexOf('select') !== -1
52+
return (
53+
<FormGroup>
54+
<ControlLabel>
55+
{this.messages(`${prefix}${field.name}`)}
56+
{field.required ? ' *' : ''}
57+
</ControlLabel>
58+
<FormControl
59+
value={value === null ? '' : value}
60+
{...fieldProps}
61+
placeholder={isSelect
62+
? undefined
63+
: field.placeholder || this.messages(`${prefix}${field.name}Placeholder`)
64+
}
65+
name={field.name}
66+
children={field.children
67+
? field.children.sort((a, b) => {
68+
if (a.value < b.value) return -1
69+
if (a.value > b.value) return 1
70+
return 0
71+
}).map((o, i) => (
72+
<option key={i} {...o} />
73+
))
74+
: undefined
75+
}
76+
onChange={onChange} />
77+
</FormGroup>
78+
)
79+
}
80+
81+
render () {
82+
const {field, shouldRender} = this.props
3383
// If should render is false, do not render form element (for conditional
3484
// visibility of form elements).
3585
if (!shouldRender()) return null
3686
const isCheckbox = field.type === 'checkbox'
37-
const isSelect = field.type.indexOf('select') !== -1
38-
const checkboxProps = isCheckbox ? {checked: value} : {}
3987
return (
4088
<Col xs={field.width || 6}>
41-
<FormGroup>
42-
<ControlLabel>
43-
{this.messages(`${prefix}${field.name}`)}
44-
{field.required ? ' *' : ''}
45-
</ControlLabel>
46-
<FormControl
47-
value={value === null ? '' : value}
48-
{...checkboxProps} // adds checkbox props if type is checkbox
49-
{...fieldProps}
50-
placeholder={isCheckbox || isSelect
51-
? undefined
52-
: field.placeholder || this.messages(`${prefix}${field.name}Placeholder`)
53-
}
54-
name={field.name}
55-
children={field.children
56-
? field.children.sort((a, b) => {
57-
if (a.value < b.value) return -1
58-
if (a.value > b.value) return 1
59-
return 0
60-
}).map((o, i) => (
61-
<option key={i} {...o} />
62-
))
63-
: undefined
64-
}
65-
onChange={this.props.onChange} />
66-
</FormGroup>
89+
{isCheckbox
90+
? this.renderCheckbox()
91+
: this.renderLabelAndFormControl()
92+
}
6793
</Col>
6894
)
6995
}

lib/common/util/json.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// @flow
22

3+
import { analyze } from 'jju'
4+
35
/**
46
* Check if a string is valid JSON.
57
*/
@@ -11,3 +13,28 @@ export function isValidJSON (str: string): boolean {
1113
}
1214
return true
1315
}
16+
17+
/**
18+
* Check if a string is valid JSONC that OTP should be able to
19+
* parse. OTP allows comments and unquoted keys, but not other
20+
* fancy stuff. See OTP json parser here:
21+
* https://github.com/opentripplanner/OpenTripPlanner/blob/27f4ed0a86157bdd4c4bc3004fec25687768d373/src/main/java/org/opentripplanner/standalone/OTPMain.java#L190-L194
22+
*/
23+
export function isValidJSONC (str: string): boolean {
24+
try {
25+
const result = analyze(str)
26+
if (
27+
// if JSON has quotes with single quotes, it is invalid
28+
result.quote_types.indexOf("'") > -1 ||
29+
// if JSON has a multi-line quote, it is invalid
30+
result.has_multi_line_quote ||
31+
// if JSON has trailing commas, it is invalid
32+
result.has_trailing_comma
33+
) {
34+
return false
35+
}
36+
return true
37+
} catch (e) {
38+
return false
39+
}
40+
}

lib/manager/components/CollapsiblePanel.js

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type Props = {
2323
onRemove?: number => void,
2424
onSave?: number => any,
2525
saveDisabled: boolean,
26+
showButtonsOnBottom?: boolean,
2627
testId: string,
2728
title: Element<*> | string
2829
}
@@ -39,8 +40,40 @@ export default class CollapsiblePanel extends Component<Props> {
3940

4041
_onSave = () => this.props.onSave && this.props.onSave(this.props.index)
4142

43+
renderButtonToolbar = () => {
44+
const {onSave, saveDisabled} = this.props
45+
return (
46+
<ButtonToolbar className='pull-right'>
47+
{/* Only render save button is onSave prop is defined */}
48+
{typeof onSave === 'function' &&
49+
<Button
50+
bsSize='small'
51+
bsStyle='primary'
52+
data-test-id='save-item-button'
53+
disabled={saveDisabled}
54+
onClick={this._onSave}>
55+
<Icon type='floppy-o' /> Save
56+
</Button>
57+
}
58+
<Button
59+
bsSize='small'
60+
bsStyle='danger'
61+
onClick={this._onRemove}>
62+
<Icon type='trash-o' /> Delete
63+
</Button>
64+
</ButtonToolbar>
65+
)
66+
}
67+
4268
render () {
43-
const {data, defaultExpanded, fields, saveDisabled, testId, title} = this.props
69+
const {
70+
data,
71+
defaultExpanded,
72+
fields,
73+
showButtonsOnBottom,
74+
testId,
75+
title
76+
} = this.props
4477
return (
4578
<Panel
4679
collapsible
@@ -49,25 +82,7 @@ export default class CollapsiblePanel extends Component<Props> {
4982
header={<h5 style={{width: '100%', cursor: 'pointer'}}>{title}</h5>}
5083
>
5184
<Form>
52-
<ButtonToolbar className='pull-right'>
53-
{/* Only render save button is onSave prop is defined */}
54-
{typeof this.props.onSave === 'function' &&
55-
<Button
56-
bsSize='small'
57-
bsStyle='primary'
58-
data-test-id='save-item-button'
59-
disabled={saveDisabled}
60-
onClick={this._onSave}>
61-
<Icon type='floppy-o' /> Save
62-
</Button>
63-
}
64-
<Button
65-
bsSize='small'
66-
bsStyle='danger'
67-
onClick={this._onRemove}>
68-
<Icon type='trash-o' /> Delete
69-
</Button>
70-
</ButtonToolbar>
85+
{this.renderButtonToolbar()}
7186
{fields.map((f, i) =>
7287
<FormInput
7388
key={i}
@@ -77,6 +92,11 @@ export default class CollapsiblePanel extends Component<Props> {
7792
)}
7893
{/* Additional (usually more complex) fields can go here. */}
7994
{this.props.children}
95+
{showButtonsOnBottom && (
96+
<div style={{clear: 'both'}}>
97+
{this.renderButtonToolbar()}
98+
</div>
99+
)}
80100
</Form>
81101
</Panel>
82102
)

lib/manager/components/CurrentDeploymentPanel.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ export default class CurrentDeploymentPanel extends Component<Props> {
7070
this.props.downloadBuildArtifact(this.props.deployment)
7171
}
7272

73+
_onClickDownloadReport = () => {
74+
this.props.downloadBuildArtifact(this.props.deployment, 'graph-build-report.zip')
75+
}
76+
7377
_onClickDownloadGraph = () => {
7478
this.props.downloadBuildArtifact(this.props.deployment, 'Graph.obj')
7579
}
@@ -118,6 +122,7 @@ export default class CurrentDeploymentPanel extends Component<Props> {
118122
<ButtonToolbar>
119123
<Button bsSize='xsmall' onClick={this._onClickDownloadGraph}><Icon type='ellipsis-h' /> Graph.obj</Button>
120124
<Button bsSize='xsmall' onClick={this._onClickDownloadLogs}><Icon type='file-text-o' /> Build log</Button>
125+
<Button bsSize='xsmall' onClick={this._onClickDownloadReport}><Icon type='file-zip-o' /> Graph build report</Button>
121126
<Button bsSize='xsmall' onClick={this._onClickDownloadBundle}><Icon type='file-zip-o' /> Bundle</Button>
122127
</ButtonToolbar>
123128
<div style={{ margin: '20px 0' }}>

lib/manager/components/DeploymentViewer.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import EditableTextField from '../../common/components/EditableTextField'
3232
import WatchButton from '../../common/containers/WatchButton'
3333
import {getComponentMessages, getConfigProperty} from '../../common/util/config'
3434
import {formatTimestamp, fromNow} from '../../common/util/date-time'
35-
import {isValidJSON} from '../../common/util/json'
35+
import {isValidJSONC} from '../../common/util/json'
3636
import {defaultTileURL} from '../../common/util/maps'
3737
import { versionsSorter } from '../../common/util/util'
3838
import {getServerDeployedTo} from '../util/deployment'
@@ -479,7 +479,7 @@ class CustomConfig extends Component<{
479479
_onSaveConfig = () => {
480480
const {deployment, name, updateDeployment} = this.props
481481
const value = this.state[name]
482-
if (!isValidJSON(value)) return window.alert('Must provide valid JSON string.')
482+
if (!isValidJSONC(value)) return window.alert('Must provide valid JSON string.')
483483
else {
484484
updateDeployment(deployment, {[name]: value})
485485
this.setState({[name]: undefined})
@@ -490,7 +490,7 @@ class CustomConfig extends Component<{
490490
const {deployment, name, label} = this.props
491491
const useCustom = deployment[name] !== null
492492
const value = this.state[name] || deployment[name]
493-
const validJSON = isValidJSON(value)
493+
const validJSON = isValidJSONC(value)
494494
return (
495495
<div>
496496
<h5>{label} configuration</h5>

0 commit comments

Comments
 (0)