feat(my-joy-beta): create instance networks

fixes #985
This commit is contained in:
Sérgio Ramos 2018-01-11 15:54:24 +00:00 committed by Sérgio Ramos
parent e12a0d4dd2
commit f489e34402
49 changed files with 36292 additions and 27947 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3,17 +3,19 @@ export { default as Affinity } from './affinity';
export { default as Arrow } from './arrow';
export { default as Bin } from './bin';
export { default as Checkcircle } from './checkcircle';
export { default as Chevron } from './chevron';
export { default as Clipboard } from './clipboard';
export { default as Close } from './close';
export { default as Cns } from './cns';
export { default as Copy } from './copy';
export { default as Cpu } from './cpu';
export { default as DataCenter } from './data-center';
export { default as Delete } from './delete';
export { default as Dot } from './dot';
export { default as Duplicate } from './duplicate';
export { default as Edit } from './edit';
export { default as Fabric } from './fabric';
export { default as Firewall } from './firewall';
export { default as General } from './general';
export { default as Health } from './health';
export { default as Id } from './id';
export { default as Import } from './import';
@ -22,21 +24,21 @@ export { default as InstanceType } from './instance-type';
export { default as Instances } from './instances';
export { default as Loading } from './loading';
export { default as Login } from './login';
export { default as Memory } from './memory';
export { default as Metadata } from './metadata';
export { default as Minus } from './minus';
export { default as Name } from './name';
export { default as Network } from './network';
export { default as Package } from './package';
export { default as Plus } from './plus';
export { default as Private } from './private';
export { default as Public } from './public';
export { default as Randomize } from './randomize';
export { default as Reset } from './reset';
export { default as Restart } from './restart';
export { default as Start } from './start';
export { default as Stop } from './stop';
export { default as Storage } from './storage';
export { default as Tags } from './tags';
export { default as Triton } from './triton';
export { default as User } from './user';
export { default as Randomize } from './randomize';
export { default as Name } from './name';
export { default as Fabric } from './fabric';
export { default as Cpu } from './cpu';
export { default as Memory } from './memory';
export { default as Storage } from './storage';
export { default as General } from './general';

View File

@ -17,18 +17,16 @@ export default ({
<Rotate direction={direction}>
{({ style: rotateStyle }) => (
<svg
width="6"
height="10"
viewBox="0 0 6 10"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 12 16"
width="12"
height="16"
style={{ ...style, ...rotateStyle }}
{...rest}
>
<path
fill={calcFill({ fill, disabled, light, colors })}
fillRule="evenodd"
d="M1.12 0L0 1.36 3.496 4.8 0 8.24 1.12 9.6 6 4.8 1.12 0z"
opacity=".5"
d="M10,6V4A4,4,0,0,0,2,4V6H2A2,2,0,0,0,0,8v6a2,2,0,0,0,2,2h8a2,2,0,0,0,2-2V8A2,2,0,0,0,10,6ZM4,4c0-1.65.35-2,2-2s2,.35,2,2V6H4Zm6,9a1,1,0,0,1-1,1H3a1,1,0,0,1-1-1V9A1,1,0,0,1,3,8H9a1,1,0,0,1,1,1ZM6,13H6a1,1,0,0,1-1-1V10A1,1,0,0,1,6,9H6a1,1,0,0,1,1,1v2A1,1,0,0,1,6,13Z"
/>
</svg>
)}

View File

@ -0,0 +1,37 @@
import React from 'react';
import Colors from './colors';
import Rotate from './rotate';
import calcFill from './fill';
export default ({
fill = null,
light = false,
disabled = false,
direction = 'down',
style = {},
...rest
}) => (
<Colors white text grey>
{colors => (
<Rotate direction={direction}>
{({ style: rotateStyle }) => (
<svg
viewBox="0 0 12 16"
width="12"
height="16"
style={{ ...style, ...rotateStyle }}
{...rest}
>
<g>
<path
fill={calcFill({ fill, disabled, light, colors })}
d="M6 13a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1 1 1 0 0 1 1 1v2a1 1 0 0 1-1 1zm4-7V4a4 4 0 0 0-8 0h2c0-1.65.35-2 2-2s2 .35 2 2v2H2a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zm0 7a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1z"
/>
</g>
</svg>
)}
</Rotate>
)}
</Colors>
);

View File

@ -6,14 +6,11 @@
"repository": "github:yldio/joyent-portal",
"main": "build/",
"scripts": {
"dev":
"REACT_APP_GQL_PORT=4000 PORT=3069 REACT_APP_GQL_PROTOCOL=http joyent-react-scripts start",
"dev": "REACT_APP_GQL_PORT=4000 PORT=3069 REACT_APP_GQL_PROTOCOL=http joyent-react-scripts start",
"start": "PORT=3069 joyent-react-scripts start",
"build": "NODE_ENV=production joyent-react-scripts build",
"lint-ci":
"eslint . --ext .js --ext .md && echo 0 `# stylelint './src/**/*.js'`",
"lint":
"eslint . --fix --ext .js --ext .md && echo 0 `# stylelint './src/**/*.js'`",
"lint-ci": "eslint . --ext .js --ext .md && echo 0 `# stylelint './src/**/*.js'`",
"lint": "eslint . --fix --ext .js --ext .md && echo 0 `# stylelint './src/**/*.js'`",
"test": "NODE_ENV=test joyent-react-scripts test --env=jsdom",
"test-ci": "npm run test",
"prepublish": "echo 0"

View File

@ -316,7 +316,7 @@ exports[`renders <Name expanded /> without throwing 1`] = `
.c4 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;

View File

@ -281,10 +281,7 @@ exports[`renders <Filters /> without throwing 1`] = `
/>
</div>
<div
checked={false}
className="c8"
disabled={false}
id="a"
>
<label
className="c9"
@ -349,10 +346,7 @@ exports[`renders <Filters /> without throwing 1`] = `
/>
</div>
<div
checked={false}
className="c8"
disabled={false}
id="bc"
>
<label
className="c9"
@ -417,10 +411,7 @@ exports[`renders <Filters /> without throwing 1`] = `
/>
</div>
<div
checked={false}
className="c8"
disabled={false}
id="be"
>
<label
className="c9"
@ -485,10 +476,7 @@ exports[`renders <Filters /> without throwing 1`] = `
/>
</div>
<div
checked={false}
className="c8"
disabled={false}
id="bg"
>
<label
className="c9"
@ -553,10 +541,7 @@ exports[`renders <Filters /> without throwing 1`] = `
/>
</div>
<div
checked={false}
className="c8"
disabled={false}
id="bi"
>
<label
className="c9"
@ -1192,6 +1177,7 @@ exports[`renders <Package /> without throwing 1`] = `
.c7 {
margin-left: 0.75rem;
margin-bottom: 0.75rem;
}
.c2 {
@ -1306,8 +1292,6 @@ exports[`renders <Package /> without throwing 1`] = `
</div>
<div
className="c7"
disabled={false}
id="Y"
>
<div
className="c8"

View File

@ -0,0 +1,199 @@
import React from 'react';
import renderer from 'react-test-renderer';
import 'jest-styled-components';
import { Collapsed, Expanded } from '../network';
import Theme from '@mocks/theme';
it('renders <Network /> without throwing', () => {
expect(
renderer
.create(
<Theme>
<Expanded />
</Theme>
)
.toJSON()
).toMatchSnapshot();
expect(
renderer
.create(
<Theme>
<Collapsed />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Network {...network} /> without throwing', () => {
const network = {
id: '1',
name: 'name',
description: 'description',
fabric: false,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: false,
infoExpanded: false
};
expect(
renderer
.create(
<Theme>
<Expanded {...network} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
expect(
renderer
.create(
<Theme>
<Collapsed {...network} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Network {...network} /> without throwing', () => {
const network = {
id: '1',
name: 'name',
description: 'description',
fabric: false,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: false,
infoExpanded: false
};
expect(
renderer
.create(
<Theme>
<Expanded {...network} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
expect(
renderer
.create(
<Theme>
<Collapsed {...network} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Network {...network} public /> without throwing', () => {
const network = {
id: '1',
name: 'name',
description: 'description',
fabric: false,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: false,
infoExpanded: false,
public: true
};
expect(
renderer
.create(
<Theme>
<Expanded {...network} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
expect(
renderer
.create(
<Theme>
<Collapsed {...network} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Network {...network} fabric /> without throwing', () => {
const network = {
id: '1',
name: 'name',
description: 'description',
fabric: true,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: false,
infoExpanded: false
};
expect(
renderer
.create(
<Theme>
<Expanded {...network} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
expect(
renderer
.create(
<Theme>
<Collapsed {...network} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Network {...network} infoExpanded /> without throwing', () => {
const network = {
id: '1',
name: 'name',
description: 'description',
fabric: true,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: false,
infoExpanded: true
};
expect(
renderer
.create(
<Theme>
<Expanded {...network} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
expect(
renderer
.create(
<Theme>
<Collapsed {...network} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});

View File

@ -0,0 +1,205 @@
import React from 'react';
import { Field } from 'redux-form';
import { Margin, Padding } from 'styled-components-spacing';
import styled from 'styled-components';
import Flex, { FlexItem } from 'styled-flex-component';
import remcalc from 'remcalc';
import {
H4,
P,
Card,
CardHeader,
CardHeaderMeta,
CardHeaderBox,
CardOutlet,
FormGroup,
FormLabel,
Input,
Checkbox,
Divider,
FabricIcon,
DataCenterIcon,
PublicIcon,
PrivateIcon,
ArrowIcon
} from 'joyent-ui-toolkit';
const Box = styled.div`
display: inline-block;
background-color: ${props => props.theme.white};
border: ${remcalc(1)} solid ${props => props.theme.grey};
border-radius: ${remcalc(4)};
min-width: ${remcalc(300)};
`;
export const Collapsed = ({ name, fabric, ...network }) => (
<Margin inline right={3} top={3}>
<Box>
<Flex column>
<FlexItem>
<Margin left={3} right={3} top={2} bottom={2}>
<P>{name}</P>
</Margin>
</FlexItem>
<FlexItem>
<Divider height={remcalc(1)} />
</FlexItem>
<FlexItem>
<Margin left={3} right={3} top={2} bottom={2}>
<Flex>
<Margin right={4}>
<FlexItem>
<Flex alignCenter>
<FlexItem>
<Margin right={1}>
{network.public ? <PublicIcon /> : <PrivateIcon />}
</Margin>
</FlexItem>
<FlexItem>
<P>{network.public ? 'Public' : 'Private'}</P>
</FlexItem>
</Flex>
</FlexItem>
</Margin>
<Margin>
<FlexItem>
<Flex alignCenter>
<FlexItem>
<Margin right={1}>
{fabric ? <FabricIcon /> : <DataCenterIcon />}
</Margin>
</FlexItem>
<FlexItem>
<P>{fabric ? 'Fabric' : 'Data center network'}</P>
</FlexItem>
</Flex>
</FlexItem>
</Margin>
</Flex>
</Margin>
</FlexItem>
</Flex>
</Box>
</Margin>
);
export const Expanded = ({
id,
name,
fabric,
subnet,
description,
provision_start_ip,
provision_end_ip,
selected = false,
infoExpanded = false,
onInfoClick,
...network
}) => (
<Margin bottom={4}>
<Card shadow>
<CardHeader secondary={selected}>
<CardHeaderBox>
<FormGroup name={id} field={Field}>
<Checkbox noMargin />
</FormGroup>
</CardHeaderBox>
<CardHeaderMeta paddingLeft={0}>
<H4 white={selected}>{name}</H4>
</CardHeaderMeta>
</CardHeader>
<CardOutlet>
<Padding all={4}>
{description && (
<Margin bottom={3}>
<P>{description}</P>
</Margin>
)}
<Flex>
<Margin right={4}>
<FlexItem>
<Flex alignCenter>
<FlexItem>
<Margin right={1}>
{network.public ? <PublicIcon /> : <PrivateIcon />}
</Margin>
</FlexItem>
<FlexItem>
<P>{network.public ? 'Public' : 'Private'}</P>
</FlexItem>
</Flex>
</FlexItem>
</Margin>
<Margin right={4}>
<FlexItem>
<Flex alignCenter>
<FlexItem>
<Margin right={1}>
{fabric ? <FabricIcon /> : <DataCenterIcon />}
</Margin>
</FlexItem>
<FlexItem>
<P>{fabric ? 'Fabric' : 'Data center network'}</P>
</FlexItem>
</Flex>
</FlexItem>
</Margin>
</Flex>
{fabric ? (
<Margin top={3}>
<Card collapsed={!infoExpanded} actionable={!infoExpanded}>
<CardHeader
secondary={false}
transparent={false}
onClick={onInfoClick}
>
<CardHeaderMeta>
<Padding left={3} right={3}>
<P>Network information</P>
</Padding>
</CardHeaderMeta>
<CardHeaderBox>
<ArrowIcon direction={infoExpanded ? 'up' : 'down'} />
</CardHeaderBox>
</CardHeader>
{infoExpanded ? (
<CardOutlet>
<Padding all={3}>
<Flex column>
<FlexItem>
<FormGroup name="id">
<FormLabel>ID</FormLabel>
<Input type="text" value={id} />
</FormGroup>
</FlexItem>
<FlexItem>
<FormGroup name="subnet">
<FormLabel>Subnet</FormLabel>
<Input type="text" value={subnet} />
</FormGroup>
</FlexItem>
<FlexItem>
<FormGroup name="ip-range">
<FormLabel>IP range</FormLabel>
<Input
type="text"
value={`${provision_start_ip} - ${provision_end_ip}`}
/>
</FormGroup>
</FlexItem>
</Flex>
</Padding>
</CardOutlet>
) : null}
</Card>
</Margin>
) : null}
</Padding>
</CardOutlet>
</Card>
</Margin>
);
export default ({ small = false, ...rest }) =>
small ? <Collapsed {...rest} /> : <Expanded {...rest} />;

View File

@ -195,7 +195,7 @@ exports[`renders <Toolbar /> without throwing 1`] = `
.c4 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
@ -558,7 +558,7 @@ exports[`renders <Toolbar actionLabel /> without throwing 1`] = `
.c4 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
@ -943,7 +943,7 @@ exports[`renders <Toolbar actionable /> without throwing 1`] = `
.c4 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
@ -1306,7 +1306,7 @@ exports[`renders <Toolbar onActionClick /> without throwing 1`] = `
.c4 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
@ -1669,7 +1669,7 @@ exports[`renders <Toolbar searchLabel /> without throwing 1`] = `
.c4 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
@ -2032,7 +2032,7 @@ exports[`renders <Toolbar searchPlaceholder /> without throwing 1`] = `
.c4 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
@ -2417,7 +2417,7 @@ exports[`renders <Toolbar searchable /> without throwing 1`] = `
.c4 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;

View File

@ -1,4 +1,5 @@
import React, { PureComponent } from 'react';
import { Padding } from 'styled-components-spacing';
import PropTypes from 'prop-types';
import { withTheme } from 'styled-components';
import { Row, Col } from 'react-styled-flexboxgrid';
@ -6,7 +7,6 @@ import { Field } from 'redux-form';
import styled from 'styled-components';
import remcalc from 'remcalc';
import titleCase from 'title-case';
import { Padding } from 'styled-components-spacing';
import Flex, { FlexItem } from 'styled-flex-component';
import Editor from 'joyent-ui-toolkit/dist/es/editor';
@ -138,24 +138,26 @@ export const KeyValue = ({
actionable={Boolean(handleHeaderClick)}
onClick={handleHeaderClick}
>
<CardHeaderMeta>
{method === 'add' || method === 'create' ? (
<H4>{`${titleCase(method)} ${type}`}</H4>
) : (
<CollapsedKeyValue>
{expanded ? (
<span>{`${initialValues.name}: `}</span>
) : (
<b>{`${initialValues.name}: `}</b>
)}
<span>{initialValues.value}</span>
</CollapsedKeyValue>
)}
</CardHeaderMeta>
<Padding left={3} right={3}>
<CardHeaderMeta>
{method === 'add' || method === 'create' ? (
<H4>{`${titleCase(method)} ${type}`}</H4>
) : (
<CollapsedKeyValue>
{expanded ? (
<span>{`${initialValues.name}: `}</span>
) : (
<b>{`${initialValues.name}: `}</b>
)}
<span>{initialValues.value}</span>
</CollapsedKeyValue>
)}
</CardHeaderMeta>
</Padding>
</CardHeader>
{expanded ? (
<CardOutlet>
<Padding all={1}>
<Padding all={3}>
{error && !submitting ? (
<Row>
<Col xs={12}>

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { Row, Col } from 'react-styled-flexboxgrid';
import styled, { withTheme } from 'styled-components';
import { Margin } from 'styled-components-spacing';
import { Margin, Padding } from 'styled-components-spacing';
import remcalc from 'remcalc';
import is from 'styled-is';
import titleCase from 'title-case';
@ -209,169 +209,171 @@ export default withTheme(
<Row>
<Col xs={12} sm={12} md={9}>
<Card>
<CardOutlet big>
<Meta {...instance} />
<Row between="xs">
<Col xs={9}>
<SmallOnly>
<Button
type="button"
loading={starting}
disabled={instance.state !== 'STOPPED'}
onClick={() => onAction('start')}
secondary
small
icon
>
<StartIcon disabled={instance.state !== 'STOPPED'} />
</Button>
</SmallOnly>
<Medium>
<Button
type="button"
loading={starting}
disabled={instance.state !== 'STOPPED'}
onClick={() => onAction('start')}
secondary
bold
icon
>
<StartIcon disabled={instance.state !== 'STOPPED'} />
<span>Start</span>
</Button>
</Medium>
<SmallOnly>
<Button
type="button"
loading={stopping}
disabled={instance.state !== 'RUNNING'}
onClick={() => onAction('stop')}
secondary
small
icon
>
<StopIcon disabled={instance.state !== 'RUNNING'} />
</Button>
</SmallOnly>
<Medium>
<Button
type="button"
loading={stopping}
disabled={instance.state !== 'RUNNING'}
onClick={() => onAction('stop')}
secondary
bold
icon
>
<StopIcon disabled={instance.state !== 'RUNNING'} />
<span>Stop</span>
</Button>
</Medium>
<SmallOnly>
<Button
type="button"
loading={rebooting}
disabled={instance.state !== 'RUNNING'}
onClick={() => onAction('reboot')}
secondary
small
icon
>
<ResetIcon disabled={instance.state !== 'RUNNING'} />
</Button>
</SmallOnly>
<Medium>
<Button
type="button"
loading={rebooting}
disabled={instance.state !== 'RUNNING'}
onClick={() => onAction('reboot')}
secondary
bold
icon
>
<ResetIcon disabled={instance.state !== 'RUNNING'} />
<span>Reboot</span>
</Button>
</Medium>
</Col>
<Col xs={3}>
<SmallOnly>
<Button
type="button"
loading={removing}
disabled={
['RUNNING', 'STOPPED'].indexOf(instance.state) < 0
}
onClick={() => onAction('remove')}
secondary
small
right
icon
error
>
<DeleteIcon
fill={theme.red}
<CardOutlet>
<Padding all={4}>
<Meta {...instance} />
<Row between="xs">
<Col xs={9}>
<SmallOnly>
<Button
type="button"
loading={starting}
disabled={instance.state !== 'STOPPED'}
onClick={() => onAction('start')}
secondary
small
icon
>
<StartIcon disabled={instance.state !== 'STOPPED'} />
</Button>
</SmallOnly>
<Medium>
<Button
type="button"
loading={starting}
disabled={instance.state !== 'STOPPED'}
onClick={() => onAction('start')}
secondary
bold
icon
>
<StartIcon disabled={instance.state !== 'STOPPED'} />
<span>Start</span>
</Button>
</Medium>
<SmallOnly>
<Button
type="button"
loading={stopping}
disabled={instance.state !== 'RUNNING'}
onClick={() => onAction('stop')}
secondary
small
icon
>
<StopIcon disabled={instance.state !== 'RUNNING'} />
</Button>
</SmallOnly>
<Medium>
<Button
type="button"
loading={stopping}
disabled={instance.state !== 'RUNNING'}
onClick={() => onAction('stop')}
secondary
bold
icon
>
<StopIcon disabled={instance.state !== 'RUNNING'} />
<span>Stop</span>
</Button>
</Medium>
<SmallOnly>
<Button
type="button"
loading={rebooting}
disabled={instance.state !== 'RUNNING'}
onClick={() => onAction('reboot')}
secondary
small
icon
>
<ResetIcon disabled={instance.state !== 'RUNNING'} />
</Button>
</SmallOnly>
<Medium>
<Button
type="button"
loading={rebooting}
disabled={instance.state !== 'RUNNING'}
onClick={() => onAction('reboot')}
secondary
bold
icon
>
<ResetIcon disabled={instance.state !== 'RUNNING'} />
<span>Reboot</span>
</Button>
</Medium>
</Col>
<Col xs={3}>
<SmallOnly>
<Button
type="button"
loading={removing}
disabled={
['RUNNING', 'STOPPED'].indexOf(instance.state) < 0
}
/>
</Button>
</SmallOnly>
<Medium>
<Button
type="button"
loading={removing}
disabled={
['RUNNING', 'STOPPED'].indexOf(instance.state) < 0
}
onClick={() => onAction('remove')}
secondary
bold
right
icon
error
>
<DeleteIcon
fill={
['RUNNING', 'STOPPED'].indexOf(instance.state) >= 0
? theme.red
: undefined
}
onClick={() => onAction('remove')}
secondary
small
right
icon
error
>
<DeleteIcon
fill={theme.red}
disabled={
['RUNNING', 'STOPPED'].indexOf(instance.state) < 0
}
/>
</Button>
</SmallOnly>
<Medium>
<Button
type="button"
loading={removing}
disabled={
['RUNNING', 'STOPPED'].indexOf(instance.state) < 0
}
/>
<span>Remove</span>
</Button>
</Medium>
</Col>
</Row>
<Margin bottom={5} top={4}>
<Divider height={remcalc(1)} />
</Margin>
<CopiableField
text={(instance.id || '').split('-')[0]}
label="Short ID"
/>
<CopiableField text={instance.id} label="ID" />
<CopiableField text={instance.compute_node} label="CN UUID" />
{instance.image &&
instance.image.id && (
<CopiableField text={instance.image.id} label="Image UUID" />
)}
<CopiableField
text={`ssh root@${instance.primary_ip}`}
label="Login"
/>
{(instance.ips || []).map((ip, i) => (
onClick={() => onAction('remove')}
secondary
bold
right
icon
error
>
<DeleteIcon
fill={
['RUNNING', 'STOPPED'].indexOf(instance.state) >= 0
? theme.red
: undefined
}
disabled={
['RUNNING', 'STOPPED'].indexOf(instance.state) < 0
}
/>
<span>Remove</span>
</Button>
</Medium>
</Col>
</Row>
<Margin bottom={5} top={4}>
<Divider height={remcalc(1)} />
</Margin>
<CopiableField
key={i}
noMargin={i === instance.ips.length - 1}
text={ip}
label={`IP address ${i + 1}`}
text={(instance.id || '').split('-')[0]}
label="Short ID"
/>
))}
<CopiableField text={instance.id} label="ID" />
<CopiableField text={instance.compute_node} label="CN UUID" />
{instance.image &&
instance.image.id && (
<CopiableField text={instance.image.id} label="Image UUID" />
)}
<CopiableField
text={`ssh root@${instance.primary_ip}`}
label="Login"
/>
{(instance.ips || []).map((ip, i) => (
<CopiableField
key={i}
noMargin={i === instance.ips.length - 1}
text={ip}
label={`IP address ${i + 1}`}
/>
))}
</Padding>
</CardOutlet>
</Card>
</Col>

View File

@ -0,0 +1,147 @@
import React from 'react';
import renderer from 'react-test-renderer';
import 'jest-styled-components';
import Theme from '@mocks/theme';
import { Networks } from '../networks';
it('renders <Networks /> without throwing', () => {
expect(
renderer
.create(
<Theme>
<Networks />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Networks loading /> without throwing', () => {
expect(
renderer
.create(
<Theme>
<Networks loading />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Networks loading expanded /> without throwing', () => {
expect(
renderer
.create(
<Theme>
<Networks loading expanded />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Networks networks=[] /> without throwing', () => {
const networks = [
{
id: '1',
name: 'name',
description: 'description',
fabric: true,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: false
},
{
id: '2',
name: 'name2',
description: 'description2',
fabric: false,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: true
}
];
expect(
renderer
.create(
<Theme>
<Networks networks={networks} />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Networks networks=[] expanded /> without throwing', () => {
const networks = [
{
id: '1',
name: 'name',
description: 'description',
fabric: true,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: false
},
{
id: '2',
name: 'name2',
description: 'description2',
fabric: false,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: true
}
];
expect(
renderer
.create(
<Theme>
<Networks networks={networks} expanded />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Networks networks=[] proceeded /> without throwing', () => {
const networks = [
{
id: '1',
name: 'name',
description: 'description',
fabric: true,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: false
},
{
id: '2',
name: 'name2',
description: 'description2',
fabric: false,
subnet: '255.255.255.0',
provision_start_ip: '192.168.1.2',
provision_end_ip: '192.168.1.253',
selected: true
}
];
expect(
renderer
.create(
<Theme>
<Networks networks={networks} proceeded />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});

View File

@ -8,6 +8,7 @@ import Image from '@containers/create-instance/image';
import Metadata from '@containers/create-instance/metadata';
import Tags from '@containers/create-instance/tags';
import Package from '@containers/create-instance/package';
import Networks from '@containers/create-instance/networks';
export default ({ step, ...props }) => (
<ViewContainer>
@ -29,5 +30,8 @@ export default ({ step, ...props }) => (
<Margin bottom={4}>
<Metadata {...props} expanded={step === 'metadata'} />
</Margin>
<Margin bottom={4}>
<Networks {...props} expanded={step === 'networks'} />
</Margin>
</ViewContainer>
);

View File

@ -18,6 +18,7 @@ const FORM_NAME_EDIT = i => `CREATE-INSTANCE-METADATA-EDIT-${i}`;
export const Metadata = ({
metadata = [],
expanded,
proceeded,
addOpen,
handleAddMetadata,
handleRemoveMetadata,
@ -45,11 +46,13 @@ export const Metadata = ({
</P>
</Margin>
) : null}
<Margin bottom={4}>
<H3>
{metadata.length} key:value pair{metadata.length === 1 ? '' : 's'}
</H3>
</Margin>
{proceeded ? (
<Margin bottom={4}>
<H3>
{metadata.length} key:value pair{metadata.length === 1 ? '' : 's'}
</H3>
</Margin>
) : null}
{metadata.map(({ name, value, expanded }, index) => (
<ReduxForm
form={FORM_NAME_EDIT(index)}
@ -107,22 +110,27 @@ export const Metadata = ({
Next
</Button>
</Fragment>
) : (
) : proceeded ? (
<Button type="button" onClick={handleEdit} secondary>
Edit
</Button>
)}
) : null}
</div>
</Fragment>
);
export default compose(
connect(({ values }, ownProps) => ({
proceeded: get(values, 'create-instance-metadata-proceeded', false),
addOpen: get(values, 'create-instance-metadata-add-open', false),
metadata: get(values, 'create-instance-metadata', [])
})),
connect(null, (dispatch, { metadata = [], history }) => ({
handleNext: () => {
dispatch(
set({ name: 'create-instance-metadata-proceeded', value: true })
);
return history.push(`/instances/~create/networks`);
},
handleEdit: () => {

View File

@ -0,0 +1,148 @@
import React, { Fragment } from 'react';
import { set } from 'react-redux-values';
import { Margin } from 'styled-components-spacing';
import { compose, graphql } from 'react-apollo';
import ReduxForm from 'declarative-redux-form';
import { connect } from 'react-redux';
import get from 'lodash.get';
import forceArray from 'force-array';
import { NetworkIcon, P, Button, H3, StatusLoader } from 'joyent-ui-toolkit';
import Title from '@components/create-instance/title';
import Network from '@components/create-instance/network';
import ListNetworks from '@graphql/list-networks.gql';
const FORM_NAME = 'CREATE-INSTANCE-NETWORKS';
export const Networks = ({
networks = [],
expanded = false,
proceeded = false,
loading = false,
setInfoExpanded,
handleNext,
handleEdit
}) => {
const selected = networks.filter(({ selected }) => selected);
return (
<Fragment>
<Title icon={<NetworkIcon />}>Networks</Title>
{expanded ? (
<Margin bottom={3}>
<P>
Instances are automatically connected to a private fabric network,
which is the best choice for internal communication within your
application. Data center networks are the best choice for exposing
your application to the public internet (if the data center network
is a public network).{' '}
<a
target="__blank"
href="https://docs.joyent.com/public-cloud/network/sdn"
>
Read more
</a>
</P>
</Margin>
) : null}
{proceeded && !expanded ? (
<H3>
{selected.length} network{selected.length === 1 ? '' : 's'} added
</H3>
) : null}
{loading && expanded ? <StatusLoader /> : null}
{!loading ? (
<ReduxForm
form={FORM_NAME}
destroyOnUnmount={false}
forceUnregisterOnUnmount={true}
>
{props => (
<form>
{networks.map(
({ id, selected, infoExpanded, ...network }) =>
!expanded && !selected ? null : (
<Network
key={id}
id={id}
selected={selected}
infoExpanded={infoExpanded}
small={!expanded && selected}
onInfoClick={() => setInfoExpanded(id, !infoExpanded)}
{...network}
/>
)
)}
</form>
)}
</ReduxForm>
) : null}
<div>
{expanded ? (
<Button type="button" onClick={handleNext}>
Next
</Button>
) : proceeded ? (
<Button type="button" onClick={handleEdit} secondary>
Edit
</Button>
) : null}
</div>
</Fragment>
);
};
export default compose(
graphql(ListNetworks, {
props: ({ data }) => {
const { networks = [], loading = false, error = null, refetch } = data;
return {
networks: forceArray(networks),
loading,
error,
refetch
};
}
}),
connect(
({ values, form }, { networks }) => {
const selected = get(form, `${FORM_NAME}.values`, {});
return {
proceeded: get(values, 'create-instance-networks-proceeded', false),
networks: networks.map(({ id, ...network }) => ({
...network,
selected: Boolean(selected[id]),
infoExpanded: get(
values,
`create-instance-networks-${id}-expanded`,
false
),
id
}))
};
},
(dispatch, { history }) => ({
handleNext: () => {
dispatch(
set({ name: 'create-instance-networks-proceeded', value: true })
);
return history.push('/instances/~create/firewall');
},
handleEdit: () => {
return history.push('/instances/~create/networks');
},
setInfoExpanded: (id, expanded) => {
return dispatch(
set({
name: `create-instance-networks-${id}-expanded`,
value: expanded
})
);
}
})
)
)(Networks);

View File

@ -19,6 +19,7 @@ const FORM_NAME_EDIT = i => `CREATE-INSTANCE-TAGS-EDIT-${i}`;
export const Tags = ({
tags = [],
expanded,
proceeded,
addOpen,
handleAddTag,
handleRemoveTag,
@ -45,21 +46,25 @@ export const Tags = ({
</P>
</Margin>
) : null}
<Margin bottom={4}>
<H3>
{tags.length} Tag{tags.length === 1 ? '' : 's'}
</H3>
</Margin>
<TagList>
{tags.map(({ name, value }, index) => (
<Tag
key={index}
name={name}
value={value}
onRemoveClick={() => handleRemoveTag(index)}
/>
))}
</TagList>
{proceeded ? (
<Margin bottom={4}>
<H3>
{tags.length} Tag{tags.length === 1 ? '' : 's'}
</H3>
</Margin>
) : null}
{proceeded || expanded ? (
<TagList>
{tags.map(({ name, value }, index) => (
<Tag
key={index}
name={name}
value={value}
onRemoveClick={expanded && (() => handleRemoveTag(index))}
/>
))}
</TagList>
) : null}
{expanded && addOpen ? (
<ReduxForm
form={FORM_NAME_CREATE}
@ -93,22 +98,25 @@ export const Tags = ({
Next
</Button>
</Fragment>
) : (
) : proceeded ? (
<Button type="button" onClick={handleEdit} secondary>
Edit
</Button>
)}
) : null}
</div>
</Fragment>
);
export default compose(
connect(({ values }, ownProps) => ({
proceeded: get(values, 'create-instance-tags-proceeded', false),
addOpen: get(values, 'create-instance-tags-add-open', false),
tags: get(values, 'create-instance-tags', [])
})),
connect(null, (dispatch, { tags = [], history }) => ({
handleNext: () => {
dispatch(set({ name: 'create-instance-tags-proceeded', value: true }));
return history.push(`/instances/~create/metadata`);
},
handleEdit: () => {

View File

@ -61,7 +61,7 @@ exports[`renders <Breadcrumb /> without throwing 1`] = `
}
.c6 {
margin: 0.5rem 0.625rem 0.1875rem 0.625rem;
margin: 0.1875rem 0.625rem;
}
.c4 {
@ -146,21 +146,20 @@ exports[`renders <Breadcrumb /> without throwing 1`] = `
</h2>
<svg
className="c6 "
height="10"
height="6"
style={
Object {
"transform": "rotate(0deg)",
"transform": "rotate(-90deg)",
}
}
viewBox="0 0 6 10"
width="6"
viewBox="0 0 9 6"
width="9"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.12 0L0 1.36 3.496 4.8 0 8.24 1.12 9.6 6 4.8 1.12 0z"
fill="rgba(73, 73, 73, 1)"
d="M9 1.386L7.648 0 4.5 3.228 1.352 0 0 1.386 4.5 6z"
fill="rgb(151, 151, 151)"
fillRule="evenodd"
opacity=".5"
/>
</svg>
</div>
@ -231,7 +230,7 @@ exports[`renders <Breadcrumb match /> without throwing 1`] = `
}
.c6 {
margin: 0.5rem 0.625rem 0.1875rem 0.625rem;
margin: 0.1875rem 0.625rem;
}
.c4 {
@ -316,21 +315,20 @@ exports[`renders <Breadcrumb match /> without throwing 1`] = `
</h2>
<svg
className="c6 "
height="10"
height="6"
style={
Object {
"transform": "rotate(0deg)",
"transform": "rotate(-90deg)",
}
}
viewBox="0 0 6 10"
width="6"
viewBox="0 0 9 6"
width="9"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.12 0L0 1.36 3.496 4.8 0 8.24 1.12 9.6 6 4.8 1.12 0z"
fill="rgba(73, 73, 73, 1)"
d="M9 1.386L7.648 0 4.5 3.228 1.352 0 0 1.386 4.5 6z"
fill="rgb(151, 151, 151)"
fillRule="evenodd"
opacity=".5"
/>
</svg>
</div>
@ -345,21 +343,20 @@ exports[`renders <Breadcrumb match /> without throwing 1`] = `
</h2>
<svg
className="c6 "
height="10"
height="6"
style={
Object {
"transform": "rotate(0deg)",
"transform": "rotate(-90deg)",
}
}
viewBox="0 0 6 10"
width="6"
viewBox="0 0 9 6"
width="9"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.12 0L0 1.36 3.496 4.8 0 8.24 1.12 9.6 6 4.8 1.12 0z"
fill="rgba(73, 73, 73, 1)"
d="M9 1.386L7.648 0 4.5 3.228 1.352 0 0 1.386 4.5 6z"
fill="rgb(151, 151, 151)"
fillRule="evenodd"
opacity=".5"
/>
</svg>
</div>

View File

@ -1,19 +1,15 @@
query instance($name: String!) {
machines(name: $name) {
query {
networks {
id
name
networks {
id
name
public
fabric
description
subnet
provision_start_ip
provision_end_ip
gateway
resolvers
internet_nat
}
public
fabric
description
subnet
provision_start_ip
provision_end_ip
gateway
resolvers
internet_nat
}
}

View File

@ -131,6 +131,11 @@ export default () => (
exact
component={props => <CreateInstance {...props} step="metadata" />}
/>
<Route
path="/instances/~create/user-script"
exact
component={props => <CreateInstance {...props} step="user-script" />}
/>
<Route
path="/instances/~create/networks"
exact

View File

@ -25,7 +25,7 @@ exports[`Breadcrumb Default Breadcrumb 1`] = `
}
.c6 {
margin: 0.5rem 0.625rem 0.1875rem 0.625rem;
margin: 0.1875rem 0.625rem;
}
.c4 {
@ -146,21 +146,20 @@ exports[`Breadcrumb Default Breadcrumb 1`] = `
</h2>
<svg
className="c6 "
height="10"
height="6"
style={
Object {
"transform": "rotate(0deg)",
"transform": "rotate(-90deg)",
}
}
viewBox="0 0 6 10"
width="6"
viewBox="0 0 9 6"
width="9"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.12 0L0 1.36 3.496 4.8 0 8.24 1.12 9.6 6 4.8 1.12 0z"
fill="rgba(73, 73, 73, 1)"
d="M9 1.386L7.648 0 4.5 3.228 1.352 0 0 1.386 4.5 6z"
fill="rgb(151, 151, 151)"
fillRule="evenodd"
opacity=".5"
/>
</svg>
</div>
@ -175,21 +174,20 @@ exports[`Breadcrumb Default Breadcrumb 1`] = `
</h2>
<svg
className="c6 "
height="10"
height="6"
style={
Object {
"transform": "rotate(0deg)",
"transform": "rotate(-90deg)",
}
}
viewBox="0 0 6 10"
width="6"
viewBox="0 0 9 6"
width="9"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.12 0L0 1.36 3.496 4.8 0 8.24 1.12 9.6 6 4.8 1.12 0z"
fill="rgba(73, 73, 73, 1)"
d="M9 1.386L7.648 0 4.5 3.228 1.352 0 0 1.386 4.5 6z"
fill="rgb(151, 151, 151)"
fillRule="evenodd"
opacity=".5"
/>
</svg>
</div>
@ -204,21 +202,20 @@ exports[`Breadcrumb Default Breadcrumb 1`] = `
</h2>
<svg
className="c6 "
height="10"
height="6"
style={
Object {
"transform": "rotate(0deg)",
"transform": "rotate(-90deg)",
}
}
viewBox="0 0 6 10"
width="6"
viewBox="0 0 9 6"
width="9"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.12 0L0 1.36 3.496 4.8 0 8.24 1.12 9.6 6 4.8 1.12 0z"
fill="rgba(73, 73, 73, 1)"
d="M9 1.386L7.648 0 4.5 3.228 1.352 0 0 1.386 4.5 6z"
fill="rgb(151, 151, 151)"
fillRule="evenodd"
opacity=".5"
/>
</svg>
</div>
@ -233,21 +230,20 @@ exports[`Breadcrumb Default Breadcrumb 1`] = `
</h2>
<svg
className="c6 "
height="10"
height="6"
style={
Object {
"transform": "rotate(0deg)",
"transform": "rotate(-90deg)",
}
}
viewBox="0 0 6 10"
width="6"
viewBox="0 0 9 6"
width="9"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.12 0L0 1.36 3.496 4.8 0 8.24 1.12 9.6 6 4.8 1.12 0z"
fill="rgba(73, 73, 73, 1)"
d="M9 1.386L7.648 0 4.5 3.228 1.352 0 0 1.386 4.5 6z"
fill="rgb(151, 151, 151)"
fillRule="evenodd"
opacity=".5"
/>
</svg>
</div>
@ -282,7 +278,7 @@ exports[`Breadcrumb Default Item 1`] = `
}
.c2 {
margin: 0.5rem 0.625rem 0.1875rem 0.625rem;
margin: 0.1875rem 0.625rem;
}
.c0 {
@ -307,21 +303,20 @@ exports[`Breadcrumb Default Item 1`] = `
</h2>
<svg
className="c2 "
height="10"
height="6"
style={
Object {
"transform": "rotate(0deg)",
"transform": "rotate(-90deg)",
}
}
viewBox="0 0 6 10"
width="6"
viewBox="0 0 9 6"
width="9"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.12 0L0 1.36 3.496 4.8 0 8.24 1.12 9.6 6 4.8 1.12 0z"
fill="rgba(73, 73, 73, 1)"
d="M9 1.386L7.648 0 4.5 3.228 1.352 0 0 1.386 4.5 6z"
fill="rgb(151, 151, 151)"
fillRule="evenodd"
opacity=".5"
/>
</svg>
</div>

View File

@ -1,17 +1,17 @@
import React from 'react';
import styled from 'styled-components';
import styled, { withTheme } from 'styled-components';
import remcalc from 'remcalc';
import { H2 } from '../text/headings';
import { Chevron } from '../icons';
import { Arrow as BaseArrow } from '../icons';
const Name = H2.extend`
color: ${props => props.theme.primary};
margin: ${remcalc(12)} 0;
`;
const Arrow = styled(Chevron)`
margin: ${remcalc(8)} ${remcalc(10)} ${remcalc(3)} ${remcalc(10)};
const Arrow = styled(BaseArrow)`
margin: ${remcalc(3)} ${remcalc(10)};
`;
const Container = styled.div`
@ -31,7 +31,7 @@ const BaseLink = styled(({ component, children, ...rest }) =>
}
`;
export default ({ children, component, ...rest }) => {
export default withTheme(({ children, component, theme, ...rest }) => {
const _child = component ? (
<BaseLink {...rest} component={component}>
{children}
@ -43,7 +43,7 @@ export default ({ children, component, ...rest }) => {
return (
<Container>
<Name name="breadcrum-item">{_child}</Name>
<Arrow />
<Arrow direction="left" fill={theme.greyDark} />
</Container>
);
};
});

View File

@ -13,8 +13,6 @@ exports[`Card Card With Header 1`] = `
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
height: auto;
min-height: 7.8125rem;
position: relative;
border-width: 0.0625rem;
border-style: solid;
@ -37,8 +35,6 @@ exports[`Card Card With Header 1`] = `
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
height: auto;
min-height: 7.8125rem;
position: relative;
border-width: 0.0625rem;
border-style: solid;
@ -97,8 +93,6 @@ exports[`Card Default Card 1`] = `
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
height: auto;
min-height: 7.8125rem;
position: relative;
border-width: 0.0625rem;
border-style: solid;
@ -131,8 +125,6 @@ exports[`Card Disabled Card 1`] = `
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
height: auto;
min-height: 7.8125rem;
position: relative;
border-width: 0.0625rem;
border-style: solid;
@ -169,8 +161,6 @@ exports[`Card Secondary Card 1`] = `
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
height: auto;
min-height: 7.8125rem;
position: relative;
border-width: 0.0625rem;
border-style: solid;
@ -206,8 +196,6 @@ exports[`Card Shadow Card 1`] = `
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
height: auto;
min-height: 7.8125rem;
position: relative;
border-width: 0.0625rem;
border-style: solid;

View File

@ -22,8 +22,6 @@ export const BaseCard = styled.div`
flex: 1 0 auto;
flex-direction: column;
height: auto;
min-height: ${remcalc(125)};
position: relative;
border-width: ${remcalc(1)};

View File

@ -42,8 +42,8 @@ const BaseHeader = BaseCard.extend`
`;
const BaseBox = BaseCard.extend`
width: ${remcalc(49)};
min-width: ${remcalc(49)};
width: ${remcalc(46)};
min-width: ${remcalc(46)};
min-height: ${remcalc(46)};
display: inline-flex;
@ -85,7 +85,6 @@ const BaseMeta = BaseCard.extend`
min-height: ${remcalc(47)};
width: auto;
height: auto;
padding: ${remcalc(12)};
display: inline-flex;
flex: 1 1 auto;
@ -141,7 +140,7 @@ Box.defaultProps = {
border: null
};
export const Meta = ({ children, ...rest }) => (
export const Meta = Baseline(({ children, ...rest }) => (
<Subscriber channel="card">
{value => (
<BaseMeta {...rest} {...value} name="card-header-meta" collapsed>
@ -149,7 +148,7 @@ export const Meta = ({ children, ...rest }) => (
</BaseMeta>
)}
</Subscriber>
);
));
const Header = ({ children, transparent, shadow, ...rest }) => {
const render = ({ secondary, tertiary, collapsed, actionable, ...value }) => {

View File

@ -14,13 +14,8 @@ const BaseOutlet = BaseCard.extend`
flex: 1 1 auto;
flex-direction: column;
border-width: 0;
padding: ${remcalc(12)};
margin-bottom: 0;
${is('big')`
padding: ${remcalc(24)};
`};
background-color: transparent;
${is('collapsed')`

View File

@ -164,10 +164,7 @@ exports[`Form Checkbox 1`] = `
/>
</div>
<div
checked={false}
className="c4"
disabled={false}
id=""
>
<label
className="c5"
@ -293,7 +290,7 @@ exports[`Form FormMeta 1`] = `
exports[`Form Input 1`] = `
.c0 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
@ -542,8 +539,6 @@ exports[`Form Radio 1`] = `
</div>
<div
className="c4"
disabled={false}
id=""
>
<label
className="c5"
@ -583,7 +578,7 @@ exports[`Form Select 1`] = `
.c2 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
@ -683,7 +678,7 @@ exports[`Form Select 1`] = `
exports[`Form Textarea 1`] = `
.c1 {
box-sizing: border-box;
width: 100%;
width: 18.75rem;
height: 6rem;
min-height: 6rem;
margin-bottom: 0.5rem;

View File

@ -24,7 +24,7 @@ const paddingTop = props => (props.multiple ? remcalc(20) : remcalc(13));
const style = css`
box-sizing: border-box;
width: 100%;
width: ${remcalc(300)};
height: ${height};
min-height: ${height};

View File

@ -181,7 +181,7 @@ const ToggleBase = ({ container = null, type = 'radio' }) =>
const el = OuterContainer ? (
<OuterContainer {...rest}>
{toggle}
<Container {...rest}>{children}</Container>
{children ? <Container>{children}</Container> : null}
</OuterContainer>
) : (
toggle

View File

@ -6,17 +6,19 @@ import {
Arrow as BaseArrow,
Bin as BaseBin,
Checkcircle as BaseCheckcircle,
Chevron as BaseChevron,
Clipboard as BaseClipboard,
Close as BaseClose,
Cns as BaseCns,
Copy as BaseCopy,
Cpu as BaseCpu,
DataCenter as BaseDataCenter,
Delete as BaseDelete,
Dot as BaseDot,
Duplicate as BaseDuplicate,
Edit as BaseEdit,
Fabric as BaseFabric,
Firewall as BaseFirewall,
General as BaseGeneral,
Health as BaseHealth,
Id as BaseId,
Import as BaseImport,
@ -25,49 +27,44 @@ import {
Instances as BaseInstances,
Loading as BaseLoading,
Login as BaseLogin,
Memory as BaseMemory,
Metadata as BaseMetadata,
Minus as BaseMinus,
Name as BaseName,
Network as BaseNetwork,
Package as BasePackage,
Plus as BasePlus,
Private as BasePrivate,
Public as BasePublic,
Randomize as BaseRandomize,
Reset as BaseReset,
Restart as BaseRestart,
Start as BaseStart,
Stop as BaseStop,
Storage as BaseStorage,
Tags as BaseTags,
Triton as BaseTriton,
User as BaseUser,
Fabric as BaseFabric,
Name as BaseName,
Randomize as BaseRandomize,
Cpu as BaseCpu,
Memory as BaseMemory,
Storage as BaseStorage,
General as BaseGeneral
User as BaseUser
} from 'joyent-icons';
export const General = Baseline(BaseGeneral);
export const Storage = Baseline(BaseStorage);
export const Cpu = Baseline(BaseCpu);
export const Memory = Baseline(BaseMemory);
export const Fabric = Baseline(BaseFabric);
export const Name = Baseline(BaseName);
export const Randomize = Baseline(BaseRandomize);
export const Actions = Baseline(BaseActions);
export const Affinity = Baseline(BaseAffinity);
export const Arrow = Baseline(BaseArrow);
export const Bin = Baseline(BaseBin);
export const Checkcircle = Baseline(BaseCheckcircle);
export const Chevron = Baseline(BaseChevron);
export const Clipboard = Baseline(BaseClipboard);
export const Close = Baseline(BaseClose);
export const Cns = Baseline(BaseCns);
export const Copy = Baseline(BaseCopy);
export const Cpu = Baseline(BaseCpu);
export const DataCenter = Baseline(BaseDataCenter);
export const Delete = Baseline(BaseDelete);
export const Dot = Baseline(BaseDot);
export const Duplicate = Baseline(BaseDuplicate);
export const Edit = Baseline(BaseEdit);
export const Fabric = Baseline(BaseFabric);
export const Firewall = Baseline(BaseFirewall);
export const General = Baseline(BaseGeneral);
export const Health = Baseline(BaseHealth);
export const Id = Baseline(BaseId);
export const Import = Baseline(BaseImport);
@ -76,14 +73,21 @@ export const InstanceType = Baseline(BaseInstanceType);
export const Instances = Baseline(BaseInstances);
export const Loading = Baseline(BaseLoading);
export const Login = Baseline(BaseLogin);
export const Memory = Baseline(BaseMemory);
export const Metadata = Baseline(BaseMetadata);
export const Minus = Baseline(BaseMinus);
export const Name = Baseline(BaseName);
export const Network = Baseline(BaseNetwork);
export const Package = Baseline(BasePackage);
export const Plus = Baseline(BasePlus);
export const Private = Baseline(BasePrivate);
export const Public = Baseline(BasePublic);
export const Randomize = Baseline(BaseRandomize);
export const Reset = Baseline(BaseReset);
export const Restart = Baseline(BaseRestart);
export const Start = Baseline(BaseStart);
export const Stop = Baseline(BaseStop);
export const Storage = Baseline(BaseStorage);
export const Tags = Baseline(BaseTags);
export const Triton = Baseline(BaseTriton);
export const User = Baseline(BaseUser);

View File

@ -73,17 +73,19 @@ export {
Arrow as ArrowIcon,
Bin as BinIcon,
Checkcircle as CheckcircleIcon,
Chevron as ChevronIcon,
Clipboard as ClipboardIcon,
Close as CloseIcon,
Cns as CnsIcon,
Copy as CopyIcon,
Cpu as CpuIcon,
DataCenter as DataCenterIcon,
Delete as DeleteIcon,
Dot as DotIcon,
Duplicate as DuplicateIcon,
Edit as EditIcon,
Fabric as FabricIcon,
Firewall as FirewallIcon,
General as GeneralIcon,
Health as HealthIcon,
Id as IdIcon,
Import as ImportIcon,
@ -92,22 +94,24 @@ export {
Instances as InstancesIcon,
Loading as LoadingIcon,
Login as LoginIcon,
Memory as MemoryIcon,
Metadata as MetadataIcon,
Minus as MinusIcon,
Name as NameIcon,
Network as NetworkIcon,
Package as PackageIcon,
Plus as PlusIcon,
Private as PrivateIcon,
Public as PublicIcon,
Randomize as RandomizeIcon,
Reset as ResetIcon,
Restart as RestartIcon,
Start as StartIcon,
Stop as StopIcon,
Storage as StorageIcon,
Tags as TagsIcon,
Triton as TritonIcon,
User as UserIcon,
Name as NameIcon,
General as GeneralIcon,
Storage as StorageIcon,
Cpu as CpuIcon,
Memory as MemoryIcon
} from './icons';
export {

View File

@ -1872,10 +1872,10 @@ browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
electron-to-chromium "^1.2.7"
browserslist@^2.1.2, browserslist@^2.10.2, browserslist@^2.5.1:
version "2.11.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.0.tgz#50350d6873a82ebe0f3ae5483658c571ae5f9d7d"
version "2.11.1"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.1.tgz#02fda29d9a2164b879100126e7b0d0b57e43a7bb"
dependencies:
caniuse-lite "^1.0.30000784"
caniuse-lite "^1.0.30000789"
electron-to-chromium "^1.3.30"
bser@1.0.2:
@ -2042,12 +2042,12 @@ caniuse-api@^1.5.2:
lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000789"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000789.tgz#5cf3fec75480041ab162ca06413153141e234325"
version "1.0.30000790"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000790.tgz#a8023e6eb9fe9c0ef3d60b4427ce104ea87d381c"
caniuse-lite@^1.0.30000748, caniuse-lite@^1.0.30000784:
version "1.0.30000789"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000789.tgz#2e3d937b267133f63635ef7f441fac66360fc889"
caniuse-lite@^1.0.30000748, caniuse-lite@^1.0.30000784, caniuse-lite@^1.0.30000789:
version "1.0.30000790"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000790.tgz#c954cca780046f34c4b433d324ef419e1db51a53"
capture-stack-trace@^1.0.0:
version "1.0.0"
@ -2196,13 +2196,12 @@ clap@^1.0.9:
chalk "^1.1.3"
class-utils@^0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.5.tgz#17e793103750f9627b2176ea34cfd1b565903c80"
version "0.3.6"
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
dependencies:
arr-union "^3.1.0"
define-property "^0.2.5"
isobject "^3.0.0"
lazy-cache "^2.0.2"
static-extend "^0.1.1"
classnames@^2.2.5:
@ -2392,10 +2391,14 @@ command-join@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/command-join/-/command-join-2.0.0.tgz#52e8b984f4872d952ff1bdc8b98397d27c7144cf"
commander@2.12.x, commander@^2.11.0, commander@^2.9.0, commander@~2.12.1:
commander@2.12.x, commander@~2.12.1:
version "2.12.2"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555"
commander@^2.11.0, commander@^2.9.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
commander@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781"
@ -3268,8 +3271,8 @@ dns-equal@^1.0.0:
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
dns-packet@^1.0.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.2.2.tgz#a8a26bec7646438963fc86e06f8f8b16d6c8bf7a"
version "1.3.0"
resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.0.tgz#7e2b33bf992678a44534c7117d39196bda684d33"
dependencies:
ip "^1.1.0"
safe-buffer "^5.0.1"
@ -3392,9 +3395,9 @@ duplexer@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
duplexify@^3.1.2, duplexify@^3.4.2:
version "3.5.1"
resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.1.tgz#4e1516be68838bc90a49994f0b39a6e5960befcd"
duplexify@^3.4.2, duplexify@^3.5.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.3.tgz#8b5818800df92fd0125b27ab896491912858243e"
dependencies:
end-of-stream "^1.0.0"
inherits "^2.0.1"
@ -3402,12 +3405,13 @@ duplexify@^3.1.2, duplexify@^3.4.2:
stream-shift "^1.0.0"
duplicate-package-checker-webpack-plugin@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/duplicate-package-checker-webpack-plugin/-/duplicate-package-checker-webpack-plugin-2.0.2.tgz#2b01772ec781ec507c8b96615e06deca3552110a"
version "2.1.0"
resolved "https://registry.yarnpkg.com/duplicate-package-checker-webpack-plugin/-/duplicate-package-checker-webpack-plugin-2.1.0.tgz#6723ee32d89947997470778973c10788cb69e496"
dependencies:
chalk "^2.3.0"
find-root "^1.0.0"
lodash "^4.17.4"
semver "^5.4.1"
ecc-jsbn@~0.1.1:
version "0.1.1"
@ -3464,8 +3468,8 @@ encoding@^0.1.11:
iconv-lite "~0.4.13"
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206"
version "1.4.1"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
dependencies:
once "^1.4.0"
@ -6536,8 +6540,8 @@ log-update@^1.0.2:
cli-cursor "^1.0.2"
loglevel@^1.4.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.0.tgz#ae0caa561111498c5ba13723d6fb631d24003934"
version "1.6.1"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.1.tgz#e0fc95133b6ef276cdc8887cdaf24aa6f156f8fa"
longest-streak@^2.0.1:
version "2.0.2"
@ -8031,8 +8035,8 @@ prettier@1.7.4:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.7.4.tgz#5e8624ae9363c80f95ec644584ecdf55d74f93fa"
prettier@^1.7.4:
version "1.10.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.10.1.tgz#01423fea6957ea23618d37d339ef0e7f7c967fc6"
version "1.10.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.10.2.tgz#1af8356d1842276a99a5b5529c82dd9e9ad3cc93"
pretty-bytes@^4.0.2:
version "4.0.2"
@ -8128,13 +8132,20 @@ pump@^1.0.0:
end-of-stream "^1.1.0"
once "^1.3.1"
pumpify@^1.3.3:
version "1.3.5"
resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.3.5.tgz#1b671c619940abcaeac0ad0e3a3c164be760993b"
pump@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.0.tgz#7946da1c8d622b098e2ceb2d3476582470829c9d"
dependencies:
duplexify "^3.1.2"
inherits "^2.0.1"
pump "^1.0.0"
end-of-stream "^1.1.0"
once "^1.3.1"
pumpify@^1.3.3:
version "1.3.6"
resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.3.6.tgz#00d40e5ded0a3bf1e0788b1c0cf426a42882ab64"
dependencies:
duplexify "^3.5.3"
inherits "^2.0.3"
pump "^2.0.0"
punycode@1.3.2:
version "1.3.2"
@ -8250,8 +8261,8 @@ randomatic@^1.1.3:
kind-of "^4.0.0"
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79"
version "2.0.6"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.6.tgz#d302c522948588848a8d300c932b44c24231da80"
dependencies:
safe-buffer "^5.1.0"
@ -8594,7 +8605,7 @@ react@16.2.0, react@^0.14.0, react@^15.5.4, react@^16.2.0:
read-all-stream@^3.0.0:
version "3.1.0"
resolved "http://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa"
resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa"
dependencies:
pinkie-promise "^2.0.0"
readable-stream "^2.0.0"
@ -10115,8 +10126,8 @@ stylelint@^8.4.0:
table "^4.0.1"
stylis@^3.0.0, stylis@^3.4.0:
version "3.4.7"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.4.7.tgz#4fa57ef276d1ed20aafda4e1a97c35b5b87d59ce"
version "3.4.8"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.4.8.tgz#94380babbcd4c75726215794ca985b38ec96d1a3"
sugarss@^1.0.0:
version "1.0.1"