summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Cacqueray <tdecacqu@redhat.com>2018-08-28 08:51:39 +0000
committerTristan Cacqueray <tdecacqu@redhat.com>2018-10-11 02:58:06 +0000
commit6cb6b736150f0f65a29733e3055fa098953f901c (patch)
treecb4025fe778e90f190cc2c20f59895df16c5fcf0
parent99c38c93751bd2c0f1f6237268df117f28af5ac2 (diff)
downloadzuul-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.yaml5
-rw-r--r--web/package.json2
-rw-r--r--web/src/api.js4
-rw-r--r--web/src/containers/SourceContext.jsx38
-rw-r--r--web/src/containers/job/Job.jsx100
-rw-r--r--web/src/containers/job/JobProject.jsx38
-rw-r--r--web/src/containers/job/JobVariant.jsx200
-rw-r--r--web/src/containers/job/Nodeset.jsx90
-rw-r--r--web/src/containers/job/Role.jsx34
-rw-r--r--web/src/pages/Job.jsx65
-rw-r--r--web/src/pages/Jobs.jsx9
-rw-r--r--web/src/routes.js5
-rw-r--r--web/yarn.lock67
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> -&nbsp;
+ <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"