mirror of
https://github.com/yldio/copilot.git
synced 2024-11-14 15:20:06 +02:00
feat(my-joyent): fetch packages and implement filters
This commit is contained in:
parent
3b427871cf
commit
884db125e0
@ -7,7 +7,8 @@
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"lint": "eslint . --fix",
|
||||
"lint-ci": "eslint . --format junit --output-file $CIRCLE_TEST_REPORTS/lint/cloudapi-gql.xml",
|
||||
"lint-ci":
|
||||
"eslint . --format junit --output-file $CIRCLE_TEST_REPORTS/lint/cloudapi-gql.xml",
|
||||
"test": "echo 0",
|
||||
"test-ci": "echo 0",
|
||||
"start": "node src/index.js",
|
||||
@ -15,6 +16,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bunyan": "^1.8.12",
|
||||
"cors": "^2.8.4",
|
||||
"dotenv": "^4.0.0",
|
||||
"express": "^4.15.4",
|
||||
"express-graphql": "^0.6.11",
|
||||
|
@ -1,7 +1,11 @@
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(cors());
|
||||
app.options('*', cors());
|
||||
|
||||
app.use('/graphql', require('./endpoint'));
|
||||
|
||||
const server = app.listen(4000, err => {
|
||||
|
0
packages/my-joyent/.yarnclean
Normal file
0
packages/my-joyent/.yarnclean
Normal file
@ -6,7 +6,7 @@
|
||||
"main": "build/",
|
||||
"scripts": {
|
||||
"dev":
|
||||
"REACT_APP_GQL_PORT=3000 PORT=3069 REACT_APP_GQL_PROTOCOL=http react-scripts start",
|
||||
"REACT_APP_GQL_PORT=4000 PORT=3069 REACT_APP_GQL_PROTOCOL=http react-scripts start",
|
||||
"start": "PORT=3069 react-scripts start",
|
||||
"build": "NODE_ENV=production react-scripts build",
|
||||
"lint:css": "stylelint './src/**/*.js'",
|
||||
@ -18,7 +18,8 @@
|
||||
"lint-ci": "redrun -p lint-ci:*",
|
||||
"test": "NODE_ENV=test ./test/run --env=jsdom",
|
||||
"test-ci":
|
||||
"echo 0 `# NODE_ENV=test JEST_JUNIT_OUTPUT=$CIRCLE_TEST_REPORTS/test/cp-frontend.xml ./test/run --env=jsdom --coverage --coverageDirectory=$CIRCLE_ARTIFACTS/cp-frontend --testResultsProcessor=$(node -e \"console.log(require.resolve('jest-junit'))\")`"
|
||||
"echo 0 `# NODE_ENV=test JEST_JUNIT_OUTPUT=$CIRCLE_TEST_REPORTS/test/cp-frontend.xml ./test/run --env=jsdom --coverage --coverageDirectory=$CIRCLE_ARTIFACTS/cp-frontend --testResultsProcessor=$(node -e \"console.log(require.resolve('jest-junit'))\")`",
|
||||
"prepublish": "node scripts/postinstall"
|
||||
},
|
||||
"dependencies": {
|
||||
"apollo": "^0.2.2",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import 'jest-styled-components';
|
||||
|
||||
import { Router, FiltersMock } from '@mocks/';
|
||||
import Filters from '../filters';
|
||||
|
||||
it('renders <Filters /> without throwing', () => {
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Router>
|
||||
<Filters filters={FiltersMock} />
|
||||
</Router>
|
||||
)
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
72
packages/my-joyent/src/components/filters/filters.js
Normal file
72
packages/my-joyent/src/components/filters/filters.js
Normal file
@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
import { Col } from 'react-styled-flexboxgrid';
|
||||
import styled from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
import { Slider, FormLabel } from 'joyent-ui-toolkit';
|
||||
|
||||
const FilterWrapper = styled.section`
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
> div {
|
||||
flex-grow: 1;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: ${remcalc(36)};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Filters = ({
|
||||
filters: { cpu, cost, ram, disk },
|
||||
ramSliderChange,
|
||||
cpuSliderChange,
|
||||
diskSliderChange,
|
||||
costSliderChange
|
||||
}) => {
|
||||
return (
|
||||
<Col xs={12}>
|
||||
<FormLabel>Choose a package</FormLabel>
|
||||
<FilterWrapper>
|
||||
<Slider
|
||||
minValue={ram.min}
|
||||
maxValue={ram.max}
|
||||
step={0.256}
|
||||
value={ram}
|
||||
onChangeComplete={value => ramSliderChange(value)}
|
||||
>
|
||||
GB RAM
|
||||
</Slider>
|
||||
<Slider
|
||||
minValue={cpu.min}
|
||||
maxValue={cpu.max}
|
||||
step={0.25}
|
||||
value={cpu}
|
||||
onChangeComplete={value => cpuSliderChange(value)}
|
||||
>
|
||||
vCPUs
|
||||
</Slider>
|
||||
<Slider
|
||||
minValue={disk.min}
|
||||
maxValue={disk.max}
|
||||
step={0.01}
|
||||
value={disk}
|
||||
onChangeComplete={value => diskSliderChange(value)}
|
||||
>
|
||||
TB Disk
|
||||
</Slider>
|
||||
<Slider
|
||||
minValue={cost.min}
|
||||
maxValue={cost.max}
|
||||
step={0.02}
|
||||
value={cost}
|
||||
onChangeComplete={value => costSliderChange(value)}
|
||||
>
|
||||
$/hr
|
||||
</Slider>
|
||||
</FilterWrapper>
|
||||
</Col>
|
||||
);
|
||||
};
|
||||
|
||||
export default Filters;
|
1
packages/my-joyent/src/components/filters/index.js
Normal file
1
packages/my-joyent/src/components/filters/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default as Filters } from './filters';
|
File diff suppressed because it is too large
Load Diff
@ -3,19 +3,19 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import ShallowRenderer from 'react-test-renderer/shallow';
|
||||
import 'jest-styled-components';
|
||||
|
||||
import { Router } from '@mocks/';
|
||||
import { Router, FiltersMock } from '@mocks/';
|
||||
import Home from '../home';
|
||||
|
||||
it('renders <Home /> without throwing', () => {
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Router>
|
||||
<Home />
|
||||
</Router>
|
||||
)
|
||||
.toJSON();
|
||||
const renderer = new ShallowRenderer();
|
||||
renderer.render(
|
||||
<Router>
|
||||
<Home filters={FiltersMock} />
|
||||
</Router>
|
||||
);
|
||||
const tree = renderer.getRenderOutput();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Row } from 'react-styled-flexboxgrid';
|
||||
import { SectionNav } from '@components/navigation';
|
||||
import { Filters } from '@components/filters';
|
||||
import PackagesHOC from '@containers/packages';
|
||||
import { Message, Breadcrumb, BreadcrumbItem, Anchor } from 'joyent-ui-toolkit';
|
||||
|
||||
class Home extends Component {
|
||||
@ -12,6 +14,7 @@ class Home extends Component {
|
||||
};
|
||||
|
||||
this.closeMessage = this.closeMessage.bind(this);
|
||||
this.changeValue = this.changeValue.bind(this);
|
||||
}
|
||||
|
||||
closeMessage() {
|
||||
@ -20,8 +23,18 @@ class Home extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
changeValue(key, value) {
|
||||
const filters = this.props.filters;
|
||||
this.props.onFilterChange({
|
||||
...filters,
|
||||
[key]: value
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const _msg = this.state.showMessage ? (
|
||||
const { showMessage } = this.state;
|
||||
const { filters } = this.props;
|
||||
const _msg = showMessage ? (
|
||||
<Message
|
||||
title="Choosing deployement data center"
|
||||
onCloseClick={this.closeMessage}
|
||||
@ -33,6 +46,7 @@ class Home extends Component {
|
||||
</p>
|
||||
</Message>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<main>
|
||||
<SectionNav />
|
||||
@ -41,6 +55,18 @@ class Home extends Component {
|
||||
<BreadcrumbItem>Create Instance</BreadcrumbItem>
|
||||
</Breadcrumb>
|
||||
<Row>{_msg}</Row>
|
||||
<Row>
|
||||
<Filters
|
||||
filters={filters}
|
||||
ramSliderChange={value => this.changeValue('ram', value)}
|
||||
cpuSliderChange={value => this.changeValue('cpu', value)}
|
||||
diskSliderChange={value => this.changeValue('disk', value)}
|
||||
costSliderChange={value => this.changeValue('cost', value)}
|
||||
/>
|
||||
</Row>
|
||||
<Row>
|
||||
<PackagesHOC />
|
||||
</Row>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import 'jest-styled-components';
|
||||
|
||||
import { Router, PackagesMock, FiltersMock } from '@mocks/';
|
||||
import { Packages } from '../';
|
||||
|
||||
it('renders <Packages /> without throwing', () => {
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Router>
|
||||
<Packages packages={PackagesMock} filters={FiltersMock} />
|
||||
</Router>
|
||||
)
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
1
packages/my-joyent/src/components/packages/index.js
Normal file
1
packages/my-joyent/src/components/packages/index.js
Normal file
@ -0,0 +1 @@
|
||||
export { default as Packages } from './list';
|
80
packages/my-joyent/src/components/packages/list.js
Normal file
80
packages/my-joyent/src/components/packages/list.js
Normal file
@ -0,0 +1,80 @@
|
||||
import React, { Component } from 'react';
|
||||
import remcalc from 'remcalc';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
Card,
|
||||
CardSubTitle,
|
||||
CardTitle,
|
||||
CardView,
|
||||
CardFooter,
|
||||
CardMeta
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
const ListStyled = styled.ul`
|
||||
display: flex;
|
||||
width: 100%;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin-top: ${remcalc(36)};
|
||||
`;
|
||||
class Packages extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { filters: { ram, cpu, cost, disk }, packages } = props;
|
||||
this.state = {
|
||||
ram,
|
||||
cpu,
|
||||
cost,
|
||||
disk,
|
||||
packages
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { filters: { ram, cpu, cost, disk }, packages } = nextProps;
|
||||
this.setState({
|
||||
ram,
|
||||
cpu,
|
||||
cost,
|
||||
disk,
|
||||
packages: packages
|
||||
.filter(pack => pack.memory >= ram.min && pack.memory <= ram.max)
|
||||
.filter(
|
||||
pack => pack.disk / 1000 >= disk.min && pack.disk / 1000 <= disk.max
|
||||
)
|
||||
.filter(pack => pack.vcpus >= cpu.min && pack.vcpus <= cpu.max)
|
||||
.filter(pack => pack.price >= cost.min && pack.price <= cost.max)
|
||||
});
|
||||
}
|
||||
|
||||
_packages() {
|
||||
return (
|
||||
<ListStyled>
|
||||
{this.state.packages.map(pack => (
|
||||
<li>
|
||||
<Card transparent>
|
||||
<CardView>
|
||||
<CardMeta>
|
||||
<CardTitle>${pack.price} per hour</CardTitle>
|
||||
<CardSubTitle>{pack.memory} GB RAM</CardSubTitle>
|
||||
<CardSubTitle>{pack.vcpus} vCPUs</CardSubTitle>
|
||||
<CardSubTitle>{pack.disk / 100} TB disk</CardSubTitle>
|
||||
<CardSubTitle>SSD</CardSubTitle>
|
||||
|
||||
<CardFooter>{pack.group}</CardFooter>
|
||||
</CardMeta>
|
||||
</CardView>
|
||||
</Card>
|
||||
</li>
|
||||
))}
|
||||
</ListStyled>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return this._packages();
|
||||
}
|
||||
}
|
||||
|
||||
export default Packages;
|
File diff suppressed because it is too large
Load Diff
@ -7,13 +7,15 @@ import renderer from 'react-test-renderer';
|
||||
import 'jest-styled-components';
|
||||
|
||||
import HomeHOC from '../';
|
||||
import { Router } from '@mocks/';
|
||||
import { Router, Store } from '@mocks/';
|
||||
|
||||
it('renders <HomeHOC /> without throwing', () => {
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Router>
|
||||
<HomeHOC />
|
||||
<Store>
|
||||
<HomeHOC />
|
||||
</Store>
|
||||
</Router>
|
||||
)
|
||||
.toJSON();
|
||||
|
@ -1,11 +1,27 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import changeFilters from '../../state/actions';
|
||||
import { LayoutContainer } from '@components/layout';
|
||||
import { Home } from '@components/home';
|
||||
|
||||
const HomeHOC = () => (
|
||||
const HomeHOC = ({ filters, onFilterChange }) => (
|
||||
<LayoutContainer>
|
||||
<Home />
|
||||
<Home filters={filters} onFilterChange={onFilterChange} />
|
||||
</LayoutContainer>
|
||||
);
|
||||
|
||||
export default HomeHOC;
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
filters: state.filters
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
onFilterChange: filters => {
|
||||
dispatch(changeFilters(filters));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(HomeHOC);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import 'jest-styled-components';
|
||||
|
||||
import PackagesHOC from '../';
|
||||
import { Router, Store } from '@mocks/';
|
||||
|
||||
it('renders <PackagesHOC /> without throwing', () => {
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Router>
|
||||
<Store>
|
||||
<PackagesHOC />
|
||||
</Store>
|
||||
</Router>
|
||||
)
|
||||
.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
25
packages/my-joyent/src/containers/packages/index.js
Normal file
25
packages/my-joyent/src/containers/packages/index.js
Normal file
@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
// import { graphql } from 'react-apollo';
|
||||
import { Packages } from '@components/packages';
|
||||
// import packagesQuery from '@graphql/packages.gql';
|
||||
import data from '../../data/packages';
|
||||
|
||||
const PackagesHOC = ({ packages, filters }) => (
|
||||
<Packages packages={data} filters={filters} />
|
||||
);
|
||||
|
||||
// const PackagesHOCWithData = graphql(packagesQuery, {
|
||||
// props: ({ data: { packages = [], loading = true } }) => ({
|
||||
// packages,
|
||||
// loading
|
||||
// })
|
||||
// })(PackagesHOC);
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
filters: state.filters
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(PackagesHOC);
|
146
packages/my-joyent/src/data/packages.json
Normal file
146
packages/my-joyent/src/data/packages.json
Normal file
@ -0,0 +1,146 @@
|
||||
[
|
||||
{
|
||||
"name": "High CPU 0.25",
|
||||
"vcpus": 0.25,
|
||||
"memory": 0.256,
|
||||
"disk": 10,
|
||||
"group": "Compute Optimized",
|
||||
"price": "0.016"
|
||||
},
|
||||
{
|
||||
"name": "High CPU 0.75",
|
||||
"vcpus": 0.5,
|
||||
"memory": 0.768,
|
||||
"disk": 25,
|
||||
"group": "Compute Optimized",
|
||||
"price": "0.033"
|
||||
},
|
||||
{
|
||||
"name": "High CPU 1.75",
|
||||
"vcpus": 1,
|
||||
"memory": 1.8,
|
||||
"disk": 50,
|
||||
"group": "Compute Optimized",
|
||||
"price": "0.066"
|
||||
},
|
||||
{
|
||||
"name": "High CPU 3.75",
|
||||
"vcpus": 2,
|
||||
"memory": 3.8,
|
||||
"disk": 100,
|
||||
"group": "Compute Optimized",
|
||||
"price": "0.131"
|
||||
},
|
||||
{
|
||||
"name": "High CPU 7.75",
|
||||
"vcpus": 4,
|
||||
"memory": 7.8,
|
||||
"disk": 200,
|
||||
"group": "Compute Optimized",
|
||||
"price": "0.263"
|
||||
},
|
||||
{
|
||||
"name": "High CPU 15.75",
|
||||
"vcpus": 8,
|
||||
"memory": 15.8,
|
||||
"disk": 400,
|
||||
"group": "Compute Optimized",
|
||||
"price": "0.525"
|
||||
},
|
||||
{
|
||||
"name": "General 3.75",
|
||||
"vcpus": 1,
|
||||
"memory": 3.8,
|
||||
"disk": 50,
|
||||
"group": "General Purpose",
|
||||
"price": "0.084"
|
||||
},
|
||||
{
|
||||
"name": "General 7.75",
|
||||
"vcpus": 2,
|
||||
"memory": 7.8,
|
||||
"disk": 100,
|
||||
"group": "General Purpose",
|
||||
"price": "0.166"
|
||||
},
|
||||
{
|
||||
"name": "General 15.75",
|
||||
"vcpus": 4,
|
||||
"memory": 15.8,
|
||||
"disk": 200,
|
||||
"group": "General Purpose",
|
||||
"price": "0.333"
|
||||
},
|
||||
{
|
||||
"name": "General 31.75",
|
||||
"vcpus": 8,
|
||||
"memory": 31.8,
|
||||
"disk": 400,
|
||||
"group": "General Purpose",
|
||||
"price": "0.665"
|
||||
},
|
||||
{
|
||||
"name": "High RAM 15.75",
|
||||
"vcpus": 2,
|
||||
"memory": 15.8,
|
||||
"disk": 100,
|
||||
"group": "Memory Optimized",
|
||||
"price": "0.259"
|
||||
},
|
||||
{
|
||||
"name": "High RAM 31.75",
|
||||
"vcpus": 4,
|
||||
"memory": 31.8,
|
||||
"disk": 200,
|
||||
"group": "Memory Optimized",
|
||||
"price": "0.52"
|
||||
},
|
||||
{
|
||||
"name": "High RAM 63.75",
|
||||
"vcpus": 8,
|
||||
"memory": 63.8,
|
||||
"disk": 400,
|
||||
"group": "Memory Optimized",
|
||||
"price": "1.039"
|
||||
},
|
||||
{
|
||||
"name": "Fast Disk 31.75",
|
||||
"vcpus": 4,
|
||||
"memory": 31.8,
|
||||
"disk": 800,
|
||||
"group": "Storage Optimized",
|
||||
"price": "1.066"
|
||||
},
|
||||
{
|
||||
"name": "Fast Disk 63.75",
|
||||
"vcpus": 8,
|
||||
"memory": 63.8,
|
||||
"disk": 1600,
|
||||
"group": "Storage Optimized",
|
||||
"price": "2.31"
|
||||
},
|
||||
{
|
||||
"name": "Big Disk 15.75",
|
||||
"vcpus": 2,
|
||||
"memory": 15.8,
|
||||
"disk": 1200,
|
||||
"group": "Storage Optimized",
|
||||
"price": "0.413"
|
||||
},
|
||||
{
|
||||
"name": "Big Disk 31.75",
|
||||
"vcpus": 4,
|
||||
"memory": 31.8,
|
||||
"disk": 2400,
|
||||
"group": "Storage Optimized",
|
||||
"price": "0.825"
|
||||
},
|
||||
{
|
||||
"name": "Big Disk 63.75",
|
||||
"vcpus": 8,
|
||||
"memory": 63.8,
|
||||
"disk": 4900,
|
||||
"group": "Storage Optimized",
|
||||
"price": "1.75"
|
||||
}
|
||||
]
|
5
packages/my-joyent/src/graphql/data-centers.gql
Normal file
5
packages/my-joyent/src/graphql/data-centers.gql
Normal file
@ -0,0 +1,5 @@
|
||||
query Portal {
|
||||
datacenters {
|
||||
name
|
||||
}
|
||||
}
|
10
packages/my-joyent/src/graphql/packages.gql
Normal file
10
packages/my-joyent/src/graphql/packages.gql
Normal file
@ -0,0 +1,10 @@
|
||||
query Portal {
|
||||
packages {
|
||||
name
|
||||
vcpus
|
||||
memory
|
||||
disk
|
||||
version
|
||||
group
|
||||
}
|
||||
}
|
8
packages/my-joyent/src/state/actions.js
Normal file
8
packages/my-joyent/src/state/actions.js
Normal file
@ -0,0 +1,8 @@
|
||||
const changeFilters = filters => {
|
||||
return {
|
||||
type: 'CHANGE_FILTERS',
|
||||
filters
|
||||
};
|
||||
};
|
||||
|
||||
export default changeFilters;
|
13
packages/my-joyent/src/state/filterReducer.js
Normal file
13
packages/my-joyent/src/state/filterReducer.js
Normal file
@ -0,0 +1,13 @@
|
||||
const filterReducer = (state = [], action) => {
|
||||
switch (action.type) {
|
||||
case 'CHANGE_FILTERS':
|
||||
return {
|
||||
...state,
|
||||
...action.filters
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default filterReducer;
|
@ -1,3 +1,10 @@
|
||||
const state = {};
|
||||
const state = {
|
||||
filters: {
|
||||
cpu: { min: 0.25, max: 8 },
|
||||
cost: { min: 0.016, max: 2.131 },
|
||||
ram: { min: 0.256, max: 63.8 },
|
||||
disk: { min: 0.01, max: 4.9 }
|
||||
}
|
||||
};
|
||||
|
||||
export default state;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
|
||||
import { reducer as formReducer } from 'redux-form';
|
||||
import { ApolloClient, createNetworkInterface } from 'react-apollo';
|
||||
import filterReducer from './filterReducer';
|
||||
import state from './state';
|
||||
|
||||
const GLOBAL =
|
||||
@ -37,14 +38,15 @@ export const client = new ApolloClient({
|
||||
return `${o.__typename}:${id}`;
|
||||
},
|
||||
networkInterface: createNetworkInterface({
|
||||
uri: `${GQL_PROTOCOL}://${GQL_HOSTNAME}:${GQL_PORT}/api/graphql`
|
||||
uri: `${GQL_PROTOCOL}://${GQL_HOSTNAME}:${GQL_PORT}/graphql`
|
||||
})
|
||||
});
|
||||
|
||||
export const store = createStore(
|
||||
combineReducers({
|
||||
apollo: client.reducer(),
|
||||
form: formReducer
|
||||
form: formReducer,
|
||||
filters: filterReducer
|
||||
}),
|
||||
state, // Initial state
|
||||
compose(
|
||||
|
18
packages/my-joyent/test/mocks/filters.js
Normal file
18
packages/my-joyent/test/mocks/filters.js
Normal file
@ -0,0 +1,18 @@
|
||||
export default {
|
||||
cpu: {
|
||||
min: 0.25,
|
||||
max: 3.25
|
||||
},
|
||||
cost: {
|
||||
min: 0.016,
|
||||
max: 0.525
|
||||
},
|
||||
ram: {
|
||||
min: 0.256,
|
||||
max: 50.688
|
||||
},
|
||||
disk: {
|
||||
min: 0.01,
|
||||
max: 107.26
|
||||
}
|
||||
};
|
@ -1,3 +1,5 @@
|
||||
export { default as Router } from './router';
|
||||
export { default as Store } from './store';
|
||||
export { default as PackagesMock } from './packages';
|
||||
export { default as FiltersMock } from './filters';
|
||||
export { default as Theme } from './theme';
|
||||
|
50
packages/my-joyent/test/mocks/packages.js
Normal file
50
packages/my-joyent/test/mocks/packages.js
Normal file
@ -0,0 +1,50 @@
|
||||
export default [
|
||||
{
|
||||
name: 'High CPU 0.25',
|
||||
vcpus: 0.25,
|
||||
memory: 0.256,
|
||||
disk: 10,
|
||||
group: 'Compute Optimized',
|
||||
price: '0.016'
|
||||
},
|
||||
{
|
||||
name: 'High CPU 0.75',
|
||||
vcpus: 0.5,
|
||||
memory: 0.768,
|
||||
disk: 25,
|
||||
group: 'Compute Optimized',
|
||||
price: '0.033'
|
||||
},
|
||||
{
|
||||
name: 'High CPU 1.75',
|
||||
vcpus: 1,
|
||||
memory: 1.8,
|
||||
disk: 50,
|
||||
group: 'Compute Optimized',
|
||||
price: '0.066'
|
||||
},
|
||||
{
|
||||
name: 'High CPU 3.75',
|
||||
vcpus: 2,
|
||||
memory: 3.8,
|
||||
disk: 100,
|
||||
group: 'Compute Optimized',
|
||||
price: '0.131'
|
||||
},
|
||||
{
|
||||
name: 'High CPU 7.75',
|
||||
vcpus: 4,
|
||||
memory: 7.8,
|
||||
disk: 200,
|
||||
group: 'Compute Optimized',
|
||||
price: '0.263'
|
||||
},
|
||||
{
|
||||
name: 'High CPU 15.75',
|
||||
vcpus: 8,
|
||||
memory: 15.8,
|
||||
disk: 400,
|
||||
group: 'Compute Optimized',
|
||||
price: '0.525'
|
||||
}
|
||||
];
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": "joyent-portal",
|
||||
"rules": {
|
||||
"new-cap": 0
|
||||
"new-cap": 0,
|
||||
"jsx-a11y/href-no-hash": 0
|
||||
}
|
||||
}
|
||||
|
0
packages/ui-toolkit/.yarnclean
Normal file
0
packages/ui-toolkit/.yarnclean
Normal file
@ -10,16 +10,22 @@
|
||||
"lint:css": "echo 0",
|
||||
"lint-ci:css": "echo 0",
|
||||
"lint:js": "eslint . --fix",
|
||||
"lint-ci:js": "eslint . --format junit --output-file $CIRCLE_TEST_REPORTS/lint/ui-toolkit.xml",
|
||||
"lint-ci:js":
|
||||
"eslint . --format junit --output-file $CIRCLE_TEST_REPORTS/lint/ui-toolkit.xml",
|
||||
"lint": "redrun -s lint:*",
|
||||
"lint-ci": "redrun -s lint-ci:*",
|
||||
"test": "echo 0",
|
||||
"test-ci": "echo 0",
|
||||
"copy-fonts": "rm -rf dist; mkdir -p dist/es/typography; mkdir -p dist/umd/typography; cp -r src/typography/libre-franklin dist/es/typography; cp -r src/typography/libre-franklin dist/umd/typography",
|
||||
"compile-watch:es": "NODE_ENV=development babel src --out-dir dist/es --source-maps inline --watch",
|
||||
"compile:es": "NODE_ENV=development babel src --out-dir dist/es --source-maps inline",
|
||||
"compile:umd": "cross-env NODE_ENV=test babel src --out-dir dist/umd --source-maps inline",
|
||||
"compile-watch:umd": "cross-env NODE_ENV=test babel src --out-dir dist/umd --source-maps inline --watch",
|
||||
"copy-fonts":
|
||||
"rm -rf dist; mkdir -p dist/es/typography; mkdir -p dist/umd/typography; cp -r src/typography/libre-franklin dist/es/typography; cp -r src/typography/libre-franklin dist/umd/typography",
|
||||
"compile-watch:es":
|
||||
"NODE_ENV=development babel src --out-dir dist/es --source-maps inline --watch",
|
||||
"compile:es":
|
||||
"NODE_ENV=development babel src --out-dir dist/es --source-maps inline",
|
||||
"compile:umd":
|
||||
"cross-env NODE_ENV=test babel src --out-dir dist/umd --source-maps inline",
|
||||
"compile-watch:umd":
|
||||
"cross-env NODE_ENV=test babel src --out-dir dist/umd --source-maps inline --watch",
|
||||
"compile": "redrun -p compile:*",
|
||||
"watch": "redrun copy-fonts && redrun -p compile-watch:*",
|
||||
"styleguide:build": "cross-env NODE_ENV=production styleguidist build",
|
||||
@ -47,6 +53,7 @@
|
||||
"polished": "^1.6.1",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-broadcast": "^0.1.2",
|
||||
"react-input-range": "^1.2.1",
|
||||
"react-styled-flexboxgrid": "^2.0.3",
|
||||
"redrun": "^5.9.16",
|
||||
"reduce-css-calc": "^2.0.5",
|
||||
@ -81,7 +88,8 @@
|
||||
"stylelint": "^8.0.0",
|
||||
"stylelint-config-primer": "^2.0.1",
|
||||
"stylelint-config-standard": "^17.0.0",
|
||||
"stylelint-processor-styled-components": "styled-components/stylelint-processor-styled-components#2a33b5f",
|
||||
"stylelint-processor-styled-components":
|
||||
"styled-components/stylelint-processor-styled-components#2a33b5f",
|
||||
"svgo": "^0.7.2",
|
||||
"tinycolor2": "^1.4.1",
|
||||
"title-case": "^2.1.1",
|
||||
|
@ -35,6 +35,16 @@ const StyledCard = Row.extend`
|
||||
box-shadow: none;
|
||||
`};
|
||||
|
||||
${is('transparent')`
|
||||
border-radius: ${remcalc(4)}
|
||||
background:
|
||||
border: 1px solid ${props => props.theme.grey};
|
||||
background: ${props => props.theme.background};
|
||||
box-shadow: 0px 2px 0px rgba(0, 0, 0, 0.05);
|
||||
min-height: ${remcalc(185)};
|
||||
min-width: 200px;
|
||||
`};
|
||||
|
||||
${is('stacked')`
|
||||
${paperEffect}
|
||||
`};
|
||||
@ -85,7 +95,8 @@ Card.propTypes = {
|
||||
collapsed: PropTypes.bool,
|
||||
headed: PropTypes.bool,
|
||||
flat: PropTypes.bool,
|
||||
stacked: PropTypes.bool
|
||||
stacked: PropTypes.bool,
|
||||
transparent: PropTypes.bool
|
||||
};
|
||||
|
||||
export default Baseline(Card);
|
||||
|
44
packages/ui-toolkit/src/card/footer.js
Normal file
44
packages/ui-toolkit/src/card/footer.js
Normal file
@ -0,0 +1,44 @@
|
||||
import { Subscriber } from 'react-broadcast';
|
||||
import styled from 'styled-components';
|
||||
import Baseline from '../baseline';
|
||||
import typography from '../typography';
|
||||
import remcalc from 'remcalc';
|
||||
import PropTypes from 'prop-types';
|
||||
import Title from './title';
|
||||
import React from 'react';
|
||||
|
||||
const StyledTitle = Title.extend`
|
||||
${typography.fontFamily};
|
||||
${typography.normal};
|
||||
|
||||
flex-grow: 1;
|
||||
flex-basis: ${remcalc(90)};
|
||||
`;
|
||||
|
||||
const Span = styled.span`
|
||||
display: inline-block;
|
||||
flex-direction: column;
|
||||
|
||||
${typography.fontFamily};
|
||||
${typography.normal};
|
||||
font-size: ${remcalc(13)};
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
|
||||
color: rgba(73, 73, 73, 0.5);
|
||||
`;
|
||||
const Footer = ({ children }) => {
|
||||
const render = () => (
|
||||
<StyledTitle name="card-footer">
|
||||
<Span>{children}</Span>
|
||||
</StyledTitle>
|
||||
);
|
||||
|
||||
return <Subscriber channel="card">{render}</Subscriber>;
|
||||
};
|
||||
|
||||
Footer.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export default Baseline(Footer);
|
@ -9,3 +9,4 @@ export { default as CardSubTitle } from './subtitle.js';
|
||||
export { default as CardTitle } from './title.js';
|
||||
export { default as CardView } from './view.js';
|
||||
export { default as CardInfo } from './info.js';
|
||||
export { default as CardFooter } from './footer.js';
|
||||
|
@ -52,6 +52,36 @@ const {
|
||||
</Card>
|
||||
```
|
||||
|
||||
#### `transparent`
|
||||
```
|
||||
const {
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardMeta,
|
||||
CardOptions,
|
||||
CardOutlet,
|
||||
CardSubTitle,
|
||||
CardTitle,
|
||||
CardView,
|
||||
CardGroupView,
|
||||
CardFooter
|
||||
} = require('./');
|
||||
|
||||
<Card transparent>
|
||||
<CardView>
|
||||
<CardMeta>
|
||||
<CardTitle>$0.016 per hour</CardTitle>
|
||||
<CardSubTitle>0.256 GB RAM</CardSubTitle>
|
||||
<CardSubTitle>0.25 vCPUs</CardSubTitle>
|
||||
<CardSubTitle>0.01 TB disk</CardSubTitle>
|
||||
<CardSubTitle>SSD</CardSubTitle>
|
||||
|
||||
<CardFooter>Compute Optimise</CardFooter>
|
||||
</CardMeta>
|
||||
</CardView>
|
||||
</Card>
|
||||
```
|
||||
|
||||
#### `headed`
|
||||
|
||||
```
|
||||
|
@ -27,6 +27,7 @@ export {
|
||||
export { Dropdown } from './dropdown';
|
||||
export { default as StatusLoader } from './status-loader';
|
||||
export { default as Message } from './message';
|
||||
export { default as Slider } from './slider';
|
||||
|
||||
export {
|
||||
default as Progressbar,
|
||||
@ -69,7 +70,8 @@ export {
|
||||
CardSubTitle,
|
||||
CardTitle,
|
||||
CardView,
|
||||
CardInfo
|
||||
CardInfo,
|
||||
CardFooter
|
||||
} from './card';
|
||||
|
||||
export {
|
||||
|
@ -72,7 +72,7 @@ const Message = ({ title, message, onCloseClick, children, ...type }) => {
|
||||
|
||||
Message.propTypes = {
|
||||
title: PropTypes.string,
|
||||
message: PropTypes.string.isRequired,
|
||||
message: PropTypes.string,
|
||||
onCloseClick: PropTypes.func,
|
||||
error: PropTypes.boolean,
|
||||
warning: PropTypes.boolean,
|
||||
|
25
packages/ui-toolkit/src/slider/Readme.md
Normal file
25
packages/ui-toolkit/src/slider/Readme.md
Normal file
@ -0,0 +1,25 @@
|
||||
### Double Range Slider
|
||||
|
||||
```
|
||||
<Slider
|
||||
minValue={0.25}
|
||||
maxValue={8}
|
||||
step={0.25}
|
||||
value={{ min: 0.25, max: 8 }}
|
||||
onChangeComplete={value => console.log(value)}
|
||||
onChange={value => console.log(value)}
|
||||
>vCPUs</Slider>
|
||||
```
|
||||
|
||||
### Normal Slider
|
||||
|
||||
```
|
||||
<Slider
|
||||
minValue={10}
|
||||
maxValue={100}
|
||||
step={5}
|
||||
value={0}
|
||||
onChangeComplete={value => console.log(value)}
|
||||
onChange={value => console.log(value)}
|
||||
>Price</Slider>
|
||||
```
|
147
packages/ui-toolkit/src/slider/index.js
Normal file
147
packages/ui-toolkit/src/slider/index.js
Normal file
@ -0,0 +1,147 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import InputRange from 'react-input-range';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import theme from '../theme';
|
||||
import FormLabel from '../form/label';
|
||||
import {
|
||||
sliderStyles,
|
||||
disabledStyles,
|
||||
trackStyles,
|
||||
activeStyles,
|
||||
rangeStyles
|
||||
} from './inputStyles';
|
||||
|
||||
const SliderStyled = styled.div`
|
||||
.input-range {
|
||||
${rangeStyles};
|
||||
}
|
||||
|
||||
.slider {
|
||||
${sliderStyles};
|
||||
}
|
||||
.disabled {
|
||||
${disabledStyles};
|
||||
}
|
||||
|
||||
.min,
|
||||
.max {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.value {
|
||||
top: ${remcalc(8)};
|
||||
position: absolute;
|
||||
|
||||
.label-container {
|
||||
font-weight: 600;
|
||||
font-size: ${remcalc(10)};
|
||||
color: ${theme.secondary};
|
||||
left: -50%;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.track {
|
||||
${trackStyles};
|
||||
}
|
||||
|
||||
.active-track {
|
||||
${activeStyles};
|
||||
}
|
||||
`;
|
||||
|
||||
const Label = styled(FormLabel)`
|
||||
margin-bottom: ${remcalc(10)};
|
||||
margin-top: ${remcalc(12)};
|
||||
`;
|
||||
|
||||
class Slider extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
minValue: this.props.minValue,
|
||||
maxValue: this.props.maxValue,
|
||||
value: this.props.value
|
||||
};
|
||||
|
||||
this.changeValue = this.changeValue.bind(this);
|
||||
}
|
||||
|
||||
changeValue(value) {
|
||||
this.setState({ value }, () => this.props.onChange(value));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { minValue, maxValue, value } = this.state;
|
||||
const { children, ...rest } = this.props;
|
||||
return (
|
||||
<SliderStyled>
|
||||
<Label>{children}</Label>
|
||||
<InputRange
|
||||
{...rest}
|
||||
minValue={minValue}
|
||||
maxValue={maxValue}
|
||||
value={value}
|
||||
onChange={value => this.changeValue(value)}
|
||||
/>
|
||||
</SliderStyled>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Slider.propTypes = {
|
||||
minValue: PropTypes.number,
|
||||
maxValue: PropTypes.number,
|
||||
step: PropTypes.number,
|
||||
value: PropTypes.oneOfType([PropTypes.number, PropTypes.shape()]),
|
||||
onChangeComplete: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
formatLabel: PropTypes.func,
|
||||
ariaLabelledby: PropTypes.string,
|
||||
ariaControls: PropTypes.string,
|
||||
classNames: PropTypes.shape({
|
||||
activeTrack: PropTypes.string,
|
||||
disabledInputRange: PropTypes.string,
|
||||
inputRange: PropTypes.string,
|
||||
labelContainer: PropTypes.string,
|
||||
maxLabel: PropTypes.string,
|
||||
minLabel: PropTypes.string,
|
||||
slider: PropTypes.string,
|
||||
sliderContainer: PropTypes.string,
|
||||
track: PropTypes.string,
|
||||
valueLabel: PropTypes.string
|
||||
}),
|
||||
disabled: PropTypes.bool,
|
||||
draggableTrack: PropTypes.bool,
|
||||
onChangeStart: PropTypes.func,
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
Slider.defaultProps = {
|
||||
onChangeComplete: () => {},
|
||||
onChange: () => {},
|
||||
formatLabel: value =>
|
||||
(value.toString().split('.')[1] || []).length > 3
|
||||
? Math.round(value).toFixed(3)
|
||||
: value,
|
||||
onChangeStart: () => {},
|
||||
step: 1,
|
||||
classNames: {
|
||||
activeTrack: 'active-track',
|
||||
disabledInputRange: 'disabled-range',
|
||||
inputRange: 'input-range',
|
||||
labelContainer: 'label-container',
|
||||
maxLabel: 'max',
|
||||
minLabel: 'min',
|
||||
sliderContainer: 'slider-container',
|
||||
track: 'track',
|
||||
valueLabel: 'value',
|
||||
slider: 'slider'
|
||||
}
|
||||
};
|
||||
|
||||
export default Slider;
|
61
packages/ui-toolkit/src/slider/inputStyles.js
Normal file
61
packages/ui-toolkit/src/slider/inputStyles.js
Normal file
@ -0,0 +1,61 @@
|
||||
import { css } from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
export const sliderStyles = css`
|
||||
appearance: none;
|
||||
background: ${theme.white};
|
||||
border: 2px solid ${theme.greyLight};
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: ${remcalc(14)};
|
||||
width: ${remcalc(14)};
|
||||
transform: translateY(-50%) translateX(-50%);
|
||||
outline: none;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: ${remcalc(2)};
|
||||
|
||||
&::active {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
&::focus {
|
||||
box-shadow: 0 0 0 5px rgba(63, 81, 181, 0.2);
|
||||
}
|
||||
`;
|
||||
|
||||
export const disabledStyles = css`
|
||||
.track {
|
||||
background: ${theme.grey};
|
||||
}
|
||||
.slider {
|
||||
background: ${theme.greyDark};
|
||||
border: 1px solid ${theme.greyDark};
|
||||
box-shadow: none;
|
||||
transform: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export const trackStyles = css`
|
||||
background: ${theme.grey};
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: ${remcalc(4)};
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
export const activeStyles = css`
|
||||
background: ${theme.blue};
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
`;
|
||||
|
||||
export const rangeStyles = css`
|
||||
position: relative;
|
||||
width: calc(100% - 18px);
|
||||
margin: auto;
|
||||
min-height: ${remcalc(10)};
|
||||
`;
|
@ -50,6 +50,8 @@ export const base = {
|
||||
...tertiary,
|
||||
text: '#494949', // used
|
||||
grey: '#D8D8D8', // used
|
||||
greyDark: '#CCC',
|
||||
greyLight: '#bdbdbd', // used
|
||||
disabled: '#FAFAFA', // used
|
||||
background: '#FAFAFA', // used
|
||||
green: '#00AF66', // used
|
||||
@ -57,7 +59,8 @@ export const base = {
|
||||
orange: '#E38200', // used
|
||||
orangeDark: '#CB7400', // not used - BORDER
|
||||
red: '#DA4B42', // used
|
||||
redDark: '#CD251B' // not used - BORDER
|
||||
redDark: '#CD251B', // not used - BORDER
|
||||
blue: '#364ACD'
|
||||
};
|
||||
|
||||
/** ********************************** HEADER ********************************** */
|
||||
|
@ -70,7 +70,8 @@ module.exports = snapguidist({
|
||||
'src/tooltip/tooltip.js',
|
||||
'src/close-button/index.js',
|
||||
'src/icon-button/index.js',
|
||||
'src/message/index.js'
|
||||
'src/message/index.js',
|
||||
'src/slider/index.js'
|
||||
]
|
||||
},
|
||||
{
|
||||
|
20
yarn.lock
20
yarn.lock
@ -684,6 +684,10 @@ auto-bind@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-1.1.0.tgz#93b864dc7ee01a326281775d5c75ca0a751e5961"
|
||||
|
||||
autobind-decorator@^1.3.4:
|
||||
version "1.4.3"
|
||||
resolved "https://registry.yarnpkg.com/autobind-decorator/-/autobind-decorator-1.4.3.tgz#4c96ffa77b10622ede24f110f5dbbf56691417d1"
|
||||
|
||||
automated-readability@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/automated-readability/-/automated-readability-1.0.1.tgz#5cf9111efcead6fe13b8c954d425b0068d59949d"
|
||||
@ -2960,6 +2964,13 @@ cors@2.8.1:
|
||||
dependencies:
|
||||
vary "^1"
|
||||
|
||||
cors@^2.8.4:
|
||||
version "2.8.4"
|
||||
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.4.tgz#2bd381f2eb201020105cd50ea59da63090694686"
|
||||
dependencies:
|
||||
object-assign "^4"
|
||||
vary "^1"
|
||||
|
||||
cosmiconfig@^2.1.0, cosmiconfig@^2.1.1, cosmiconfig@^2.1.3:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.2.2.tgz#6173cebd56fac042c1f4390edf7af6c07c7cb892"
|
||||
@ -8565,7 +8576,7 @@ oauth-sign@~0.8.1:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
|
||||
|
||||
object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
object-assign@4.1.1, object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
|
||||
@ -9934,6 +9945,13 @@ react-icons@^2.2.5:
|
||||
dependencies:
|
||||
react-icon-base "2.0.7"
|
||||
|
||||
react-input-range@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/react-input-range/-/react-input-range-1.2.1.tgz#10ff5fc1ec6ab9d95e15cddebe6f6879db2c3386"
|
||||
dependencies:
|
||||
autobind-decorator "^1.3.4"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-redux@^5.0.6:
|
||||
version "5.0.6"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.6.tgz#23ed3a4f986359d68b5212eaaa681e60d6574946"
|
||||
|
Loading…
Reference in New Issue
Block a user