Commit 0365ba8e by Barnabás Czémán

Add initial forms and pages

parent d1490b28
DANGEROUSLY_DISABLE_HOST_CHECK=true
......@@ -2,6 +2,7 @@
"extends": "airbnb",
"rules": {
"react/jsx-filename-extension": "off",
"react/prop-types": "off",
"import/extensions": off,
"jsx-quotes": ["error", "prefer-single"],
"max-len": ["error", 125],
......@@ -11,4 +12,3 @@
"document": "false"
}
}
......@@ -2,22 +2,34 @@
"name": "network-frontend",
"version": "0.1.0",
"private": true,
"proxy": "http://127.0.0.1:8080",
"dependencies": {
"axios": "^0.17.0",
"moment": "^2.19.2",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-redux": "^5.0.6",
"react-router-dom": "^4.2.2",
"react-scripts": "1.0.14",
"redux": "^3.7.2",
"redux-form": "^7.1.2",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.2.0",
"semantic-ui-css": "^2.2.12",
"semantic-ui-react": "^0.75.1"
"semantic-ui-react": "^0.75.1",
"underscore": "^1.8.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"devDependencies": {
"eslint": "^4.10.0",
"eslint-config-airbnb": "^16.1.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-react": "^7.4.0"
}
}
import React from 'react'
import { Container, Divider, Dropdown, Grid, Header, Image, List, Menu, Segment } from 'semantic-ui-react'
import { Container, Dropdown, List, Menu, Segment } from 'semantic-ui-react'
import { NavLink, Link, Route } from 'react-router-dom'
import {
HostList,
VlanList,
DomainList,
RecordList,
BlacklistList,
RuleList,
FirewallList,
SwitchPortList,
VlanGroupList,
HostGroupList,
} from './containers'
import DomainFormContainer from './containers/DomainFormContainer'
import VlanFormContainer from './containers/VlanFormContainer'
import HostFormContainer from './containers/HostFormContainer'
import BlacklistFormContainer from './containers/BlacklistFormContainer'
import RuleFormContainer from './containers/RuleFormContainer'
import FirewallFormContainer from './containers/FirewallFormContainer'
import RecordFormContainer from './containers/RecordFormContainer'
import SwitchPortFormContainer from './containers/SwitchPortFormContainer'
import VlanGroupFormContainer from './containers/VlanGroupFormContainer'
import HostGroupFormContainer from './containers/HostGroupFormContainer'
const App = () => (
<div>
<Menu fixed='top' inverted>
......@@ -25,23 +49,33 @@ const App = () => (
</Container>
</Menu>
<Container text style={{ marginTop: '7em' }}>
<Container text style={{ marginTop: '7em', marginBottom: '7em' }}>
<Route path='/' exact />
<Route path='/hosts' />
<Route path='/vlans' />
<Route path='/doamins' />
<Route path='/records' />
<Route path='/blacklist' />
<Route path='/rules' />
<Route path='/switchports' />
<Route path='/firewalls' />
<Route path='/vlangroups' />
<Route path='/hostgroups' />
<Route path='/hosts' exact component={HostList} />
<Route path='/hosts/:id' component={HostFormContainer} />
<Route path='/vlans' exact component={VlanList} />
<Route path='/vlans/:id' component={VlanFormContainer} />
<Route path='/domains' exact component={DomainList} />
<Route path='/domains/:id' component={DomainFormContainer} />
<Route path='/records' exact component={RecordList} />
<Route path='/records/:id' component={RecordFormContainer} />
<Route path='/blacklist' exact component={BlacklistList} />
<Route path='/blacklist/:id' component={BlacklistFormContainer} />
<Route path='/rules' exact component={RuleList} />
<Route path='/rules/:id' component={RuleFormContainer} />
<Route path='/switchports' exact component={SwitchPortList} />
<Route path='/switchports/:id' component={SwitchPortFormContainer} />
<Route path='/firewalls' exact component={FirewallList} />
<Route path='/firewalls/:id' component={FirewallFormContainer} />
<Route path='/vlangroups' exact component={VlanGroupList} />
<Route path='/vlangroups/:id' component={VlanGroupFormContainer} />
<Route path='/hostgroups' exact component={HostGroupList} />
<Route path='/hostgroups/:id' exact component={HostGroupFormContainer} />
</Container>
<Segment inverted vertical >
<Container textAlign='center'>
<List horizontal inverted divided link>
<List horizontal inverted divided link>
<List.Item as='a' href='#'>Legal Notice</List.Item>
<List.Item as='a' href='#'>Policy</List.Item>
<List.Item as='a' href='#'>Help</List.Item>
......
import React from 'react'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
const Root = ({ store }) => (
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
)
export default Root
import axios from 'axios'
export const REQUEST_DATA = 'REQUEST_DATA'
export const RECEIVE_DATA = 'RECEIVE_DATA'
export const REQUEST_OPTIONS = 'REQUEST_OPTIONS'
export const RECEIVE_OPTIONS = 'RECEIVE_OPTIONS'
export const receiveData = (name, { data }) => ({
type: RECEIVE_DATA,
payload: {
data,
name,
isFetching: false,
},
})
export const requestData = name => ({
type: REQUEST_DATA,
payload: {
data: [],
name,
isFetching: true,
},
})
export const fetchData = (name, url) => (dispatch) => {
dispatch(requestData(name))
axios.get(url).then(response => dispatch(receiveData(name, response)))
}
const config = {
xsrfCookieName: 'csrftoken',
xsrfHeaderName: 'X-CSRFToken',
}
export const postData = (url, data) => () => axios.post(url, data, config)
export const putData = (url, data) => () => axios.put(url, data, config)
export const deleteData = url => () => axios.delete(url, config)
export const receiveOptions = (name, { data }) => ({
type: RECEIVE_OPTIONS,
payload: {
options: data,
name,
isFetching: false,
},
})
export const requestOptions = name => ({
type: REQUEST_OPTIONS,
payload: {
options: {},
name,
isFetching: true,
},
})
export const fetchOptions = (name, url) => (dispatch) => {
dispatch(requestOptions(name))
return axios.options(url).then(response => dispatch(receiveOptions(name, response)))
}
/* export const logMe = data => (
async (dispatch) => {
console.log(data)
try {
const response = await axios.post('url', data)
} catch (err) {
console.error(err)
}
}
) */
import React from 'react'
import { reduxForm, Field } from 'redux-form'
import { Form } from 'semantic-ui-react'
import SemanticReduxFormField from '../components/SemanticReduxFormField'
const BlacklistForm = ({
pristine,
submitting,
hostOptions,
handleSubmit,
}) => (
<Form onSubmit={handleSubmit}>
<Field component={Form.Input} type='text' placeholder='IPv4' name='ipv4' />
<Field
options={hostOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='host'
type='text'
search
/>
<Field component={Form.Input} type='datetime-local' name='expires_at' />
<Field component={Form.Checkbox} label='Whitelisted' name='whitelisted' />
<Field component={Form.TextArea} label='Reason' name='reason' />
<Field component={Form.TextArea} label='Short Message' name='short_message' />
<Form.Button disabled={pristine || submitting} type='submit'>Submit</Form.Button>
</Form>
)
export default reduxForm({ form: 'blacklist' })(BlacklistForm)
import React from 'react'
import { Image } from 'semantic-ui-react'
const Dashboard = () => (
<Image src='' alt='graphit' />
)
export default Dashboard
import React, { Component } from 'react'
import { Table, Icon, Menu } from 'semantic-ui-react'
import moment from 'moment'
import _ from 'underscore'
export default class DataTable extends Component {
constructor(props) {
super(props)
this.state = {
column: null,
data: this.props.data,
direction: null,
}
}
handleSort(clickedColumn) {
const { column, data, direction } = this.state
if (column !== clickedColumn) {
this.setState({
column: clickedColumn,
data: { ...data, results: _.sortBy(data.results, clickedColumn) },
direction: 'ascending',
})
} else {
this.setState({
data: { results: data.results.reverse() },
direction: direction === 'ascending' ? 'descending' : 'ascending',
})
}
}
handlePagination(url) {
this.props.onPagination(url).then(data => this.setState(data))
}
handleRowClick(item) {
const { options } = this.props
this.props.history.push(`${this.props.match.path}/edit`, { item, options })
}
renderField(item, field) {
const { POST } = this.props.options.actions
if (item[field] !== null) {
switch (POST[field].type) {
case 'datetime':
return moment(item[field]).format('YYYY.MM.DD hh:mm')
case 'boolean':
if (item[field] === true) {
return <Icon color='green' name='checkmark' size='large' />
}
return <Icon color='red' name='close' size='large' />
case 'field':
case 'choices':
case 'integer':
case 'string':
default:
return item[field]
}
}
return ''
}
renderItems() {
const { fields } = this.props
const { data } = this.state
return data.results.map(item => (
<Table.Row key={item.url} onClick={() => this.handleRowClick(item)}>
{fields.map(field => (
<Table.Cell key={field}>{this.renderField(item, field)}</Table.Cell>
))}
</Table.Row>
))
}
render() {
if (this.props.options !== undefined) {
const { options: { actions: { POST } }, data, fields } = this.props
const { column, direction } = this.state
return (
<Table sortable selectable singleLine>
<Table.Header>
<Table.Row>
{fields.map(field => (
<Table.HeaderCell
key={field}
sorted={column === field ? direction : null}
onClick={() => this.handleSort(field)}
>
{POST[field].label}
</Table.HeaderCell>
))}
</Table.Row>
</Table.Header>
<Table.Body>
{ this.renderItems() }
</Table.Body>
<Table.Footer>
<Table.Row>
<Table.HeaderCell colSpan={fields.length}>
{ data.previous || data.next ?
<Menu floated='right' pagination>
{ data.previous ?
<Menu.Item onClick={() => this.handlePagination(data.previous)}>Previous</Menu.Item> : ''
}
{ data.next ?
<Menu.Item onClick={() => this.handlePagination(data.next)}>Next</Menu.Item> : ''
}
</Menu> : ''
}
</Table.HeaderCell>
</Table.Row>
</Table.Footer>
</Table>
)
}
return <div />
}
}
import React from 'react'
import { reduxForm, Field } from 'redux-form'
import { Form } from 'semantic-ui-react'
import SemanticReduxFormField from '../components/SemanticReduxFormField'
const DomainForm = ({
pristine,
submitting,
handleSubmit,
ownerOptions,
}) => (
<Form onSubmit={handleSubmit}>
<Field component={Form.Input} type='text' placeholder='Name' name='name' />
<Field component={Form.Input} type='number' placeholder='Ttl' name='ttl' />
<Field
options={ownerOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='owner'
type='text'
search
/>
<Form.Button disabled={pristine || submitting} type='submit'>Submit</Form.Button>
</Form>
)
export default reduxForm({ form: 'domain' })(DomainForm)
import React from 'react'
import { reduxForm, Field } from 'redux-form'
import { Form } from 'semantic-ui-react'
const FirewallForm = ({ pristine, submitting, handleSubmit }) => (
<Form onSubmit={handleSubmit}>
<Field component={Form.Input} type='text' placeholder='Name' name='name' />
<Form.Button disabled={pristine || submitting} type='submit'>Submit</Form.Button>
</Form>
)
export default reduxForm({ form: 'domain' })(FirewallForm)
import React from 'react'
import { reduxForm, Field } from 'redux-form'
import { Form } from 'semantic-ui-react'
import SemanticReduxFormField from '../components/SemanticReduxFormField'
const HostForm = ({
pristine,
submitting,
handleSubmit,
ownerOptions,
}) => (
<Form onSubmit={handleSubmit}>
<Field component={Form.Input} type='text' placeholder='Name' name='name' />
<Field component={Form.Input} type='number' placeholder='Ttl' name='ttl' />
<Field
options={ownerOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='owner'
type='text'
search
/>
<Form.Button disabled={pristine || submitting} type='submit'>Submit</Form.Button>
</Form>
)
export default reduxForm({ form: 'host' })(HostForm)
import React from 'react'
import { reduxForm, Field } from 'redux-form'
import { Form } from 'semantic-ui-react'
import SemanticReduxFormField from '../components/SemanticReduxFormField'
const HostGroupForm = ({
pristine,
submitting,
handleSubmit,
ownerOptions,
}) => (
<Form onSubmit={handleSubmit}>
<Field component={Form.Input} type='text' placeholder='Name' name='name' />
<Field component={Form.TextArea} type='text' label='Description' name='description' />
<Field
options={ownerOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='owner'
type='text'
search
/>
<Form.Button disabled={pristine || submitting} type='submit'>Submit</Form.Button>
</Form>
)
export default reduxForm({ form: 'domain' })(HostGroupForm)
import React from 'react'
import { reduxForm, Field } from 'redux-form'
import { Form } from 'semantic-ui-react'
import SemanticReduxFormField from '../components/SemanticReduxFormField'
const RecordForm = ({
pristine,
submitting,
handleSubmit,
hostOptions,
domainOptions,
ownerOptions,
}) => (
<Form onSubmit={handleSubmit}>
<Field
options={[
{ key: 'A', value: 'A', text: 'A' },
{ key: 'CNAME', value: 'CNAME', text: 'CNAME' },
{ key: 'AAAA', value: 'AAAA', text: 'AAAA' },
{ key: 'MX', value: 'MX', text: 'MX' },
{ key: 'NS', value: 'NS', text: 'NS' },
{ key: 'PTR', value: 'PTR', text: 'PTR' },
{ key: 'TXT', value: 'TXT', text: 'TXT' },
]}
component={SemanticReduxFormField}
as={Form.Select}
name='type'
type='text'
/>
<Field
options={hostOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='host'
type='text'
search
/>
<Field component={Form.Input} type='text' placeholder='Name' name='name' />
<Field
options={domainOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='domain'
type='text'
search
/>
<Field component={Form.Input} type='text' placeholder='Address' name='address' />
<Field component={Form.Input} type='number' placeholder='Ttl' name='ttl' />
<Field component={Form.TextArea} name='description' label='Description' />
<Field
options={ownerOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='owner'
type='text'
search
/>
<Form.Button disabled={pristine || submitting} type='submit'>Submit</Form.Button>
</Form>
)
export default reduxForm({ form: 'record' })(RecordForm)
import React from 'react'
import { reduxForm, Field } from 'redux-form'
import { Form } from 'semantic-ui-react'
const HostForm = ({ pristine, submitting, handleSubmit }) => (
<Form onSubmit={handleSubmit}>
<Field component={Form.Input} type='text' placeholder='Name' name='name' />
<Form.Button disabled={pristine || submitting} type='submit'>Submit</Form.Button>
</Form>
)
export default reduxForm({ form: 'domain' })(HostForm)
import React, { Component } from 'react'
import { Input } from 'semantic-ui-react'
export default class SemanticReduxFormField extends Component {
handleChange(value) {
const { input } = this.props
return input.onChange(value)
}
render() {
const { input, meta: { touched, error }, as: As = Input } = this.props
return (
<As
{...input}
value={input.value || []}
{...this.props}
onChange={(e, { value }) => this.handleChange(value)}
error={touched && error}
/>
)
}
}
import React from 'react'
import { reduxForm, Field } from 'redux-form'
import { Form } from 'semantic-ui-react'
import SemanticReduxFormField from '../components/SemanticReduxFormField'
const SwitchPortForm = ({
pristine,
submitting,
handleSubmit,
taggedVlansOptions,
unTaggedVlanOptions,
}) => (
<Form onSubmit={handleSubmit}>
<Field
options={taggedVlansOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='tagged_vlans'
label='Tagged Vlans'
type='text'
search
/>
<Field
options={unTaggedVlanOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='untagged_vlan'
label='Untagged Vlan'
type='text'
search
/>
<Field component={Form.TextArea} label='Description' name='description' />
<Form.Button disabled={pristine || submitting} type='submit'>Submit</Form.Button>
</Form>
)
export default reduxForm({ form: 'domain' })(SwitchPortForm)
import React from 'react'
import { reduxForm, formValueSelector, Field } from 'redux-form'
import { connect } from 'react-redux'
import { Form, Segment } from 'semantic-ui-react'
import SemanticReduxFormField from './SemanticReduxFormField'
const VlanForm = ({
pristine,
submitting,
handleSubmit,
networkType,
natToOptions,
domainOptions,
ownerOptions,
}) => (
<Form onSubmit={handleSubmit}>
<Field component={Form.Input} type='text' placeholder='Name' name='name' />
<Field component={Form.Input} type='number' placeholder='VID' name='vid' />
<Field
component={SemanticReduxFormField}
as={Form.Select}
type='text'
options={[
{ key: 'public', value: 'public', text: 'Public' },
{ key: 'portforward', value: 'portforward', text: 'Portforward' },
]}
name='network_type'
/>
<Field component={Form.Input} type='text' placeholder='IPv4 address/prefix' name='network4' />
<Field component={Form.Checkbox} name='managed' label='Managed' />
{ networkType === 'portforward' && (
<Segment basic>
<Field
component={Form.Select}
as={Form.Select}
name='snat_to'
options={natToOptions()}
multiple
search
/>
<Field component={Form.Input} type='text' placeholder='Snat IP' name='snat_ip' />
<Field component={Form.TextArea} name='dhcp_pool' />
</Segment>
)}
<Field component={Form.Input} type='text' placeholder='IPv6 address/prefix' name='network6' />
<Field component={Form.Input} type='text' placeholder='IPv6 template' name='ipv6_template' />
<Field component={Form.Input} type='number' placeholder='IPv6 prefixlen/host' name='host_ipv6_prefixlen' />
<Field component={Form.Input} type='text' placeholder='IPv6 template' name='ipv6_template' />
<Field
component={SemanticReduxFormField}
as={Form.Select}
type='text'
name='domain'
options={domainOptions()}
search
/>
<Field component={Form.Input} type='text' placeholder='Reverse Domain' name='reverse_domain' />
<Field component={Form.TextArea} label='Description' name='description' />
<Field component={Form.TextArea} label='Comment' name='comment' />
<Field
component={SemanticReduxFormField}
as={Form.Select}
type='text'
name='owner'
options={ownerOptions()}
search
/>
<Form.Button disabled={pristine || submitting} type='submit'>Submit</Form.Button>
</Form>
)
const formName = 'vlan'
const selector = formValueSelector(formName)
const mapStateToProps = state => ({
networkType: selector(state, 'network_type'),
})
export default connect(mapStateToProps)(reduxForm({ form: formName })(VlanForm))
import React from 'react'
import { reduxForm, Field } from 'redux-form'
import { Form } from 'semantic-ui-react'
import SemanticReduxFormField from '../components/SemanticReduxFormField'
const VlanGroupForm = ({
pristine,
submitting,
handleSubmit,
vlansOptions,
ownerOptions,
}) => (
<Form onSubmit={handleSubmit}>
<Field component={Form.Input} type='text' placeholder='Name' name='name' />
<Field
options={vlansOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='vlans'
type='text'
search
multiple
/>
<Field component={Form.TextArea} label='Description' name='description' />
<Field
options={ownerOptions()}
component={SemanticReduxFormField}
as={Form.Select}
name='owner'
type='text'
search
/>
<Form.Button disabled={pristine || submitting} type='submit'>Submit</Form.Button>
</Form>
)
export default reduxForm({ form: 'domain' })(VlanGroupForm)
import React from 'react'
import { Segment, Header, Divider } from 'semantic-ui-react'
const Wrapper = ({ title, children }) => (
<Segment basic>
<Header as='h2'>{title}</Header>
<Divider />
{children}
</Segment>
)
export default Wrapper
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { postData, fetchData } from '../actions'
import BlacklistForm from '../components/BlacklistForm'
import Wrapper from '../components/Wrapper'
class BlacklistFormContainer extends Component {
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchData('hosts', '/api/v1/network/hosts/'))
}
genSelectOptions() {
const { hosts } = this.props.data
if (hosts === undefined) { return [] }
return hosts.map(host => ({ key: host.url, text: host.hostname, value: host.url }))
}
render() {
const { handleSubmit } = this.props
console.log(this.props)
return (
<Wrapper title='Blacklist'>
<BlacklistForm onSubmit={handleSubmit} hostOptions={() => this.genSelectOptions()} />
</Wrapper>
)
}
}
const mapStateToProps = ({ data }) => ({ data })
const mapDispatchToProps = dispatch => ({
handleSubmit: data => dispatch(postData('/api/v1/network/blacklist/', data)),
dispatch,
})
// TODO: Add id parameter for handleSubmit
export default connect(mapStateToProps, mapDispatchToProps)(BlacklistFormContainer)
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchData, fetchOptions } from '../actions'
import DataTable from '../components/DataTable'
import Wrapper from '../components/Wrapper'
class _BlacklistList extends Component {
constructor(props) {
super(props)
this.state = {
fields: ['ipv4', 'host_name', 'reason', 'whitelisted', 'expires_at', 'created_at'],
url: '/api/v1/network/blacklist/?page_size=25',
name: 'blacklist',
}
}
componentDidMount() {
const { url } = this.state
const { dispatch } = this.props
dispatch(fetchData(this.state.name, url))
dispatch(fetchOptions(this.state.name, url))
}
render() {
const { fields, url, name } = this.state
const { isDataFetching, isOptionsFetching, dispatch } = this.props
if (isDataFetching === false && isOptionsFetching === false) {
return (
<Wrapper title='BlackList'>
<DataTable
{...this.props}
fields={fields}
url={url}
onPagination={next => dispatch(fetchData(name, `${next}&page_size=25`))}
/>
</Wrapper>
)
}
return <div />
}
}
const mapStateToProps = ({
data: { blacklist, isDataFetching },
options: { blacklistOptions, isOptionsFetching },
}) => ({
data: blacklist,
options: blacklistOptions,
isDataFetching,
isOptionsFetching,
})
const BlacklistList = withRouter(connect(mapStateToProps)(_BlacklistList))
export { BlacklistList }
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { postData, fetchData } from '../actions'
import DomainForm from '../components/DomainForm'
import Wrapper from '../components/Wrapper'
class DomainFormContainer extends Component {
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchData('owners', '/api/v1/dashboard/user/'))
}
genSelectOptions() {
const { owners } = this.props.data
if (owners === undefined) { return [] }
return owners.map(owner => ({ key: owner.url, text: `${owner.full_name} (${owner.email})`, value: owner.url }))
}
render() {
const { handleSubmit } = this.props
return (
<Wrapper title='Domain'>
<DomainForm onSubmit={handleSubmit} ownerOptions={() => this.genSelectOptions()} />
</Wrapper>
)
}
}
const mapStateToProps = ({ data }) => ({ data })
const mapDispatchToProps = dispatch => ({
handleSubmit: data => dispatch(postData('/api/v1/network/domains/', data)),
dispatch,
})
// TODO: Add id parameter for handleSubmit
export default connect(mapStateToProps, mapDispatchToProps)(DomainFormContainer)
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchData, fetchOptions } from '../actions'
import DataTable from '../components/DataTable'
import Wrapper from '../components/Wrapper'
class _DomainList extends Component {
constructor(props) {
super(props)
this.state = {
fields: ['name', 'owner_name', 'ttl'],
url: '/api/v1/network/domains/?page_size=25',
name: 'domains',
}
}
componentDidMount() {
const { url } = this.state
const { dispatch } = this.props
dispatch(fetchData(this.state.name, url))
dispatch(fetchOptions(this.state.name, url))
}
render() {
const { fields, url, name } = this.state
const { isDataFetching, isOptionsFetching, dispatch } = this.props
if (isDataFetching === false && isOptionsFetching === false) {
return (
<Wrapper title='Domains'>
<DataTable
{...this.props}
fields={fields}
url={url}
onPagination={next => dispatch(fetchData(name, `${next}&page_size=25`))}
/>
</Wrapper>
)
}
return <div />
}
}
const mapStateToProps = ({
data: { domains, isDataFetching },
options: { domainsOptions, isOptionsFetching }
}) => ({
data: domains,
options: domainsOptions,
isDataFetching,
isOptionsFetching,
})
const DomainList = withRouter(connect(mapStateToProps)(_DomainList))
export { DomainList }
import React from 'react'
import { connect } from 'react-redux'
import { postData } from '../actions'
import FirewallForm from '../components/FirewallForm'
import Wrapper from '../components/Wrapper'
const FirewallFormContainer = ({ handleSubmit }) => (
<Wrapper title='Firewall'>
<FirewallForm onSubmit={handleSubmit} />
</Wrapper>
)
// TODO: Add id parameter for handleSubmit
export default connect(null, {
handleSubmit: data => postData('/api/v1/network/firewalls/', data),
})(FirewallFormContainer)
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchData, fetchOptions } from '../actions'
import DataTable from '../components/DataTable'
import Wrapper from '../components/Wrapper'
class _FirewallList extends Component {
constructor(props) {
super(props)
this.state = {
fields: ['name'],
url: '/api/v1/network/firewalls/?page_size=25',
name: 'firewalls'
}
}
componentDidMount() {
const { url } = this.state
const { dispatch } = this.props
dispatch(fetchData(this.state.name, url))
dispatch(fetchOptions(this.state.name, url))
}
render() {
const { fields, url, name } = this.state
const { isDataFetching, isOptionsFetching, dispatch } = this.props
if (isDataFetching === false && isOptionsFetching === false) {
return (
<Wrapper title='Firewalls'>
<DataTable
{...this.props}
fields={fields}
url={url}
onPagination={next => dispatch(fetchData(name, `${next}&page_size=25`))}
/>
</Wrapper>
)
}
return <div />
}
}
const mapStateToProps = ({
data: { firewalls, isDataFetching },
options: { firewallsOptions, isOptionsFetching },
}) => ({
data: firewalls,
options: firewallsOptions,
isDataFetching,
isOptionsFetching,
})
const FirewallList = withRouter(connect(mapStateToProps)(_FirewallList))
export { FirewallList }
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { postData, fetchData } from '../actions'
import HostForm from '../components/HostForm'
import Wrapper from '../components/Wrapper'
class HostFormContainer extends Component {
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchData('owners', '/api/v1/dashboard/user/'))
}
genSelectOptions() {
const { owners } = this.props.data
if (owners === undefined) { return [] }
return owners.map(owner => ({ key: owner.url, text: `${owner.full_name} (${owner.email})`, value: owner.url }))
}
render() {
const { handleSubmit } = this.props
return (
<Wrapper title='Host'>
<HostForm onSubmit={handleSubmit} ownerOptions={() => this.genSelectOptions()} />
</Wrapper>
)
}
}
const mapStateToProps = ({ data }) => ({ data })
const mapDispatchToProps = dispatch => ({
handleSubmit: data => dispatch(postData('/api/v1/network/domains/', data)),
dispatch,
})
// TODO: Add id parameter for handleSubmit
export default connect(mapStateToProps, mapDispatchToProps)(HostFormContainer)
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { postData, fetchData } from '../actions'
import HostGroupForm from '../components/HostGroupForm'
import Wrapper from '../components/Wrapper'
class HostGroupFormContainer extends Component {
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchData('owners', '/api/v1/dashboard/user/'))
}
genSelectOptions() {
const { owners } = this.props.data
if (owners === undefined) { return [] }
return owners.map(owner => ({ key: owner.url, text: `${owner.full_name} (${owner.email})`, value: owner.url }))
}
render() {
const { handleSubmit } = this.props
return (
<Wrapper title='HostGroup'>
<HostGroupForm onSubmit={handleSubmit} ownerOptions={() => this.genSelectOptions()} />
</Wrapper>
)
}
}
const mapStateToProps = ({ data }) => ({ data })
const mapDispatchToProps = dispatch => ({
handleSubmit: data => dispatch(postData('/api/v1/network/groups/', data)),
dispatch,
})
// TODO: Add id parameter for handleSubmit
export default connect(mapStateToProps, mapDispatchToProps)(HostGroupFormContainer)
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchData, fetchOptions } from '../actions'
import DataTable from '../components/DataTable'
import Wrapper from '../components/Wrapper'
class _HostGroupList extends Component {
constructor(props) {
super(props)
this.state = {
fields: ['name', 'description', 'owner_name'],
url: '/api/v1/network/groups/?page_size=25',
name: 'hostgroups',
}
}
componentDidMount() {
const { url } = this.state
const { dispatch } = this.props
dispatch(fetchData(this.state.name, url))
dispatch(fetchOptions(this.state.name, url))
}
render() {
const { fields, url, name } = this.state
const { isDataFetching, isOptionsFetching, dispatch } = this.props
if (isDataFetching === false && isOptionsFetching === false) {
return (
<Wrapper title='HostGroups'>
<DataTable
{...this.props}
fields={fields}
url={url}
onPagination={next => dispatch(fetchData(name, `${next}&page_size=25`))}
/>
</Wrapper>
)
}
return <div />
}
}
const mapStateToProps = ({ data: { hostgroups, isDataFetching }, options: { hostgroupsOptions, isOptionsFetching } }) => ({
data: hostgroups,
options: hostgroupsOptions,
isDataFetching,
isOptionsFetching,
})
const HostGroupList = withRouter(connect(mapStateToProps)(_HostGroupList))
export { HostGroupList }
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchData, fetchOptions } from '../actions'
import DataTable from '../components/DataTable'
import Wrapper from '../components/Wrapper'
class _HostList extends Component {
constructor(props) {
super(props)
this.state = {
fields: ['hostname', 'vlan_name', 'mac', 'ipv4', 'ipv6', 'external_ipv4', 'created_at', 'owner_name'],
url: '/api/v1/network/hosts/?page_size=25',
name: 'hosts',
}
}
componentDidMount() {
const { url } = this.state
const { dispatch } = this.props
dispatch(fetchData(this.state.name, url))
dispatch(fetchOptions(this.state.name, url))
}
render() {
const { fields, url, name } = this.state
const { isDataFetching, isOptionsFetching, dispatch } = this.props
if (isDataFetching === false && isOptionsFetching === false) {
return (
<Wrapper title='Hosts'>
<DataTable
{...this.props}
fields={fields}
url={url}
onPagination={next => dispatch(fetchData(name, `${next}&page_size=25`))}
/>
</Wrapper>
)
}
return <div />
}
}
const mapStateToProps = ({ data: { hosts, isDataFetching }, options: { hostsOptions, isOptionsFetching } }) => ({
data: hosts,
options: hostsOptions,
isDataFetching,
isOptionsFetching,
})
const HostList = withRouter(connect(mapStateToProps)(_HostList))
export { HostList }
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { postData, fetchData } from '../actions'
import RecordForm from '../components/RecordForm'
import Wrapper from '../components/Wrapper'
class RecordFormContainer extends Component {
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchData('hosts', '/api/v1/network/hosts/'))
dispatch(fetchData('domains', '/api/v1/network/domains/'))
dispatch(fetchData('owners', '/api/v1/dashboard/user/'))
}
genHostOptions() {
const { hosts } = this.props.data
if (hosts === undefined) { return [] }
return hosts.map(host => ({ key: host.url, text: host.hostname, value: host.url }))
}
genDomainOptions() {
const { domains } = this.props.data
if (domains === undefined) { return [] }
return domains.map(domain => ({ key: domain.url, text: domain.name, value: domain.url }))
}
genOwnerOptions() {
const { owners } = this.props.data
if (owners === undefined) { return [] }
return owners.map(owner => ({ key: owner.url, text: `${owner.full_name} (${owner.email})`, value: owner.url }))
}
render() {
const { handleSubmit } = this.props
return (
<Wrapper title='Record'>
<RecordForm
onSubmit={handleSubmit}
hostOptions={() => this.genHostOptions()}
domainOptions={() => this.genDomainOptions()}
ownerOptions={() => this.genOwnerOptions()}
/>
</Wrapper>
)
}
}
const mapStateToProps = ({ data }) => ({ data })
const mapDispatchToProps = dispatch => ({
handleSubmit: data => dispatch(postData('/api/v1/network/records/', data)),
dispatch,
})
// TODO: Add id parameter for handleSubmit
export default connect(mapStateToProps, mapDispatchToProps)(RecordFormContainer)
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchData, fetchOptions } from '../actions'
import DataTable from '../components/DataTable'
import Wrapper from '../components/Wrapper'
class _RecordList extends Component {
constructor(props) {
super(props)
this.state = {
fields: ['type', 'fqdn', 'host_name', 'address', 'ttl', 'owner_name'],
url: '/api/v1/network/records/?page_size=25',
name: 'records',
}
}
componentDidMount() {
const { url } = this.state
const { dispatch } = this.props
dispatch(fetchData(this.state.name, url))
dispatch(fetchOptions(this.state.name, url))
}
render() {
const { fields, url, name } = this.state
const { isDataFetching, isOptionsFetching, dispatch } = this.props
if (isDataFetching === false && isOptionsFetching === false) {
return (
<Wrapper title='Records'>
<DataTable
{...this.props}
fields={fields}
url={url}
onPagination={next => dispatch(fetchData(name, `${next}&page_size=25`))}
/>
</Wrapper>
)
}
return <div />
}
}
const mapStateToProps = ({ data: { records, isDataFetching }, options: { recordsOptions, isOptionsFetching } }) => ({
data: records,
options: recordsOptions,
isDataFetching,
isOptionsFetching,
})
const RecordList = withRouter(connect(mapStateToProps)(_RecordList))
export { RecordList }
import React from 'react'
import { connect } from 'react-redux'
import { postData } from '../actions'
import RuleForm from '../components/RuleForm'
import Wrapper from '../components/Wrapper'
const RuleFormContainer = ({ handleSubmit }) => (
<Wrapper title='Rule'>
<RuleForm onSubmit={handleSubmit} />
</Wrapper>
)
// TODO: Add id parameter for handleSubmit
export default connect(null, {
handleSubmit: data => postData('/api/v1/network/rules/', data),
})(RuleFormContainer)
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchData, fetchOptions } from '../actions'
import DataTable from '../components/DataTable'
import Wrapper from '../components/Wrapper'
class _RuleList extends Component {
constructor(props) {
super(props)
this.state = {
fields: ['direction', 'description', 'proto', 'dport'],
url: '/api/v1/network/rules/?page_size=25',
name: 'rules',
}
}
componentDidMount() {
const { url } = this.state
const { dispatch } = this.props
dispatch(fetchData(this.state.name, url))
dispatch(fetchOptions(this.state.name, url))
}
render() {
const { fields, url, name } = this.state
const { isDataFetching, isOptionsFetching, dispatch } = this.props
if (isDataFetching === false && isOptionsFetching === false) {
return (
<Wrapper title='Rules'>
<DataTable
{...this.props}
fields={fields}
url={url}
onPagination={next => dispatch(fetchData(name, `${next}&page_size=25`))}
/>
</Wrapper>
)
}
return <div />
}
}
const mapStateToProps = ({ data: { rules, isDataFetching }, options: { rulesOptions, isOptionsFetching } }) => ({
data: rules,
options: rulesOptions,
isDataFetching,
isOptionsFetching,
})
const RuleList = withRouter(connect(mapStateToProps)(_RuleList))
export { RuleList }
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { postData, fetchData } from '../actions'
import SwitchPortForm from '../components/SwitchPortForm'
import Wrapper from '../components/Wrapper'
class SwitchPortFormContainer extends Component {
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchData('taggedVlans', '/api/v1/network/vlangroups/'))
dispatch(fetchData('untaggedVlan', '/api/v1/network/vlans/'))
}
genTaggedVlansOptions() {
const { taggedVlans } = this.props.data
if (taggedVlans === undefined) { return [] }
return taggedVlans.map(vlanGroup => ({ key: vlanGroup.url, text: vlanGroup.name, value: vlanGroup.url }))
}
genUnTaggedVlanOptions() {
const { untaggedVlan } = this.props.data
if (untaggedVlan === undefined) { return [] }
return untaggedVlan.map(vlan => ({ key: vlan.url, text: vlan.name, value: vlan.url }))
}
render() {
const { handleSubmit } = this.props
return (
<Wrapper title='SwitchPort'>
<SwitchPortForm
onSubmit={handleSubmit}
taggedVlansOptions={() => this.genTaggedVlansOptions()}
unTaggedVlanOptions={() => this.genUnTaggedVlanOptions()}
/>
</Wrapper>
)
}
}
const mapStateToProps = ({ data }) => ({ data })
const mapDispatchToProps = dispatch => ({
handleSubmit: data => dispatch(postData('/api/v1/network/switchports/', data)),
dispatch,
})
// TODO: Add id parameter for handleSubmit
export default connect(mapStateToProps, mapDispatchToProps)(SwitchPortFormContainer)
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchData, fetchOptions } from '../actions'
import DataTable from '../components/DataTable'
import Wrapper from '../components/Wrapper'
class _SwitchPortList extends Component {
constructor(props) {
super(props)
this.state = {
fields: ['untagged_vlan_info', 'tagged_vlans_name'],
url: '/api/v1/network/switchports/?page_size=25',
name: 'switchports',
}
}
componentDidMount() {
const { url } = this.state
const { dispatch } = this.props
dispatch(fetchData(this.state.name, url))
dispatch(fetchOptions(this.state.name, url))
}
render() {
const { fields, url, name } = this.state
const { isDataFetching, isOptionsFetching, dispatch } = this.props
if (isDataFetching === false && isOptionsFetching === false) {
return (
<Wrapper title='SwitchPorts'>
<DataTable
{...this.props}
fields={fields}
url={url}
onPagination={next => dispatch(fetchData(name, `${next}&page_size=25`))}
/>
</Wrapper>
)
}
return <div />
}
}
const mapStateToProps = ({ data: { switchports, isDataFetching }, options: { switchportsOptions, isOptionsFetching } }) => ({
data: switchports,
options: switchportsOptions,
isDataFetching,
isOptionsFetching,
})
const SwitchPortList = withRouter(connect(mapStateToProps)(_SwitchPortList))
export { SwitchPortList }
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { postData, fetchData } from '../actions'
import VlanForm from '../components/VlanForm'
import Wrapper from '../components/Wrapper'
class VlanFormContainer extends Component {
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchData('natsTo', '/api/v1/network/vlans/'))
dispatch(fetchData('domains', '/api/v1/network/vlans/'))
dispatch(fetchData('owners', '/api/v1/dashboard/user/'))
}
genNatToOptions() {
const { natsTo } = this.props.data
if (natsTo === undefined) { return [] }
return natsTo.map(natTo => ({ key: natTo.url, text: natTo.name, value: natTo.url }))
}
genDomainOptions() {
const { domains } = this.props.data
if (domains === undefined) { return [] }
return domains.map(domain => ({ key: domain.url, text: domain.name, value: domain.url }))
}
genOwnerOptions() {
const { owners } = this.props.data
if (owners === undefined) { return [] }
return owners.map(owner => ({ key: owner.url, text: `${owner.full_name} (${owner.email})`, value: owner.url }))
}
render() {
const { handleSubmit } = this.props
return (
<Wrapper title='Vlan'>
<VlanForm
onSubmit={handleSubmit}
natToOptions={() => this.genNatToOptions()}
domainOptions={() => this.genDomainOptions()}
ownerOptions={() => this.genOwnerOptions()}
/>
</Wrapper>
)
}
}
const mapStateToProps = ({ data }) => ({ data })
const mapDispatchToProps = dispatch => ({
handleSubmit: data => dispatch(postData('/api/v1/network/vlans/', data)),
dispatch,
})
export default connect(mapStateToProps, mapDispatchToProps)(VlanFormContainer)
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { postData, fetchData } from '../actions'
import VlanGroupForm from '../components/VlanGroupForm'
import Wrapper from '../components/Wrapper'
class VlanGroupFormContainer extends Component {
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchData('owners', '/api/v1/dashboard/user/'))
dispatch(fetchData('vlans', '/api/v1/network/vlans/'))
}
genOwnerOptions() {
const { owners } = this.props.data
if (owners === undefined) { return [] }
return owners.map(owner => ({ key: owner.url, text: `${owner.full_name} (${owner.email})`, value: owner.url }))
}
genVlansOptions() {
const { vlans } = this.props.data
if (vlans === undefined) { return [] }
return vlans.map(vlan => ({ key: vlan.url, text: vlan.name, value: vlan.url }))
}
render() {
const { handleSubmit } = this.props
return (
<Wrapper title='VlanGroup'>
<VlanGroupForm
onSubmit={handleSubmit}
ownerOptions={() => this.genOwnerOptions()}
vlansOptions={() => this.genVlansOptions()}
/>
</Wrapper>
)
}
}
const mapStateToProps = ({ data }) => ({ data })
const mapDispatchToProps = dispatch => ({
handleSubmit: data => dispatch(postData('/api/v1/network/vlangroups/', data)),
dispatch,
})
// TODO: Add id parameter for handleSubmit
export default connect(mapStateToProps, mapDispatchToProps)(VlanGroupFormContainer)
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchData, fetchOptions } from '../actions'
import DataTable from '../components/DataTable'
import Wrapper from '../components/Wrapper'
class _VlanGroupList extends Component {
constructor(props) {
super(props)
this.state = {
fields: ['name', /* TODO: 'vlans', */ 'description', 'owner_name'],
url: '/api/v1/network/vlangroups/?page_size=25',
name: 'vlangroups',
}
}
componentDidMount() {
const { url } = this.state
const { dispatch } = this.props
dispatch(fetchData(this.state.name, url))
dispatch(fetchOptions(this.state.name, url))
}
render() {
const { fields, url, name } = this.state
const { isDataFetching, isOptionsFetching, dispatch } = this.props
if (isDataFetching === false && isOptionsFetching === false) {
return (
<Wrapper title='VlanGroups'>
<DataTable
{...this.props}
fields={fields}
url={url}
onPagination={next => dispatch(fetchData(name, `${next}&page_size=25`))}
/>
</Wrapper>
)
}
return <div />
}
}
const mapStateToProps = ({ data: { vlangroups, isDataFetching }, options: { vlangroupsOptions, isOptionsFetching } }) => ({
data: vlangroups,
options: vlangroupsOptions,
isDataFetching,
isOptionsFetching,
})
const VlanGroupList = withRouter(connect(mapStateToProps)(_VlanGroupList))
export { VlanGroupList }
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { fetchData, fetchOptions } from '../actions'
import DataTable from '../components/DataTable'
import Wrapper from '../components/Wrapper'
class _VlanList extends Component {
constructor(props) {
super(props)
this.state = {
fields: ['vid', 'name', 'network4', 'network6', 'domain_name'],
url: '/api/v1/network/vlans/?page_size=25',
name: 'vlans',
}
}
componentDidMount() {
const { url } = this.state
const { dispatch } = this.props
dispatch(fetchData(this.state.name, url))
dispatch(fetchOptions(this.state.name, url))
}
render() {
const { fields, url, name } = this.state
const { isDataFetching, isOptionsFetching, dispatch } = this.props
if (isDataFetching === false && isOptionsFetching === false) {
return (
<Wrapper title='Vlans'>
<DataTable
{...this.props}
fields={fields}
url={url}
onPagination={next => dispatch(fetchData(name, `${next}&page_size=25`))}
/>
</Wrapper>
)
}
return <div />
}
}
const mapStateToProps = ({ data: { vlans, isDataFetching }, options: { vlansOptions, isOptionsFetching } }) => ({
data: vlans,
options: vlansOptions,
isDataFetching,
isOptionsFetching,
})
const VlanList = withRouter(connect(mapStateToProps)(_VlanList))
export { VlanList }
export * from './HostList'
export * from './DomainList'
export * from './RecordList'
export * from './RuleList'
export * from './VlanList'
export * from './BlacklistList'
export * from './FirewallList'
export * from './SwitchPortList'
export * from './VlanGroupList'
export * from './HostGroupList'
import React from 'react'
import ReactDOM from 'react-dom'
import thunk from 'redux-thunk'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import { createStore, applyMiddleware } from 'redux'
import logger from 'redux-logger'
import { createStore, applyMiddleware } from 'redux'
import 'semantic-ui-css/semantic.min.css'
import App from './App'
import Root from './Root'
import reducer from './reducers'
let store = createStore(reducer, applyMiddleware(thunk))
ReactDOM.render(<Provider store={store}><BrowserRouter><App /></BrowserRouter></Provider>, document.getElementById('root'))
const store = createStore(reducer, applyMiddleware(thunk), applyMiddleware(logger))
ReactDOM.render(<Root store={store} />, document.getElementById('root'))
import { REQUEST_DATA, RECEIVE_DATA } from '../actions/'
const data = (state = {}, action) => {
switch (action.type) {
case REQUEST_DATA:
case RECEIVE_DATA:
return {
...state,
[action.payload.name]: action.payload.data,
isDataFetching: action.payload.isFetching,
}
default:
return state
}
}
export default data
import { combineReducers } from 'redux'
import { reducer as formReducer } from 'redux-form'
const reducer = combineReducers({})
import data from './data'
import options from './options'
const reducer = combineReducers({ data, options, form: formReducer })
export default reducer
import { REQUEST_OPTIONS, RECEIVE_OPTIONS } from '../actions/'
const options = (state = {}, action) => {
switch (action.type) {
case REQUEST_OPTIONS:
case RECEIVE_OPTIONS:
return {
...state,
[`${action.payload.name}Options`]: action.payload.options,
isOptionsFetching: action.payload.isFetching,
}
default:
return state
}
}
export default options
......@@ -1800,7 +1800,7 @@ debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.6.0, debug@^2.6.6, debug@^2.6.
dependencies:
ms "2.0.0"
debug@^3.1.0:
debug@^3.0.1, debug@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies:
......@@ -1810,6 +1810,10 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
deep-diff@^0.3.5:
version "0.3.8"
resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84"
deep-equal@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
......@@ -2116,6 +2120,10 @@ es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14:
es6-iterator "~2.0.1"
es6-symbol "~3.1.1"
es6-error@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.0.2.tgz#eec5c726eacef51b7f6b73c20db6e1b13b069c98"
es6-iterator@^2.0.1, es6-iterator@~2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
......@@ -2193,6 +2201,18 @@ escope@^3.6.0:
esrecurse "^4.1.0"
estraverse "^4.1.1"
eslint-config-airbnb-base@^12.1.0:
version "12.1.0"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz#386441e54a12ccd957b0a92564a4bafebd747944"
dependencies:
eslint-restricted-globals "^0.1.1"
eslint-config-airbnb@^16.1.0:
version "16.1.0"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-16.1.0.tgz#2546bfb02cc9fe92284bf1723ccf2e87bc45ca46"
dependencies:
eslint-config-airbnb-base "^12.1.0"
eslint-config-react-app@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-2.0.1.tgz#fd0503da01ae608f0c6ae8861de084975142230e"
......@@ -2242,6 +2262,21 @@ eslint-plugin-import@2.7.0:
minimatch "^3.0.3"
read-pkg-up "^2.0.0"
eslint-plugin-import@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz#fa1b6ef31fcb3c501c09859c1b86f1fc5b986894"
dependencies:
builtin-modules "^1.1.1"
contains-path "^0.1.0"
debug "^2.6.8"
doctrine "1.5.0"
eslint-import-resolver-node "^0.3.1"
eslint-module-utils "^2.1.1"
has "^1.0.1"
lodash.cond "^4.3.0"
minimatch "^3.0.3"
read-pkg-up "^2.0.0"
eslint-plugin-jsx-a11y@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-5.1.1.tgz#5c96bb5186ca14e94db1095ff59b3e2bd94069b1"
......@@ -2254,6 +2289,18 @@ eslint-plugin-jsx-a11y@5.1.1:
emoji-regex "^6.1.0"
jsx-ast-utils "^1.4.0"
eslint-plugin-jsx-a11y@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.2.tgz#659277a758b036c305a7e4a13057c301cd3be73f"
dependencies:
aria-query "^0.7.0"
array-includes "^3.0.3"
ast-types-flow "0.0.7"
axobject-query "^0.1.0"
damerau-levenshtein "^1.0.0"
emoji-regex "^6.1.0"
jsx-ast-utils "^1.4.0"
eslint-plugin-react@7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.1.0.tgz#27770acf39f5fd49cd0af4083ce58104eb390d4c"
......@@ -2262,6 +2309,19 @@ eslint-plugin-react@7.1.0:
has "^1.0.1"
jsx-ast-utils "^1.4.1"
eslint-plugin-react@^7.4.0:
version "7.4.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.4.0.tgz#300a95861b9729c087d362dd64abcc351a74364a"
dependencies:
doctrine "^2.0.0"
has "^1.0.1"
jsx-ast-utils "^2.0.0"
prop-types "^15.5.10"
eslint-restricted-globals@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7"
eslint-scope@^3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8"
......@@ -2310,7 +2370,49 @@ eslint@4.4.1:
table "^4.0.1"
text-table "~0.2.0"
espree@^3.5.0:
eslint@^4.10.0:
version "4.10.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.10.0.tgz#f25d0d7955c81968c2309aa5c9a229e045176bb7"
dependencies:
ajv "^5.2.0"
babel-code-frame "^6.22.0"
chalk "^2.1.0"
concat-stream "^1.6.0"
cross-spawn "^5.1.0"
debug "^3.0.1"
doctrine "^2.0.0"
eslint-scope "^3.7.1"
espree "^3.5.1"
esquery "^1.0.0"
estraverse "^4.2.0"
esutils "^2.0.2"
file-entry-cache "^2.0.0"
functional-red-black-tree "^1.0.1"
glob "^7.1.2"
globals "^9.17.0"
ignore "^3.3.3"
imurmurhash "^0.1.4"
inquirer "^3.0.6"
is-resolvable "^1.0.0"
js-yaml "^3.9.1"
json-stable-stringify "^1.0.1"
levn "^0.3.0"
lodash "^4.17.4"
minimatch "^3.0.2"
mkdirp "^0.5.1"
natural-compare "^1.4.0"
optionator "^0.8.2"
path-is-inside "^1.0.2"
pluralize "^7.0.0"
progress "^2.0.0"
require-uncached "^1.0.3"
semver "^5.3.0"
strip-ansi "^4.0.0"
strip-json-comments "~2.0.1"
table "^4.0.1"
text-table "~0.2.0"
espree@^3.5.0, espree@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.1.tgz#0c988b8ab46db53100a1954ae4ba995ddd27d87e"
dependencies:
......@@ -3012,7 +3114,7 @@ hoek@4.x.x:
version "4.2.0"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d"
hoist-non-react-statics@^2.2.1, hoist-non-react-statics@^2.3.0:
hoist-non-react-statics@^2.2.1, hoist-non-react-statics@^2.3.0, hoist-non-react-statics@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0"
......@@ -3906,6 +4008,12 @@ jsx-ast-utils@^1.4.0, jsx-ast-utils@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1"
jsx-ast-utils@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f"
dependencies:
array-includes "^3.0.3"
kind-of@^3.0.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
......@@ -4009,7 +4117,7 @@ locate-path@^2.0.0:
p-locate "^2.0.0"
path-exists "^3.0.0"
lodash-es@^4.2.0, lodash-es@^4.2.1:
lodash-es@^4.17.3, lodash-es@^4.2.0, lodash-es@^4.2.1:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
......@@ -4254,6 +4362,10 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi
dependencies:
minimist "0.0.8"
moment@^2.19.2:
version "2.19.2"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.2.tgz#8a7f774c95a64550b4c7ebd496683908f9419dbe"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
......@@ -4728,6 +4840,10 @@ pluralize@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-4.0.0.tgz#59b708c1c0190a2f692f1c7618c446b052fd1762"
pluralize@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
portfinder@^1.0.9:
version "1.0.13"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9"
......@@ -5078,7 +5194,7 @@ promise@^7.1.1:
dependencies:
asap "~2.0.3"
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.6.0:
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.9, prop-types@^15.6.0:
version "15.6.0"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
dependencies:
......@@ -5413,6 +5529,25 @@ reduce-function-call@^1.0.1:
dependencies:
balanced-match "^0.4.2"
redux-form@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/redux-form/-/redux-form-7.1.2.tgz#6b0f25c57fd8130a05ce00f6435fe1b051f402af"
dependencies:
deep-equal "^1.0.1"
es6-error "^4.0.0"
hoist-non-react-statics "^2.3.1"
invariant "^2.2.2"
is-promise "^2.1.0"
lodash "^4.17.3"
lodash-es "^4.17.3"
prop-types "^15.5.9"
redux-logger@^3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-3.0.6.tgz#f7555966f3098f3c88604c449cf0baf5778274bf"
dependencies:
deep-diff "^0.3.5"
redux-thunk@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5"
......@@ -6330,6 +6465,10 @@ uid-number@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
underscore@^1.8.3:
version "1.8.3"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022"
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment