feat(create-instance): affinity prototype

This commit is contained in:
Sara Vieira 2017-11-22 12:13:33 +00:00 committed by Sérgio Ramos
parent 48b9aef8cb
commit 36de79324b
22 changed files with 677 additions and 217 deletions

View File

@ -11,6 +11,8 @@ import Card, { BaseCard } from './card';
const BaseHeader = BaseCard.extend`
flex-direction: row;
z-index: 1;
line-height: ${remcalc(24)};
height: auto;
margin: ${remcalc(-1)} ${remcalc(-1)} 0 ${remcalc(-1)};
@ -47,15 +49,14 @@ const BaseHeader = BaseCard.extend`
const BaseBox = BaseCard.extend`
width: ${remcalc(49)};
min-width: ${remcalc(49)};
height: ${remcalc(46)};
min-height: ${remcalc(46)};
display: inline-flex;
flex: 0 0 ${remcalc(49)};
flex: 0 0 auto;
flex-direction: column;
justify-content: center;
align-items: center;
transition: background-color 0ms ease;
background-color: transparent;
border-width: 0;
border-radius: 0;
@ -85,9 +86,9 @@ const BaseBox = BaseCard.extend`
const BaseMeta = BaseCard.extend`
box-sizing: border-box;
height: ${remcalc(47)};
min-height: ${remcalc(47)};
width: auto;
min-width: auto;
height: auto;
padding: ${remcalc(12)};
display: inline-flex;

View File

@ -50,6 +50,10 @@ const style = css`
color: rgba(73, 73, 73, 0.5);
}
&:invalid {
box-shadow: none;
}
${is('disabled')`
background-color: ${props => props.theme.disabled};
color: ${props => props.theme.textDisabled};
@ -99,6 +103,19 @@ const style = css`
border-color: ${props => props.theme.redDark}
`};
${is('embedded')`
border: none;
border-bottom: ${remcalc(1)} solid ${props => props.theme.text};
border-radius: 0;
background: transparent;
padding: 0;
padding-right: ${remcalc(12)};
display: inline;
height: ${remcalc(24)};
appearance: none;
min-height: 0;
`};
${is('warning')`
border-color: ${props => props.theme.orangeDark}
`};

View File

@ -8,6 +8,10 @@ const InputDropdown = styled.div`
border-radius: ${remcalc(4)};
margin-bottom: ${remcalc(8)};
margin-top: ${remcalc(8)};
&:hover {
border: ${remcalc(1)} solid ${props => props.theme.primary};
}
`;
export default InputDropdown;

View File

@ -33,6 +33,17 @@ const SelectWrapper = styled.div`
right: ${remcalc(12)};
}
${is('embedded')`
margin: 0 ${remcalc(6)};
&:after {
right: ${remcalc(0)};
}
`};
${is('embedded', 'left')`
margin-left: 0;
`};
${is('disabled')`
&:after {
background: url(${chevronDisabled}) center center no-repeat;
@ -51,6 +62,19 @@ const StyledSelect = select.extend`
color: ${props => props.theme.grey};
`};
${is('embedded')`
border: none;
border-bottom: ${remcalc(1)} solid ${props => props.theme.text};
border-radius: 0;
background: transparent;
padding: 0;
padding-right: ${remcalc(12)};
display: inline;
height: ${remcalc(24)};
appearance: none;
min-height: 0;
`};
${is('wrapped')`
margin: 0;
border: none;
@ -68,7 +92,7 @@ const StyledSelect = select.extend`
* @example ./usage-select.md
*/
const Select = ({ children, fluid, ...rest }) => (
<SelectWrapper fluid={fluid}>
<SelectWrapper fluid={fluid} {...rest}>
<StyledSelect {...rest} fluid={fluid}>
{children}
</StyledSelect>

View File

@ -0,0 +1,6 @@
// eslint-disable-next-line no-unused-vars
import React from 'react';
import AffinityIcon from './svg/affinity.svg';
export default AffinityIcon;

View File

@ -24,3 +24,5 @@ export { default as PartCompletedIcon } from './part-complete';
export { default as IncompleteIcon } from './incomplete';
export { default as LoadingIcon } from './loading';
export { default as ImportIcon } from './import';
export { default as AffinityIcon } from './affinity';
export { default as PackageIcon } from './package';

View File

@ -0,0 +1,6 @@
// eslint-disable-next-line no-unused-vars
import React from 'react';
import PackageIcon from './svg/package.svg';
export default PackageIcon;

View File

@ -0,0 +1,3 @@
<svg width="27" height="18" viewBox="0 0 27 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path fill="#494949" fill-rule="evenodd" d="M 13.5039 16.7949C 12.1797 17.5625 10.6406 18 9 18C 4.03125 18 0 13.9707 0 9C 0 4.0293 4.03125 0 9 0C 10.6406 0 12.1797 0.4375 13.5039 1.20508C 14.8281 0.4375 16.3594 0 18 0C 22.9688 0 27 4.0293 27 9C 27 13.9707 22.9688 18 18 18C 16.3594 18 14.8281 17.5625 13.5039 16.7949ZM 11.7266 15.4492C 10.8906 15.8027 9.96875 16 9 16C 7.19531 16 5.55078 15.3164 4.30859 14.1953C 2.89062 12.9141 2 11.0605 2 9C 2 7.86133 2.27344 6.78516 2.75781 5.83398C 3.91016 3.55859 6.27344 2 9 2C 9.96484 2 10.8828 2.19531 11.7188 2.54883C 10.043 4.18359 9 6.47656 9 9C 9 11.5332 10.043 13.8145 11.7266 15.4492ZM 13.5 14.3613C 13.168 14.082 12.8594 13.7715 12.582 13.4355C 11.5938 12.2285 11 10.6836 11 9C 11 6.84766 11.9805 4.92969 13.5078 3.64453C 15.0312 4.92773 16 6.84961 16 9C 16 11.1523 15.0273 13.0762 13.5 14.3613ZM 15.2852 15.4395C 16.1211 15.791 17.0352 16 18 16C 21.8672 16 25 12.8652 25 9C 25 5.13477 21.8672 2 18 2C 17.0312 2 16.1016 2.1875 15.2656 2.54102C 16.9492 4.17578 18 6.4668 18 9C 18 11.5234 16.9609 13.8047 15.2852 15.4395Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="22" viewBox="0 0 24 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path fill="#494949" fill-rule="evenodd" d="M 10.1387 0.000962711C 10.0979 0.00784194 10.0579 0.0194454 10.0197 0.035497L 1.5726 3.37669C 1.2804 3.49228 1.14214 3.89611 1.30066 4.17097L 2.9408 6.97688L 0.17042 9.40292C -0.112742 9.64681 -0.0283339 10.1916 0.314877 10.3353L 3.10225 11.5095L 3.10225 17.3026C 3.11612 17.6517 3.25796 17.8121 3.53566 17.9329L 12.9006 21.6194C 13.0356 21.6744 13.1926 21.6713 13.3255 21.6108L 21.3392 17.907C 21.6256 17.7472 21.6758 17.6281 21.7046 17.3027L 21.7046 11.734L 23.1662 10.9311C 23.4139 10.7939 23.5186 10.4423 23.3872 10.1886L 21.832 7.19279L 23.8631 5.0603C 24.1168 4.79718 24.0002 4.27878 23.6591 4.15378L 14.8126 0.924822C 14.7605 0.907997 14.7058 0.899242 14.6512 0.898938C 14.5242 0.892418 14.3954 0.932933 14.2942 1.01117L 12.0933 2.75515L 10.6911 0.268688C 10.589 0.0956018 10.3878 -0.0118135 10.1897 0.00104702C 10.1728 0.000218201 10.1557 0.000218201 10.1387 0.00104702L 10.1387 0.000962711ZM 9.97721 1.23556L 11.1584 3.31625L 3.87559 6.39843L 2.56689 4.17097L 9.97721 1.23556ZM 14.7276 2.07302L 22.4949 4.90483L 21.0162 6.45024L 13.028 3.41122L 14.7276 2.07302ZM 11.9488 4.17961L 19.7415 7.14955L 13.0875 10.2231L 5.09931 7.08049L 11.9488 4.17961ZM 3.73962 7.73664L 12.0082 10.9829L 9.44185 13.0031L 1.54711 9.66192L 3.73962 7.73664ZM 20.9142 7.81434L 22.1719 10.2231L 15.518 13.8837L 13.8778 11.0692L 20.9142 7.81434ZM 12.5606 11.9498L 12.5606 20.2985L 4.19001 17.0005L 4.19001 11.9757L 9.32285 14.1427C 9.49675 14.216 9.70786 14.1887 9.85824 14.0737L 12.5606 11.9498ZM 20.6168 12.3383L 20.6168 17.0264L 13.6484 20.2467L 13.6484 12.8563L 14.8466 14.9025C 14.9874 15.1483 15.3318 15.246 15.5774 15.1097L 20.6168 12.3383Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -4,7 +4,7 @@ export { default as Baseline } from './baseline';
export { default as Button } from './button';
export { default as Label } from './label';
export { PageContainer, RootContainer, ViewContainer } from './layout';
export { H1, H2, H3, H4, H5 } from './text/headings';
export { H1, H2, H3, H4, H5, H6 } from './text/headings';
export { default as P } from './text/p';
export { default as Small } from './text/small';
export { default as Title } from './text/title';
@ -113,7 +113,9 @@ export {
PartCompletedIcon,
IncompleteIcon,
LoadingIcon,
ImportIcon
ImportIcon,
AffinityIcon,
PackageIcon
} from './icons';
export {

View File

@ -247,6 +247,10 @@ const BaseTr = styled.tr`
box-shadow: 0 ${remcalc(2)} 0 rgba(0, 0, 0, 0.05);
box-sizing: border-box;
&:last-child {
box-shadow: none;
}
${is('selected')`
box-shadow: none;
td {

View File

@ -2,6 +2,7 @@ import styled from 'styled-components';
import { H1 as NH1 } from 'normalized-styled-components';
import remcalc from 'remcalc';
import typography from '../typography';
import is from 'styled-is';
export const H1 = NH1.extend`
margin: 0;
@ -14,6 +15,10 @@ export const H1 = NH1.extend`
font-style: normal;
font-stretch: normal;
${is('inline')`
display: inline-block;
`};
& + p,
& + small,
& + h1,
@ -36,6 +41,10 @@ export const H2 = styled.h2`
line-height: ${remcalc(30)};
font-size: ${remcalc(24)};
${is('inline')`
display: inline-block;
`};
& + p,
& + small,
& + h1,
@ -58,6 +67,10 @@ export const H3 = styled.h3`
line-height: ${remcalc(26)};
font-size: ${remcalc(21)};
${is('inline')`
display: inline-block;
`};
& + p,
& + small,
& + h1,
@ -80,6 +93,10 @@ export const H4 = styled.h4`
line-height: ${remcalc(24)};
font-size: ${remcalc(15)};
${is('inline')`
display: inline-block;
`};
& + p,
& + small,
& + h1,
@ -102,6 +119,37 @@ export const H5 = styled.h4`
line-height: ${remcalc(24)};
font-size: ${remcalc(15)};
${is('inline')`
display: inline-block;
`};
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(12)};
}
`;
export const H6 = styled.h6`
margin: 0;
${typography.color};
${typography.fontFamily};
${typography.normal};
line-height: ${remcalc(18)};
font-size: ${remcalc(13)};
${is('inline')`
display: inline-block;
`};
& + p,
& + small,
& + h1,

View File

@ -17,6 +17,7 @@
"prepublish": "echo 0"
},
"dependencies": {
"animate-css-styled-components": "^0.0.20",
"apollo": "^0.2.2",
"graphql-tag": "^2.5.0",
"joyent-ui-toolkit": "^2.0.1",
@ -32,6 +33,7 @@
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-styled-flexboxgrid": "^2.1.1",
"recompose": "^0.26.0",
"redux": "^3.7.2",
"redux-form": "^7.1.2",
"remcalc": "^1.0.9",

View File

@ -5,6 +5,7 @@ import { ApolloProvider } from 'react-apollo';
import { client, store } from '@state/store';
import Router from '@root/router';
import remcalc from 'remcalc';
const fullTheme = {
...theme,
@ -26,15 +27,18 @@ const fullTheme = {
}
},
spacing: {
0.5: '4px',
0: '0px',
1: '6px',
2: '12px',
3: '18px',
4: '24px',
5: '30px',
6: '36px',
10: '60px'
0.5: remcalc(4),
0: remcalc(0),
1: remcalc(6),
2: remcalc(12),
3: remcalc(18),
4: remcalc(24),
5: remcalc(30),
6: remcalc(36),
7: remcalc(42),
8: remcalc(48),
9: remcalc(54),
10: remcalc(60)
}
};

View File

@ -2,42 +2,191 @@ import React from 'react';
import styled from 'styled-components';
import remcalc from 'remcalc';
import { Row, Col } from 'react-styled-flexboxgrid';
import { compose, withState } from 'recompose';
import { Margin } from 'styled-components-spacing';
import { FadeIn, SlideInDown } from 'animate-css-styled-components';
import {
CardOutlet,
CardHeader,
CardHeaderMeta,
Card,
ArrowIcon
ArrowIcon,
Input,
Button,
Select,
H5
} from 'joyent-ui-toolkit';
const MarginInline = styled(Margin)`
display: inline;
`;
const capitalizeFirstLetter = string =>
string.charAt(0).toUpperCase() + string.slice(1);
const FullWidthCard = styled(Card)`
flex-basis: 100%;
margin-bottom: ${remcalc(18)};
overflow: hidden;
height: auto;
`;
const enhance = compose(withState('open', 'toggleCard', true));
const ListRules = ({ rule }) => (
<FullWidthCard shadow collapsed>
<CardHeader secondary={false} transparent={false}>
<CardHeaderMeta>
<Row between="xs" middle="xs">
<Col xs={11}>
<b>{capitalizeFirstLetter(rule.instance)}</b>
{`: be on ${rule.be} node as the instance(s) identified by the ${
rule.type
} ${rule.match} "${rule.value}"`}
</Col>
<Col xs={1}>
<ArrowIcon />
</Col>
</Row>
</CardHeaderMeta>
</CardHeader>
<CardOutlet>Stuff</CardOutlet>
</FullWidthCard>
const ListRules = ({ rule, open, toggleCard, updateRule, deleteRule }) => (
<FadeIn duration="0.8s">
<FullWidthCard shadow collapsed={open}>
<CardHeader
onClick={() => toggleCard(n => !n)}
actionable
secondary={false}
transparent={false}
>
<CardHeaderMeta>
<Row between="xs" middle="xs">
<Col xs={11}>
<b>{capitalizeFirstLetter(rule.instance)}</b>
{`: be on ${rule.be} node as the instance(s) identified by the `}
{!rule.tagKey
? `${rule.type} ${rule.match} "${rule.value}"`
: `tag key ${rule.tagKeyType} "${rule.tagKey}" and tag value ${rule.tagValueType} "${rule.tagValue}"`}
</Col>
<Col>
<ArrowIcon />
</Col>
</Row>
</CardHeaderMeta>
</CardHeader>
<CardOutlet>
<SlideInDown duration="0.5s">
<div>
<H5 inline>The instance</H5>
<Select
fluid
embedded
value={rule.instance}
onChange={e => updateRule({ ...rule, instance: e.target.value })}
>
<option>must</option>
<option>should</option>
</Select>
<H5 inline>be on</H5>
<Select
fluid
embedded
value={rule.be}
onChange={e => updateRule({ ...rule, be: e.target.value })}
>
<option>the same</option>
<option>a different</option>
</Select>
<H5 inline>node as the instance(s) identified by the</H5>
<div>
<Select
fluid
embedded
left
value={rule.type}
onChange={e => updateRule({ ...rule, type: e.target.value })}
>
<option>instance name</option>
<option>tag</option>
</Select>
{rule.type === 'instance name'
? [
<MarginInline right={1}>
<Select
fluid
embedded
value={rule.match}
onChange={e =>
updateRule({ ...rule, match: e.target.value })}
>
<option>containing</option>
<option>equalling</option>
<option>not equalling</option>
<option>starting with</option>
<option>ending with</option>
</Select>
</MarginInline>,
<Input
embedded
type="text"
required
value={rule.value}
onChange={e =>
updateRule({ ...rule, value: e.target.value })}
placeholder="Example instance name: nginx"
/>
]
: [
<MarginInline right={1}>
<Select
fluid
embedded
value={rule.tagKeyType}
onChange={e =>
updateRule({ ...rule, tagKeyType: e.target.value })}
>
<option>equalling</option>
<option>not equalling</option>
<option>containing</option>
<option>starting with</option>
<option>ending with</option>
</Select>
</MarginInline>,
<Input
small
embedded
type="text"
required
value={rule.tagKey}
onChange={e =>
updateRule({ ...rule, tagKey: e.target.value })}
placeholder="key"
/>,
<H5 inline>and value</H5>,
<MarginInline right={1}>
<Select
fluid
embedded
value={rule.tagValueType}
onChange={e =>
updateRule({ ...rule, tagValueType: e.target.value })}
>
<option>equalling</option>
<option>not equalling</option>
<option>containing</option>
<option>starting with</option>
<option>ending with</option>
</Select>
</MarginInline>,
<Input
small
embedded
type="text"
required
onChange={e =>
updateRule({ ...rule, tagValue: e.target.value })}
value={rule.tagValue}
placeholder="value"
/>
]}
</div>
<div>
<Button secondary onClick={() => toggleCard(n => !n)}>
Cancel
</Button>
<Button secondary onClick={() => deleteRule(rule.id)}>
Delete
</Button>
<Button onClick={() => toggleCard(n => !n)}>Edit</Button>
</div>
</div>
</SlideInDown>
</CardOutlet>
</FullWidthCard>
</FadeIn>
);
export default ListRules;
export default enhance(ListRules);

View File

@ -6,35 +6,35 @@ import remcalc from 'remcalc';
import { Margin } from 'styled-components-spacing';
import ListRules from './List';
import CreateRule from './rule';
import {
ViewContainer,
H2,
Input,
Button,
H4,
CardOutlet,
Select,
CardHeader,
CardHeaderMeta,
Card,
P
} from 'joyent-ui-toolkit';
const MarginInline = styled(Margin)`
display: inline;
`;
import { AffinityIcon, H6, Divider, Button, P } from 'joyent-ui-toolkit';
import { FadeIn } from 'animate-css-styled-components';
const RowMargin = styled(Row)`
margin-top: ${remcalc(-24)};
`;
const Flex = styled.div`
display: flex;
align-items: center;
margin-bottom: ${remcalc(8)};
svg {
margin-right: ${remcalc(6)};
}
`;
const defaultValues = {
instance: 'must',
be: 'the same',
type: 'instance name',
match: 'equalling',
value: null
value: null,
tagValue: null,
tagKey: null,
tagKeyType: 'equaling',
tagValueType: 'equaling'
};
class Affinity extends Component {
@ -78,6 +78,30 @@ class Affinity extends Component {
rule: { ...this.state.rule, value: e.target.value, id: rndId() }
});
tagKeyChange = e =>
this.setState({
...this.state,
rule: { ...this.state.rule, tagKey: e.target.value }
});
tagValueChange = e =>
this.setState({
...this.state,
rule: { ...this.state.rule, tagValue: e.target.value }
});
tagKeyTypeChange = e =>
this.setState({
...this.state,
rule: { ...this.state.rule, tagKeyType: e.target.value }
});
tagValueTypeChange = e =>
this.setState({
...this.state,
rule: { ...this.state.rule, tagValueType: e.target.value }
});
submit = () =>
this.setState({
...this.state,
@ -91,18 +115,29 @@ class Affinity extends Component {
open = id => this.setState({ open: this.state.open.push(id) });
render = () => [
<Row>
<Col xs={12}>
<Margin bottom={6}>
<H2>Affinity</H2>
</Margin>
</Col>
</Row>,
deleteRule = id =>
this.setState({
...this.state,
rules: this.state.rules.filter(rule => rule.id !== id)
});
updateRule = rule =>
this.setState({
...this.state,
rules: this.state.rules.map(r => {
if (r.id === rule.id) {
r = rule;
}
return r;
})
});
_renderInfo = () => (
<RowMargin>
<Col xs={8}>
<P>
Affinity rules control the location of instances, to help reduce
Affinity rules control the location of instances to help reduce
traffic across networks and keep the workload balanced. With strict
rules, instances are only provisioned when the criteria is met. {' '}
<a href="https://apidocs.joyent.com/docker/features/placement ">
@ -110,97 +145,68 @@ class Affinity extends Component {
</a>
</P>
</Col>
</RowMargin>,
<ViewContainer>
</RowMargin>
);
render = () => {
const { rule, rules, showRuleCreation } = this.state;
return [
<Row>
{this.state.rules.length > 0 &&
this.state.rules.map(rule => [
<H4>Affinity rules</H4>,
<ListRules rule={this.state.rule} />
])}
</Row>
</ViewContainer>,
<Row>
<Col xs={12}>
{this.state.showRuleCreation ? (
<Margin top={2}>
<Card shadow>
<CardHeader secondary={false} transparent={false}>
<CardHeaderMeta>
<Row between="xs" middle="xs">
<Col xs={12}>
<H4>Create an affinity rule</H4>
</Col>
</Row>
</CardHeaderMeta>
</CardHeader>
<CardOutlet>
<div>
<H4>The instance</H4>
</div>
<div>
<Select fluid onChange={this.instanceChange}>
<option>must</option>
<option>should</option>
</Select>
</div>
<div>
<H4>be on</H4>
</div>
<div>
<Select fluid onChange={this.beChange}>
<option>the same</option>
<option>a different</option>
</Select>
</div>
<div>
<H4>node as the instance(s) identified by the</H4>
</div>
<div>
<MarginInline right={1}>
<Select fluid onChange={this.typeChange}>
<option>instance name</option>
<option>tag name</option>
</Select>
</MarginInline>
<MarginInline right={1}>
<Select fluid onChange={this.typeChange}>
<option>equalling</option>
<option>not equalling</option>
<option>containing</option>
<option>starting with</option>
<option>ending with</option>
</Select>
</MarginInline>
<Input
type="text"
onChange={this.valueChange}
required
value={this.state.rule.value}
placeholder="Example instance name: nginx"
<Col xs={12}>
<Margin bottom={6}>
<Flex>
<AffinityIcon />
<H6>Affinity</H6>
</Flex>
<Divider height="1px" />
</Margin>
</Col>
</Row>,
this._renderInfo(),
<Row>
<Col xs={12}>
{rules.length > 0 &&
rules.map(rule => [
<Margin top={2}>
<ListRules
key={rule.id}
rule={rule}
deleteRule={this.deleteRule}
updateRule={this.updateRule}
/>
</div>
<div>
<Button secondary onClick={this.toggleForm}>
Cancel
</Button>
<Button onClick={this.submit} disabled={!this.state.rule.value}>
Create
</Button>
</div>
</CardOutlet>
</Card>
</Margin>
) : (
<Margin top={2}>
<Button secondary bold onClick={this.toggleForm}>
Create affinity rule
</Button>
</Margin>
)}
</Col>
</Row>
];
</Margin>
])}
</Col>
</Row>,
<Row>
<Col xs={12}>
{showRuleCreation ? (
<FadeIn duration="0.8s">
<CreateRule
instanceChange={this.instanceChange}
typeChange={this.typeChange}
matchChange={this.matchChange}
valueChange={this.valueChange}
tagKeyChange={this.tagKeyChange}
tagValueChange={this.tagValueChange}
tagKeyTypeChange={this.tagKeyTypeChange}
tagValueTypeChange={this.tagValueTypeChange}
toggleForm={this.toggleForm}
submit={this.submit}
rule={rule}
/>
</FadeIn>
) : (
<Margin top={2}>
<Button secondary bold onClick={this.toggleForm}>
Create affinity rule
</Button>
</Margin>
)}
</Col>
</Row>
];
};
}
export default Affinity;

View File

@ -0,0 +1,140 @@
import React from 'react';
import { Margin } from 'styled-components-spacing';
import { Row, Col } from 'react-styled-flexboxgrid';
import styled from 'styled-components';
import {
Input,
Button,
H4,
H5,
CardOutlet,
Select,
CardHeader,
CardHeaderMeta,
Card
} from 'joyent-ui-toolkit';
const MarginInline = styled(Margin)`
display: inline;
`;
export default ({
instanceChange,
beChange,
typeChange,
valueChange,
tagKeyChange,
tagValueChange,
toggleForm,
submit,
rule,
tagKeyTypeChange,
tagValueTypeChange,
matchChange
}) => [
<Margin top={2}>
<Card shadow>
<CardHeader secondary={false} transparent={false}>
<CardHeaderMeta>
<Row between="xs" middle="xs">
<Col xs={12}>
<H4>Create an affinity rule</H4>
</Col>
</Row>
</CardHeaderMeta>
</CardHeader>
<CardOutlet>
<div>
<H5 inline>The instance</H5>
<Select fluid embedded onChange={instanceChange}>
<option>must</option>
<option>should</option>
</Select>
<H5 inline>be on</H5>
<Select fluid embedded onChange={beChange}>
<option>the same</option>
<option>a different</option>
</Select>
<H5 inline>node as the instance(s) identified by the</H5>
<div>
<Select fluid embedded left onChange={typeChange}>
<option>instance name</option>
<option>tag</option>
</Select>
{rule.type === 'instance name'
? [
<MarginInline right={1}>
<Select fluid embedded onChange={matchChange}>
<option>containing</option>
<option>equalling</option>
<option>not equalling</option>
<option>starting with</option>
<option>ending with</option>
</Select>
</MarginInline>,
<Input
embedded
type="text"
onChange={valueChange}
required
value={rule.value}
placeholder="Example instance name: nginx"
/>
]
: [
<MarginInline right={1}>
<Select fluid embedded onChange={tagKeyTypeChange}>
<option>equalling</option>
<option>not equalling</option>
<option>containing</option>
<option>starting with</option>
<option>ending with</option>
</Select>
</MarginInline>,
<Input
small
embedded
type="text"
onChange={tagKeyChange}
required
value={rule.tagKey}
placeholder="key"
/>,
<H5 inline>and value</H5>,
<MarginInline right={1}>
<Select fluid embedded onChange={tagValueTypeChange}>
<option>equalling</option>
<option>not equalling</option>
<option>containing</option>
<option>starting with</option>
<option>ending with</option>
</Select>
</MarginInline>,
<Input
small
embedded
type="text"
onChange={tagValueChange}
required
value={rule.tagValue}
placeholder="value"
/>
]}
</div>
<div>
<Button secondary onClick={toggleForm}>
Cancel
</Button>
<Button
onClick={submit}
disabled={!(rule.value || (rule.tagKey && rule.tagValue))}
>
Create
</Button>
</div>
</div>
</CardOutlet>
</Card>
</Margin>
];

View File

@ -15,11 +15,23 @@ import {
FormGroup,
Checkbox,
Label,
H2,
H6,
Divider,
H4,
P
P,
PackageIcon
} from 'joyent-ui-toolkit';
const Flex = styled.div`
display: flex;
align-items: center;
margin-bottom: ${remcalc(8)};
svg {
margin-right: ${remcalc(6)};
}
`;
const FullWidth = styled(Margin)`
width: 100%;
,`;
@ -72,9 +84,13 @@ class Filters extends Component {
return [
<Row>
<Col xs={8}>
<Col xs={12}>
<Margin bottom={6}>
<H2>Package</H2>
<Flex>
<PackageIcon />
<H6>Package</H6>
</Flex>
<Divider height="1px" />
</Margin>
</Col>
</Row>,

View File

@ -9,7 +9,6 @@ import {
BreadcrumbItem,
Anchor,
Button,
Divider,
MessageTitle,
MessageDescription
} from 'joyent-ui-toolkit';
@ -84,11 +83,8 @@ class Home extends Component {
<Col xs={12}>{breadcrumbLinks}</Col>
</Row>,
<Row>
<Col xs={12}>{_msg}</Col>
<Col xs={12}><Margin bottom={7}>{_msg}</Margin></Col>
</Row>,
<Margin vertical={2}>
<Divider height="1px" />
</Margin>,
<Row>
<Col xs={12}>
<Filters

View File

@ -40,7 +40,7 @@ export const returnIcon = group => {
<IconWrapper>
<TooltipContainer hoverable>
<TooltipTarget>
<Margin horizontal={1}>
<Margin horizontal={2}>
<Flex>{icon}</Flex>
</Margin>
</TooltipTarget>

View File

@ -19,7 +19,7 @@ import {
} from 'joyent-ui-toolkit';
const ArrowIconStyled = styled(ArrowIcon)`
margin-left: ${remcalc(6)};
margin-left: ${remcalc(4)};
cursor: pointer;
position: relative;
top: ${remcalc(-3)};
@ -85,64 +85,74 @@ class Packages extends Component {
<TableThead>
<TableTr>
<TableTh selected={ordered === 'name'}>
<Span role="button" onClick={() => this.order('name')}>
Name{' '}
</Span>
{ordered === 'name' && (
<ArrowIconStyled
selected
down={this.state.name}
onClick={() => this.order('name')}
/>
)}
<div>
<Span role="button" onClick={() => this.order('name')}>
Name{' '}
</Span>
{ordered === 'name' && (
<ArrowIconStyled
selected
down={this.state.name}
onClick={() => this.order('name')}
/>
)}
</div>
</TableTh>
<TableTh right xs="100" selected={ordered === 'memory'}>
<Span role="button" onClick={() => this.order('memory')}>
RAM{' '}
</Span>
{ordered === 'memory' && (
<ArrowIconStyled
selected
down={this.state.memory}
onClick={() => this.order('memory')}
/>
)}
<div>
<Span role="button" onClick={() => this.order('memory')}>
RAM{' '}
</Span>
{ordered === 'memory' && (
<ArrowIconStyled
selected
down={this.state.memory}
onClick={() => this.order('memory')}
/>
)}
</div>
</TableTh>
<TableTh right xs="100" selected={ordered === 'disk'}>
<Span role="button" onClick={() => this.order('disk')}>
Disk{' '}
</Span>
{ordered === 'disk' && (
<ArrowIconStyled
selected
down={this.state.disk}
onClick={() => this.order('disk')}
/>
)}
<div>
<Span role="button" onClick={() => this.order('disk')}>
Disk{' '}
</Span>
{ordered === 'disk' && (
<ArrowIconStyled
selected
down={this.state.disk}
onClick={() => this.order('disk')}
/>
)}
</div>
</TableTh>
<TableTh right xs="100" selected={ordered === 'vcpus'}>
<Span role="button" onClick={() => this.order('vcpus')}>
vCPU{' '}
</Span>
{ordered === 'vcpus' && (
<ArrowIconStyled
selected
down={this.state.vcpus}
onClick={() => this.order('vcpus')}
/>
)}
<div>
<Span role="button" onClick={() => this.order('vcpus')}>
vCPU{' '}
</Span>
{ordered === 'vcpus' && (
<ArrowIconStyled
selected
down={this.state.vcpus}
onClick={() => this.order('vcpus')}
/>
)}
</div>
</TableTh>
<TableTh right xs="100" selected={ordered === 'price'}>
<Span role="button" onClick={() => this.order('price')}>
$/hour{' '}
</Span>
{ordered === 'price' && (
<ArrowIconStyled
selected={ordered === 'price'}
down={this.state.price}
onClick={() => this.order('price')}
/>
)}
<div>
<Span role="button" onClick={() => this.order('price')}>
$/hour{' '}
</Span>
{ordered === 'price' && (
<ArrowIconStyled
selected={ordered === 'price'}
down={this.state.price}
onClick={() => this.order('price')}
/>
)}
</div>
</TableTh>
</TableTr>
</TableThead>

View File

@ -279,6 +279,10 @@ amdefine@>=0.0.4:
version "1.0.1"
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
animate-css-styled-components@^0.0.20:
version "0.0.20"
resolved "https://registry.yarnpkg.com/animate-css-styled-components/-/animate-css-styled-components-0.0.20.tgz#bf1a5fa641dd7f98a7c48610bda66844a8b062c4"
anser@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.1.tgz#c3641863a962cebef941ea2c8706f2cb4f0716bd"
@ -2152,6 +2156,10 @@ chalk@~0.5.1:
strip-ansi "^0.3.0"
supports-color "^0.2.0"
change-emitter@^0.1.2:
version "0.1.6"
resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515"
character-entities-html4@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.1.tgz#359a2a4a0f7e29d3dc2ac99bdbe21ee39438ea50"
@ -4139,7 +4147,7 @@ fbemitter@^2.0.0:
dependencies:
fbjs "^0.8.4"
fbjs@^0.8.0, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.9:
fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.9:
version "0.8.16"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
dependencies:
@ -8891,6 +8899,15 @@ rechoir@^0.6.2:
dependencies:
resolve "^1.1.6"
recompose@^0.26.0:
version "0.26.0"
resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.26.0.tgz#9babff039cb72ba5bd17366d55d7232fbdfb2d30"
dependencies:
change-emitter "^0.1.2"
fbjs "^0.8.1"
hoist-non-react-statics "^2.3.1"
symbol-observable "^1.0.4"
recursive-readdir@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.1.tgz#90ef231d0778c5ce093c9a48d74e5c5422d13a99"
@ -10280,7 +10297,7 @@ syllable@^3.0.0:
pluralize "^7.0.0"
trim "0.0.1"
symbol-observable@^1.0.2, symbol-observable@^1.0.3:
symbol-observable@^1.0.2, symbol-observable@^1.0.3, symbol-observable@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"