diff options
author | Tristan Cacqueray <tdecacqu@redhat.com> | 2018-08-28 08:51:39 +0000 |
---|---|---|
committer | Tristan Cacqueray <tdecacqu@redhat.com> | 2018-10-11 02:58:06 +0000 |
commit | 6cb6b736150f0f65a29733e3055fa098953f901c (patch) | |
tree | cb4025fe778e90f190cc2c20f59895df16c5fcf0 | |
parent | 99c38c93751bd2c0f1f6237268df117f28af5ac2 (diff) | |
download | zuul-6cb6b736150f0f65a29733e3055fa098953f901c.tar.gz |
web: add job page
This change adds a /job/{job_name} web interface.
Change-Id: Idbeae3a11ec4180a193923def7dc7f9c53dc9043
-rw-r--r-- | releasenotes/notes/web-page-job-77fa7ffb2a1c09de.yaml | 5 | ||||
-rw-r--r-- | web/package.json | 2 | ||||
-rw-r--r-- | web/src/api.js | 4 | ||||
-rw-r--r-- | web/src/containers/SourceContext.jsx | 38 | ||||
-rw-r--r-- | web/src/containers/job/Job.jsx | 100 | ||||
-rw-r--r-- | web/src/containers/job/JobProject.jsx | 38 | ||||
-rw-r--r-- | web/src/containers/job/JobVariant.jsx | 200 | ||||
-rw-r--r-- | web/src/containers/job/Nodeset.jsx | 90 | ||||
-rw-r--r-- | web/src/containers/job/Role.jsx | 34 | ||||
-rw-r--r-- | web/src/pages/Job.jsx | 65 | ||||
-rw-r--r-- | web/src/pages/Jobs.jsx | 9 | ||||
-rw-r--r-- | web/src/routes.js | 5 | ||||
-rw-r--r-- | web/yarn.lock | 67 |
13 files changed, 656 insertions, 1 deletions
diff --git a/releasenotes/notes/web-page-job-77fa7ffb2a1c09de.yaml b/releasenotes/notes/web-page-job-77fa7ffb2a1c09de.yaml new file mode 100644 index 000000000..388a99329 --- /dev/null +++ b/releasenotes/notes/web-page-job-77fa7ffb2a1c09de.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + A new Job page in the web interface enable browsing + through job configuration. diff --git a/web/package.json b/web/package.json index 46872965a..1aa81cb0a 100644 --- a/web/package.json +++ b/web/package.json @@ -13,6 +13,8 @@ "prop-types": "^15.6.2", "react": "^16.4.2", "react-dom": "^16.4.2", + "react-height": "^3.0.0", + "react-json-view": "^1.19.1", "react-redux": "^5.0.7", "react-router": "^4.3.1", "react-router-dom": "^4.3.1", diff --git a/web/src/api.js b/web/src/api.js index 40fc3ee17..d59ee37ee 100644 --- a/web/src/api.js +++ b/web/src/api.js @@ -121,6 +121,9 @@ function fetchBuilds (apiPrefix, queryString) { } return Axios.get(apiUrl + apiPrefix + path) } +function fetchJob (apiPrefix, jobName) { + return Axios.get(apiUrl + apiPrefix + 'job/' + jobName) +} function fetchJobs (apiPrefix) { return Axios.get(apiUrl + apiPrefix + 'jobs') } @@ -131,6 +134,7 @@ export { fetchStatus, fetchBuild, fetchBuilds, + fetchJob, fetchJobs, fetchTenants, fetchInfo diff --git a/web/src/containers/SourceContext.jsx b/web/src/containers/SourceContext.jsx new file mode 100644 index 000000000..e29154488 --- /dev/null +++ b/web/src/containers/SourceContext.jsx @@ -0,0 +1,38 @@ +// Copyright 2018 Red Hat, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +import React from 'react' +import PropTypes from 'prop-types' + + +class SourceContext extends React.Component { + static propTypes = { + context: PropTypes.object.isRequired, + showBranch: PropTypes.bool + } + + render() { + const { context, showBranch } = this.props + return ( + <span> + {context.project} + {showBranch && context.branch !== 'master' && + ' (' + context.branch + ')'} + : {context.path} + </span> + ) + } +} + +export default SourceContext diff --git a/web/src/containers/job/Job.jsx b/web/src/containers/job/Job.jsx new file mode 100644 index 000000000..2e62ae09e --- /dev/null +++ b/web/src/containers/job/Job.jsx @@ -0,0 +1,100 @@ +// Copyright 2018 Red Hat, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +import * as React from 'react' +import PropTypes from 'prop-types' +import { + Nav, + NavItem, + TabContainer, + TabPane, + TabContent, +} from 'patternfly-react' + +import JobVariant from './JobVariant' + +class Job extends React.Component { + static propTypes = { + job: PropTypes.array.isRequired, + } + + state = { + variantIdx: 0, + descriptionMaxHeight: 0 + } + + resetMaxHeight = () => { + this.setState({descriptionMaxHeight: 0}) + } + + componentDidUpdate (prevProps, prevState) { + if (prevState.descriptionMaxHeight > 0) { + this.resetMaxHeight() + } + } + + renderVariantTitle (variant, selected) { + let title = variant.variant_description + if (!title) { + title = '' + variant.branches.forEach((item) => { + if (title) { + title += ', ' + } + title += item + }) + } + if (selected) { + title = <strong>{title}</strong> + } + return title + } + + render () { + const { job } = this.props + const { variantIdx, descriptionMaxHeight } = this.state + + return ( + <React.Fragment> + <h2>{job[0].name}</h2> + <TabContainer id="zuul-job"> + <div> + <Nav bsClass="nav nav-tabs nav-tabs-pf"> + {job.map((variant, idx) => ( + <NavItem + key={idx} + onClick={() => this.setState({variantIdx: idx})}> + <div> + {this.renderVariantTitle(variant, variantIdx === idx)} + </div> + </NavItem> + ))} + </Nav> + <TabContent> + <TabPane> + <JobVariant + variant={job[variantIdx]} + descriptionMaxHeight={descriptionMaxHeight} + parent={this} + /> + </TabPane> + </TabContent> + </div> + </TabContainer> + </React.Fragment> + ) + } +} + +export default Job diff --git a/web/src/containers/job/JobProject.jsx b/web/src/containers/job/JobProject.jsx new file mode 100644 index 000000000..a34271b60 --- /dev/null +++ b/web/src/containers/job/JobProject.jsx @@ -0,0 +1,38 @@ +// Copyright 2018 Red Hat, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +import React from 'react' +import PropTypes from 'prop-types' + + +class JobProject extends React.Component { + static propTypes = { + project: PropTypes.object.isRequired + } + + render() { + const { project } = this.props + return ( + <span> + {project.project_name} + {project.override_branch && ( + ' ( override-branch: ' + project.override_branch + ')')} + {project.override_checkout && ( + ' ( override-checkout: ' + project.override_checkout+ ')')} + </span> + ) + } +} + +export default JobProject diff --git a/web/src/containers/job/JobVariant.jsx b/web/src/containers/job/JobVariant.jsx new file mode 100644 index 000000000..80a6f5b01 --- /dev/null +++ b/web/src/containers/job/JobVariant.jsx @@ -0,0 +1,200 @@ +// Copyright 2018 Red Hat, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +import * as React from 'react' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' +import { Link } from 'react-router-dom' +import { ReactHeight } from 'react-height' +import ReactJson from 'react-json-view' +import { + Icon, +} from 'patternfly-react' + +import SourceContext from '../SourceContext' +import Nodeset from './Nodeset' +import Role from './Role' +import JobProject from './JobProject' + + +class JobVariant extends React.Component { + static propTypes = { + descriptionMaxHeight: PropTypes.number.isRequired, + parent: PropTypes.object, + tenant: PropTypes.object, + variant: PropTypes.object.isRequired + } + + renderStatus (variant) { + const status = [{ + icon: variant.voting ? 'connected' : 'disconnected', + name: variant.voting ? 'Voting' : 'Non-voting' + }] + if (variant.abstract) { + status.push({ + icon: 'infrastructure', + name: 'Abstract' + }) + } + if (variant.final) { + status.push({ + icon: 'infrastructure', + name: 'Final' + }) + } + if (variant.post_review) { + status.push({ + icon: 'locked', + name: 'Post review' + }) + } + if (variant.protected) { + status.push({ + icon: 'locked', + name: 'Protected' + }) + } + + return ( + <div className="list-view-pf-additional-info"> + {status.map((item, idx) => ( + <div key={idx} className="list-view-pf-additional-info-item"> + <Icon type='pf' name={item.icon} /> + {item.name} + </div> + ))} + </div> + ) + } + + render () { + const { tenant, variant, descriptionMaxHeight } = this.props + const rows = [] + + const jobInfos = [ + 'description', 'context', 'status', + 'parent', 'attempts', 'timeout', 'semaphore', 'implied_branch', + 'nodeset', 'variables', + ] + jobInfos.forEach(key => { + let label = key + let value = variant[key] + + if (label === 'context') { + value = ( + <SourceContext + context={variant.source_context} + showBranch={true}/> + ) + } + if (label === 'status') { + value = this.renderStatus(variant) + } + + if (!value) { + return + } + + if (label === 'nodeset') { + value = <Nodeset nodeset={value} /> + } + + if (label === 'parent') { + value = ( + <Link to={tenant.linkPrefix + '/job/' + value}> + {value} + </Link> + ) + } + if (label === 'variables') { + value = ( + <span style={{whiteSpace: 'pre'}}> + <ReactJson + src={value} + sortKeys={true} + enableClipboard={false} + displayDataTypes={false}/> + </span> + ) + } + if (label === 'description') { + const style = { + whiteSpace: 'pre' + } + if (descriptionMaxHeight > 0) { + style.minHeight = descriptionMaxHeight + } + value = ( + <ReactHeight onHeightReady={height => { + if (height > descriptionMaxHeight) { + this.props.parent.setState({descriptionMaxHeight: height}) + } + }}> + <div style={style}> + {value} + </div> + </ReactHeight> + ) + } + rows.push({label: label, value: value}) + }) + const jobInfosList = [ + 'required_projects', 'dependencies', 'files', 'irrelevant_files', 'roles' + ] + jobInfosList.forEach(key => { + let label = key + let values = variant[key] + + if (values.length === 0) { + return + } + const items = ( + <ul className='list-group'> + {values.map((value, idx) => { + let item + if (label === 'required_projects') { + item = <JobProject project={value} /> + } else if (label === 'roles') { + item = <Role role={value} /> + } else { + item = value + } + return ( + <li className='list-group-item' key={idx}> + {item} + </li> + ) + })} + </ul> + ) + rows.push({label: label, value: items}) + }) + return ( + <div> + <table className='table table-striped table-bordered'> + <tbody> + {rows.map(item => ( + <tr key={item.label}> + <td style={{width: '10%'}}>{item.label}</td> + <td>{item.value}</td> + </tr> + ))} + </tbody> + </table> + </div> + ) + } +} + +export default connect(state => ({tenant: state.tenant}))(JobVariant) diff --git a/web/src/containers/job/Nodeset.jsx b/web/src/containers/job/Nodeset.jsx new file mode 100644 index 000000000..14aba1b7d --- /dev/null +++ b/web/src/containers/job/Nodeset.jsx @@ -0,0 +1,90 @@ +// Copyright 2018 Red Hat, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +import * as React from 'react' +import PropTypes from 'prop-types' +import { + AggregateStatusCount, + AggregateStatusNotifications, + AggregateStatusNotification, + Card, + CardBody, + CardTitle, + Icon, +} from 'patternfly-react' + + +class Nodeset extends React.Component { + static propTypes = { + nodeset: PropTypes.object.isRequired + } + + render () { + const { nodeset } = this.props + const nodes = ( + <ul className="list-group"> + {nodeset.nodes.map((item, idx) => { + const groups = [] + nodeset.groups.forEach(group => { + if (group.nodes.indexOf(item.name) !== -1) { + groups.push(group.name) + } + }) + return ( + <li className="list-group-item" key={idx}> + <span title="Node name"> + {item.name} + </span> - + <span title="Label name"> + {item.label} + </span> + <span title="Groups"> + {groups.length > 0 && ' (' + groups.map(item => (item)) + ') '} + </span> + </li>) + })} + </ul> + ) + return ( + <Card accented aggregated> + <CardTitle> + {nodeset.name} + </CardTitle> + <CardBody> + <AggregateStatusNotifications> + <AggregateStatusNotification> + <span title="Nodes"> + <Icon type="pf" name="server" /> + <AggregateStatusCount> + {nodeset.nodes.length} + </AggregateStatusCount> + </span> + </AggregateStatusNotification> + <AggregateStatusNotification> + <span title="Groups"> + <Icon type="pf" name="server-group" /> + <AggregateStatusCount> + {nodeset.groups.length} + </AggregateStatusCount> + </span> + </AggregateStatusNotification> + </AggregateStatusNotifications> + {nodes} + </CardBody> + </Card> + ) + } +} + +export default Nodeset diff --git a/web/src/containers/job/Role.jsx b/web/src/containers/job/Role.jsx new file mode 100644 index 000000000..97843f3ee --- /dev/null +++ b/web/src/containers/job/Role.jsx @@ -0,0 +1,34 @@ +// Copyright 2018 Red Hat, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +import React from 'react' +import PropTypes from 'prop-types' + + +class Role extends React.Component { + static propTypes = { + role: PropTypes.object.isRequired + } + + render() { + const { role } = this.props + return ( + <span> + {role.target_name} ( {role.project_canonical_name}) + </span> + ) + } +} + +export default Role diff --git a/web/src/pages/Job.jsx b/web/src/pages/Job.jsx new file mode 100644 index 000000000..d4108fe74 --- /dev/null +++ b/web/src/pages/Job.jsx @@ -0,0 +1,65 @@ +// Copyright 2018 Red Hat, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +import * as React from 'react' +import { connect } from 'react-redux' +import PropTypes from 'prop-types' + +import Job from '../containers/job/Job' +import { fetchJob } from '../api' + + +class JobPage extends React.Component { + static propTypes = { + match: PropTypes.object.isRequired, + tenant: PropTypes.object + } + + state = { + job: null + } + + updateData = () => { + fetchJob(this.props.tenant.apiPrefix, this.props.match.params.jobName) + .then(response => { + this.setState({job: response.data}) + }) + } + + componentDidMount () { + document.title = 'Zuul Job | ' + this.props.match.params.jobName + if (this.props.tenant.name) { + this.updateData() + } + } + + componentDidUpdate (prevProps) { + if (this.props.tenant.name !== prevProps.tenant.name || + this.props.match.params.jobName !== prevProps.match.params.jobName) { + this.updateData() + } + } + + render () { + const { job } = this.state + if (!job) { + return (<p>Loading...</p>) + } + return ( + <Job job={job} /> + ) + } +} + +export default connect(state => ({tenant: state.tenant}))(JobPage) diff --git a/web/src/pages/Jobs.jsx b/web/src/pages/Jobs.jsx index 8ec0e3d72..d4ef1553f 100644 --- a/web/src/pages/Jobs.jsx +++ b/web/src/pages/Jobs.jsx @@ -58,6 +58,12 @@ class JobsPage extends React.Component { const headerFormat = value => <Table.Heading>{value}</Table.Heading> const cellFormat = (value) => ( <Table.Cell>{value}</Table.Cell>) + const cellJobFormat = (value) => ( + <Table.Cell> + <Link to={this.props.tenant.linkPrefix + '/job/' + value}> + {value} + </Link> + </Table.Cell>) const cellBuildFormat = (value) => ( <Table.Cell> <Link to={this.props.tenant.linkPrefix + '/builds?job_name=' + value}> @@ -69,6 +75,9 @@ class JobsPage extends React.Component { myColumns.forEach(column => { let formatter = cellFormat let prop = column + if (column === 'name') { + formatter = cellJobFormat + } if (column === 'Last builds') { prop = 'name' formatter = cellBuildFormat diff --git a/web/src/routes.js b/web/src/routes.js index ff2ca7c92..fef79debe 100644 --- a/web/src/routes.js +++ b/web/src/routes.js @@ -13,6 +13,7 @@ // under the License. import StatusPage from './pages/Status' +import JobPage from './pages/Job' import JobsPage from './pages/Jobs' import BuildPage from './pages/Build' import BuildsPage from './pages/Builds' @@ -44,6 +45,10 @@ const routes = () => [ component: StreamPage }, { + to: '/job/:jobName', + component: JobPage + }, + { to: '/build/:buildId', component: BuildPage }, diff --git a/web/yarn.lock b/web/yarn.lock index 025242168..2cee873f7 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -1209,6 +1209,10 @@ balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" +base16@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70" + base64-js@^1.0.2: version "1.3.0" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" @@ -3082,7 +3086,13 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" -fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.16: +fbemitter@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-2.1.1.tgz#523e14fdaf5248805bb02f62efc33be703f51865" + dependencies: + fbjs "^0.8.4" + +fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.9: version "0.8.17" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" dependencies: @@ -3202,6 +3212,13 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" +flux@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/flux/-/flux-3.1.3.tgz#d23bed515a79a22d933ab53ab4ada19d05b2f08a" + dependencies: + fbemitter "^2.0.0" + fbjs "^0.8.0" + follow-redirects@^1.0.0, follow-redirects@^1.3.0: version "1.5.5" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.5.tgz#3c143ca599a2e22e62876687d68b23d55bad788b" @@ -4719,6 +4736,10 @@ lodash.cond@^4.3.0: version "4.5.2" resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" +lodash.curry@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170" + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -4727,6 +4748,10 @@ lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" +lodash.flow@^3.3.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a" + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -5986,6 +6011,12 @@ prop-types-extra@^1.0.1: react-is "^16.3.2" warning "^3.0.0" +prop-types@15.5.8: + version "15.5.8" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.8.tgz#6b7b2e141083be38c8595aa51fc55775c7199394" + dependencies: + fbjs "^0.8.9" + prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" @@ -6034,6 +6065,10 @@ punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" +pure-color@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e" + q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -6114,6 +6149,15 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-base16-styling@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c" + dependencies: + base16 "^1.0.0" + lodash.curry "^4.0.1" + lodash.flow "^3.3.0" + pure-color "^1.2.0" + react-bootstrap-switch@^15.5.3: version "15.5.3" resolved "https://registry.yarnpkg.com/react-bootstrap-switch/-/react-bootstrap-switch-15.5.3.tgz#97287791d4ec0d1892d142542e7e5248002b1251" @@ -6210,10 +6254,25 @@ react-fontawesome@^1.6.1: dependencies: prop-types "^15.5.6" +react-height@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/react-height/-/react-height-3.0.0.tgz#fae322f9da64d3e9e25536f26b77c73954261524" + dependencies: + prop-types "15.5.8" + react-is@^16.3.2: version "16.4.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.2.tgz#84891b56c2b6d9efdee577cc83501dfc5ecead88" +react-json-view@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.19.1.tgz#95d8e59e024f08a25e5dc8f076ae304eed97cf5c" + dependencies: + flux "^3.1.3" + react-base16-styling "^0.6.0" + react-lifecycles-compat "^3.0.4" + react-textarea-autosize "^6.1.0" + react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -6337,6 +6396,12 @@ react-scripts@1.1.4: optionalDependencies: fsevents "^1.1.3" +react-textarea-autosize@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-6.1.0.tgz#df91387f8a8f22020b77e3833c09829d706a09a5" + dependencies: + prop-types "^15.6.0" + react-transition-group@^2.0.0, react-transition-group@^2.2.0: version "2.4.0" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.4.0.tgz#1d9391fabfd82e016f26fabd1eec329dbd922b5a" |