parent
396af2d2e6
commit
52d651a598
@ -29,6 +29,7 @@
|
||||
"lodash.find": "^4.6.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.includes": "^4.3.0",
|
||||
"lodash.isarray": "^4.0.0",
|
||||
"lodash.isfinite": "^3.3.2",
|
||||
"lodash.isfunction": "^3.0.8",
|
||||
"lodash.isstring": "^4.0.1",
|
||||
|
209
packages/my-joy-beta/src/components/cns.js
Normal file
209
packages/my-joy-beta/src/components/cns.js
Normal file
@ -0,0 +1,209 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
import { Margin, Padding } from 'styled-components-spacing';
|
||||
import Flex, { FlexItem } from 'styled-flex-component';
|
||||
import { Field } from 'redux-form';
|
||||
|
||||
import {
|
||||
P,
|
||||
H3,
|
||||
Card,
|
||||
Divider,
|
||||
TagList,
|
||||
Input,
|
||||
Toggle,
|
||||
Small,
|
||||
Button,
|
||||
FormGroup,
|
||||
FormLabel,
|
||||
PublicIcon,
|
||||
PrivateIcon
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
import Tag from '@components/tags';
|
||||
|
||||
const SmallBordered = styled(Small)`
|
||||
padding-right: ${remcalc(12)};
|
||||
margin-right: ${remcalc(12)};
|
||||
border-right: ${remcalc(1)} solid ${props => props.theme.grey};
|
||||
`;
|
||||
|
||||
export const Header = () => (
|
||||
<Fragment>
|
||||
<H3>Hostnames</H3>
|
||||
<Padding bottom={2}>
|
||||
<P>
|
||||
Default hostnames are automatically generated from both the instance
|
||||
name and any attached networks.
|
||||
</P>
|
||||
</Padding>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
export const Footer = ({ enabled, submitting, onToggle }) => (
|
||||
<Fragment>
|
||||
<Margin bottom={4} top={4}>
|
||||
<FormGroup name="cns-enabled">
|
||||
<Flex alignCenter>
|
||||
<FormLabel>Disabled CNS</FormLabel>
|
||||
<Toggle checked={enabled} onChange={onToggle} disabled={submitting}>
|
||||
Enabled CNS
|
||||
</Toggle>
|
||||
</Flex>
|
||||
</FormGroup>
|
||||
</Margin>
|
||||
{enabled ? (
|
||||
<Margin bottom={4}>
|
||||
<P>*All hostnames listed here will be confirmed after deployment.</P>
|
||||
</Margin>
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
export const HostnamesHeader = () => (
|
||||
<Margin top={4}>
|
||||
<H3>CNS service hostnames</H3>
|
||||
<Padding bottom={3}>
|
||||
<P>
|
||||
CNS service hostnames are created by attaching a CNS service name to one
|
||||
or more instances. You can serve multiple instances under the same
|
||||
hostname by assigning them to a matching CNS service name.
|
||||
</P>
|
||||
</Padding>
|
||||
</Margin>
|
||||
);
|
||||
|
||||
export const AddServiceForm = ({
|
||||
handleSubmit,
|
||||
submitting,
|
||||
disabled,
|
||||
pristine
|
||||
}) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Flex alignEnd>
|
||||
<FormGroup name="name" field={Field}>
|
||||
<FormLabel>Attach to new CNS service name</FormLabel>
|
||||
<Input
|
||||
onBlur={null}
|
||||
type="text"
|
||||
placeholder="Example: mySQLdb"
|
||||
disabled={disabled || submitting}
|
||||
/>
|
||||
</FormGroup>
|
||||
<Margin left={2}>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={disabled || pristine}
|
||||
loading={submitting}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</Margin>
|
||||
</Flex>
|
||||
</form>
|
||||
);
|
||||
|
||||
export const Hostname = ({ values = [], network, service, ...hostname }) => (
|
||||
<Fragment>
|
||||
{values.length ? (
|
||||
<Margin bottom={4}>
|
||||
<Flex>
|
||||
<SmallBordered bold noMargin>
|
||||
{network && service
|
||||
? 'Network CNS service'
|
||||
: network
|
||||
? 'Network'
|
||||
: service ? 'CNS service' : 'Instance name'}{' '}
|
||||
hostname{values.length === 1 ? '' : 's'}
|
||||
</SmallBordered>
|
||||
<FlexItem>
|
||||
<Margin right={1}>
|
||||
{hostname.public ? <PublicIcon /> : <PrivateIcon />}
|
||||
</Margin>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<Small noMargin>{hostname.public ? 'Public' : 'Private'}</Small>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
{values.map(value => (
|
||||
<Input onBlur={null} disabled monospace fluid value={value} />
|
||||
))}
|
||||
</Margin>
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
const DefaultHostnames = ({ hostnames }) => (
|
||||
<Fragment>
|
||||
<Header />
|
||||
<Flex column>
|
||||
{hostnames.map(({ value, ...hostname }) => (
|
||||
<Hostname key={value} value={value} {...hostname} />
|
||||
))}
|
||||
</Flex>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
const CnsHostnames = ({
|
||||
hostnames = [],
|
||||
services = [],
|
||||
onRemoveService = () => null,
|
||||
children = null
|
||||
}) => (
|
||||
<Fragment>
|
||||
<HostnamesHeader />
|
||||
{services.length ? (
|
||||
<Margin bottom={3}>
|
||||
<FormLabel>Existing CNS service name(s)</FormLabel>
|
||||
<Margin top={1}>
|
||||
<TagList>
|
||||
{services.map(value => (
|
||||
<Tag
|
||||
active
|
||||
key={value}
|
||||
value={value}
|
||||
onRemoveClick={
|
||||
onRemoveService && (() => onRemoveService(value))
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</TagList>
|
||||
</Margin>
|
||||
</Margin>
|
||||
) : null}
|
||||
{children}
|
||||
<Margin top={4}>
|
||||
<Flex column>
|
||||
{hostnames.map(({ value, ...hostname }) => (
|
||||
<Hostname key={value} value={value} {...hostname} />
|
||||
))}
|
||||
</Flex>
|
||||
</Margin>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
export default ({
|
||||
hostnames = [],
|
||||
services = [],
|
||||
onRemoveService,
|
||||
children = null
|
||||
}) => (
|
||||
<Card>
|
||||
<Padding all={4} bottom={0}>
|
||||
<DefaultHostnames
|
||||
hostnames={hostnames.filter(({ service }) => !service)}
|
||||
/>
|
||||
<Divider height={remcalc(1)} />
|
||||
<Margin top={4}>
|
||||
<CnsHostnames
|
||||
services={services}
|
||||
hostnames={hostnames.filter(({ service }) => service)}
|
||||
onRemoveService={onRemoveService}
|
||||
>
|
||||
{children}
|
||||
</CnsHostnames>
|
||||
</Margin>
|
||||
</Padding>
|
||||
</Card>
|
||||
);
|
@ -1,95 +0,0 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
import { Margin, Padding } from 'styled-components-spacing';
|
||||
import Flex, { FlexItem } from 'styled-flex-component';
|
||||
import { Field } from 'redux-form';
|
||||
|
||||
import {
|
||||
P,
|
||||
H3,
|
||||
Input,
|
||||
Small,
|
||||
Button,
|
||||
FormGroup,
|
||||
FormLabel,
|
||||
PublicIcon,
|
||||
PrivateIcon
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
const SmallBordered = styled(Small)`
|
||||
padding-right: ${remcalc(12)};
|
||||
margin-right: ${remcalc(12)};
|
||||
border-right: ${remcalc(1)} solid ${props => props.theme.grey};
|
||||
`;
|
||||
|
||||
export const Header = () => (
|
||||
<Fragment>
|
||||
<H3>Hostnames</H3>
|
||||
<Padding bottom={2}>
|
||||
<P>
|
||||
Default hostnames are automatically generated from both the instance
|
||||
name and any attached networks.
|
||||
</P>
|
||||
</Padding>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
export const HostnamesHeader = () => (
|
||||
<Margin top={4}>
|
||||
<H3>CNS service hostnames</H3>
|
||||
<Padding bottom={3}>
|
||||
<P>
|
||||
CNS service hostnames are created by attaching a CNS service name to one
|
||||
or more instances. You can serve multiple instances under the same
|
||||
hostname by assigning them to a matching CNS service name.
|
||||
</P>
|
||||
</Padding>
|
||||
</Margin>
|
||||
);
|
||||
|
||||
export const AddServiceForm = ({ handleSubmit, pristine }) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Flex alignEnd>
|
||||
<FormGroup name="name" field={Field}>
|
||||
<FormLabel>Attach to new CNS service name</FormLabel>
|
||||
<Input onBlur={null} type="text" placeholder="Example: mySQLdb" />
|
||||
</FormGroup>
|
||||
<Margin left={2}>
|
||||
<Button type="submit" disabled={pristine}>
|
||||
Add
|
||||
</Button>
|
||||
</Margin>
|
||||
</Flex>
|
||||
</form>
|
||||
);
|
||||
|
||||
export const Hostname = ({ values = [], network, service, ...hostname }) => (
|
||||
<Fragment>
|
||||
{values.length ? (
|
||||
<Margin bottom={4}>
|
||||
<Flex>
|
||||
<SmallBordered bold noMargin>
|
||||
{network && service
|
||||
? 'Network CNS service'
|
||||
: network
|
||||
? 'Network'
|
||||
: service ? 'CNS service' : 'Instance name'}{' '}
|
||||
hostname{values.length === 1 ? '' : 's'}
|
||||
</SmallBordered>
|
||||
<FlexItem>
|
||||
<Margin right={1}>
|
||||
{hostname.public ? <PublicIcon /> : <PrivateIcon />}
|
||||
</Margin>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<Small noMargin>{hostname.public ? 'Public' : 'Private'}</Small>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
{values.map(value => (
|
||||
<Input onBlur={null} disabled monospace fluid value={value} />
|
||||
))}
|
||||
</Margin>
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
@ -163,13 +163,13 @@ export const KeyValue = ({
|
||||
{initialValues.name ? (
|
||||
<Fragment>
|
||||
{expanded ? (
|
||||
<span>{`${initialValues.name}${type === 'metadata'
|
||||
? '-'
|
||||
: ':'}`}</span>
|
||||
<span>{`${initialValues.name}${
|
||||
type === 'metadata' ? '-' : ':'
|
||||
}`}</span>
|
||||
) : (
|
||||
<b>{`${initialValues.name}${type === 'metadata'
|
||||
? '-'
|
||||
: ':'}`}</b>
|
||||
<b>{`${initialValues.name}${
|
||||
type === 'metadata' ? '-' : ':'
|
||||
}`}</b>
|
||||
)}
|
||||
<span>{initialValues.value}</span>
|
||||
</Fragment>
|
||||
|
@ -398,6 +398,7 @@ Array [
|
||||
|
||||
<a
|
||||
href="https://docs.joyent.com/public-cloud/tags-metadata/metadata"
|
||||
rel="noopener noreferrer"
|
||||
target="__blank"
|
||||
>
|
||||
Read the docs
|
||||
@ -1930,6 +1931,7 @@ Array [
|
||||
|
||||
<a
|
||||
href="https://docs.joyent.com/public-cloud/tags-metadata/metadata"
|
||||
rel="noopener noreferrer"
|
||||
target="__blank"
|
||||
>
|
||||
Read the docs
|
||||
@ -4756,6 +4758,7 @@ Array [
|
||||
|
||||
<a
|
||||
href="https://docs.joyent.com/public-cloud/tags-metadata/metadata"
|
||||
rel="noopener noreferrer"
|
||||
target="__blank"
|
||||
>
|
||||
Read the docs
|
||||
|
@ -547,6 +547,7 @@ Array [
|
||||
|
||||
<a
|
||||
href="https://docs.joyent.com/public-cloud/network/sdn"
|
||||
rel="noopener noreferrer"
|
||||
target="__blank"
|
||||
>
|
||||
Read more
|
||||
@ -963,334 +964,7 @@ Array [
|
||||
/>
|
||||
</div>
|
||||
</div>,
|
||||
.c7 {
|
||||
color: rgba(73,73,73,1);
|
||||
line-height: 1.5rem;
|
||||
font-size: 0.9375rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.c7 + p,
|
||||
.c7 + small,
|
||||
.c7 + h1,
|
||||
.c7 + h2,
|
||||
.c7 + label,
|
||||
.c7 + h3,
|
||||
.c7 + h4,
|
||||
.c7 + h5,
|
||||
.c7 + div,
|
||||
.c7 + span {
|
||||
padding-bottom: 2.25rem;
|
||||
}
|
||||
|
||||
.c0 {
|
||||
box-sizing: border-box;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex: 0 1 auto;
|
||||
-ms-flex: 0 1 auto;
|
||||
flex: 0 1 auto;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-flex-wrap: wrap;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
margin-right: -0.5rem;
|
||||
margin-left: -0.5rem;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
box-sizing: border-box;
|
||||
-webkit-flex: 0 0 auto;
|
||||
-ms-flex: 0 0 auto;
|
||||
flex: 0 0 auto;
|
||||
padding-right: 0.5rem;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.c8 {
|
||||
background-color: rgb(216,216,216);
|
||||
margin: 0;
|
||||
height: 0.0625rem;
|
||||
}
|
||||
|
||||
.c5 {
|
||||
-webkit-order: 0;
|
||||
-ms-flex-order: 0;
|
||||
order: 0;
|
||||
-webkit-flex-basis: auto;
|
||||
-ms-flex-preferred-size: auto;
|
||||
flex-basis: auto;
|
||||
-webkit-box-flex: 0;
|
||||
-webkit-flex-grow: 0;
|
||||
-ms-flex-positive: 0;
|
||||
flex-grow: 0;
|
||||
-webkit-flex-shrink: 1;
|
||||
-ms-flex-negative: 1;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.c12 {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
display: inline-block;
|
||||
margin-top: 1rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.c6 {
|
||||
margin-top: 0.5rem;
|
||||
margin-right: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.c10 {
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
.c9 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-flex-wrap: nowrap;
|
||||
-ms-flex-wrap: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
-webkit-box-pack: start;
|
||||
-webkit-justify-content: flex-start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
-webkit-align-content: stretch;
|
||||
-ms-flex-line-pack: stretch;
|
||||
align-content: stretch;
|
||||
}
|
||||
|
||||
.c4 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-flex-wrap: nowrap;
|
||||
-ms-flex-wrap: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
-webkit-box-pack: start;
|
||||
-webkit-justify-content: flex-start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
-webkit-align-content: stretch;
|
||||
-ms-flex-line-pack: stretch;
|
||||
align-content: stretch;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.c11 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-flex-wrap: nowrap;
|
||||
-ms-flex-wrap: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
-webkit-box-pack: start;
|
||||
-webkit-justify-content: flex-start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
-webkit-align-content: stretch;
|
||||
-ms-flex-line-pack: stretch;
|
||||
align-content: stretch;
|
||||
-webkit-align-items: center;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.c3 {
|
||||
display: inline-block;
|
||||
background-color: rgb(255,255,255);
|
||||
border: 0.0625rem solid rgb(216,216,216);
|
||||
border-radius: 0.25rem;
|
||||
min-width: 18.75rem;
|
||||
}
|
||||
|
||||
@media only screen and (min-width:0em) {
|
||||
.c1 {
|
||||
-webkit-flex-basis: 100%;
|
||||
-ms-flex-preferred-size: 100%;
|
||||
flex-basis: 100%;
|
||||
max-width: 100%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width:48em) {
|
||||
.c1 {
|
||||
-webkit-flex-basis: 66.66666666666667%;
|
||||
-ms-flex-preferred-size: 66.66666666666667%;
|
||||
flex-basis: 66.66666666666667%;
|
||||
max-width: 66.66666666666667%;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
<form>
|
||||
<div
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
className="c1"
|
||||
>
|
||||
<div
|
||||
className="c2"
|
||||
>
|
||||
<div
|
||||
className="c3"
|
||||
>
|
||||
<div
|
||||
className="c4"
|
||||
>
|
||||
<div
|
||||
className="c5"
|
||||
>
|
||||
<div
|
||||
className="c6"
|
||||
>
|
||||
<p
|
||||
className="c7"
|
||||
>
|
||||
name2
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="c5"
|
||||
>
|
||||
<div
|
||||
className="c8 c0"
|
||||
height="0.0625rem"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="c5"
|
||||
>
|
||||
<div
|
||||
className="c6"
|
||||
>
|
||||
<div
|
||||
className="c9"
|
||||
>
|
||||
<div
|
||||
className="c10"
|
||||
>
|
||||
<div
|
||||
className="c5"
|
||||
>
|
||||
<div
|
||||
className="c11"
|
||||
>
|
||||
<div
|
||||
className="c5"
|
||||
>
|
||||
<div
|
||||
className="c12"
|
||||
>
|
||||
<svg
|
||||
className=""
|
||||
height="16"
|
||||
innerRef={undefined}
|
||||
style={
|
||||
Object {
|
||||
"transform": "rotate(0deg)",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 12 16"
|
||||
width="12"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
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"
|
||||
fill="rgba(73, 73, 73, 1)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="c5"
|
||||
>
|
||||
<p
|
||||
className="c7"
|
||||
>
|
||||
Private
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className=""
|
||||
>
|
||||
<div
|
||||
className="c5"
|
||||
>
|
||||
<div
|
||||
className="c11"
|
||||
>
|
||||
<div
|
||||
className="c5"
|
||||
>
|
||||
<div
|
||||
className="c12"
|
||||
>
|
||||
<svg
|
||||
height="13"
|
||||
viewBox="0 0 9 13"
|
||||
width="9"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0,0V13H9V0ZM7,11H2V2H7ZM3,4H6V3H3ZM3,6H6V5H3ZM3,8H6V7H3Z"
|
||||
fill="rgba(73, 73, 73, 1)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="c5"
|
||||
>
|
||||
<p
|
||||
className="c7"
|
||||
>
|
||||
Data center network
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>,
|
||||
<form />,
|
||||
.c0 {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
@ -1535,6 +1209,7 @@ Array [
|
||||
|
||||
<a
|
||||
href="https://docs.joyent.com/public-cloud/network/sdn"
|
||||
rel="noopener noreferrer"
|
||||
target="__blank"
|
||||
>
|
||||
Read more
|
||||
@ -3409,6 +3084,10 @@ Array [
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.c10 {
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
display: inline-block;
|
||||
margin-top: 1rem;
|
||||
@ -3422,10 +3101,6 @@ Array [
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.c10 {
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
.c9 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
@ -3446,29 +3121,6 @@ Array [
|
||||
align-content: stretch;
|
||||
}
|
||||
|
||||
.c4 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-flex-wrap: nowrap;
|
||||
-ms-flex-wrap: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
-webkit-box-pack: start;
|
||||
-webkit-justify-content: flex-start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
-webkit-align-content: stretch;
|
||||
-ms-flex-line-pack: stretch;
|
||||
align-content: stretch;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.c11 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
@ -3493,6 +3145,29 @@ Array [
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.c4 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-flex-wrap: nowrap;
|
||||
-ms-flex-wrap: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
-webkit-box-pack: start;
|
||||
-webkit-justify-content: flex-start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
-webkit-align-content: stretch;
|
||||
-ms-flex-line-pack: stretch;
|
||||
align-content: stretch;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.c3 {
|
||||
display: inline-block;
|
||||
background-color: rgb(255,255,255);
|
||||
|
@ -384,6 +384,7 @@ Array [
|
||||
|
||||
<a
|
||||
href="https://docs.joyent.com/public-cloud/tags-metadata/tags"
|
||||
rel="noopener noreferrer"
|
||||
target="__blank"
|
||||
>
|
||||
Read the docs
|
||||
@ -1889,6 +1890,7 @@ Array [
|
||||
|
||||
<a
|
||||
href="https://docs.joyent.com/public-cloud/tags-metadata/tags"
|
||||
rel="noopener noreferrer"
|
||||
target="__blank"
|
||||
>
|
||||
Read the docs
|
||||
@ -2525,6 +2527,7 @@ Array [
|
||||
|
||||
<a
|
||||
href="https://docs.joyent.com/public-cloud/tags-metadata/tags"
|
||||
rel="noopener noreferrer"
|
||||
target="__blank"
|
||||
>
|
||||
Read the docs
|
||||
|
@ -60,6 +60,7 @@ export const Affinity = ({
|
||||
<a
|
||||
target="__blank"
|
||||
href="https://docs.joyent.com/public-cloud/instances/docker/how/start-containers#controlling-container-placement"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read the docs
|
||||
</a>
|
||||
|
@ -4,37 +4,17 @@ import ReduxForm from 'declarative-redux-form';
|
||||
import { destroy } from 'redux-form';
|
||||
import { connect } from 'react-redux';
|
||||
import get from 'lodash.get';
|
||||
import { Margin, Padding } from 'styled-components-spacing';
|
||||
import Flex from 'styled-flex-component';
|
||||
import { Margin } from 'styled-components-spacing';
|
||||
import { set } from 'react-redux-values';
|
||||
import punycode from 'punycode';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import {
|
||||
CnsIcon,
|
||||
P,
|
||||
Card,
|
||||
H3,
|
||||
Button,
|
||||
FormGroup,
|
||||
FormLabel,
|
||||
Toggle,
|
||||
Divider,
|
||||
TagList,
|
||||
StatusLoader
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
import {
|
||||
Hostname,
|
||||
Header,
|
||||
AddServiceForm,
|
||||
HostnamesHeader
|
||||
} from '@components/create-instance/cns';
|
||||
import { CnsIcon, H3, Button, FormLabel, TagList } from 'joyent-ui-toolkit';
|
||||
|
||||
import Cns, { Footer, AddServiceForm } from '@components/cns';
|
||||
import Tag from '@components/tags';
|
||||
import Title from '@components/create-instance/title';
|
||||
import Description from '@components/description';
|
||||
import getAccount from '@graphql/get-account.gql';
|
||||
import GetAccount from '@graphql/get-account.gql';
|
||||
|
||||
const CNS_FORM = 'create-instance-cns';
|
||||
|
||||
@ -50,8 +30,7 @@ const CNSContainer = ({
|
||||
handleEdit,
|
||||
handleToggleCnsEnabled,
|
||||
handleAddService,
|
||||
handleRemoveService,
|
||||
loading
|
||||
handleRemoveService
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Title onClick={!expanded && !proceeded && handleEdit} icon={<CnsIcon />}>
|
||||
@ -73,81 +52,24 @@ const CNSContainer = ({
|
||||
) : null}
|
||||
<div>
|
||||
{expanded && cnsEnabled ? (
|
||||
<Card>
|
||||
<Padding all={4} bottom={0}>
|
||||
<Header />
|
||||
{loading ? (
|
||||
<Margin all={2}>
|
||||
{' '}
|
||||
<StatusLoader />
|
||||
</Margin>
|
||||
) : (
|
||||
<Flex column>
|
||||
{hostnames
|
||||
.filter(({ service }) => !service)
|
||||
.map(({ value, ...hostname }) => (
|
||||
<Hostname key={value} value={value} {...hostname} />
|
||||
))}
|
||||
</Flex>
|
||||
)}
|
||||
<Divider height={remcalc(1)} />
|
||||
<Margin top={4}>
|
||||
<HostnamesHeader />
|
||||
{serviceNames.length ? (
|
||||
<Margin bottom={3}>
|
||||
<FormLabel>Existing CNS service name(s)</FormLabel>
|
||||
<Margin top={1}>
|
||||
<TagList>
|
||||
{serviceNames.map((value, index) => (
|
||||
<Tag
|
||||
active
|
||||
key={index}
|
||||
value={value}
|
||||
onRemoveClick={() => handleRemoveService(index)}
|
||||
/>
|
||||
))}
|
||||
</TagList>
|
||||
</Margin>
|
||||
</Margin>
|
||||
) : null}
|
||||
<ReduxForm
|
||||
form={`${CNS_FORM}-new-service`}
|
||||
destroyOnUnmount={false}
|
||||
forceUnregisterOnUnmount={true}
|
||||
onSubmit={handleAddService}
|
||||
>
|
||||
{props => <AddServiceForm {...props} />}
|
||||
</ReduxForm>
|
||||
<Margin top={4}>
|
||||
<Flex column>
|
||||
{hostnames
|
||||
.filter(({ service }) => service)
|
||||
.map(({ value, ...hostname }) => (
|
||||
<Hostname key={value} value={value} {...hostname} />
|
||||
))}
|
||||
</Flex>
|
||||
</Margin>
|
||||
</Margin>
|
||||
</Padding>
|
||||
</Card>
|
||||
<Cns
|
||||
hostnames={hostnames}
|
||||
services={serviceNames}
|
||||
onRemoveService={handleRemoveService}
|
||||
>
|
||||
<ReduxForm
|
||||
form={`${CNS_FORM}-new-service`}
|
||||
destroyOnUnmount={false}
|
||||
forceUnregisterOnUnmount={true}
|
||||
onSubmit={handleAddService}
|
||||
>
|
||||
{props => <AddServiceForm {...props} />}
|
||||
</ReduxForm>
|
||||
</Cns>
|
||||
) : null}
|
||||
{expanded ? (
|
||||
<Fragment>
|
||||
<Margin bottom={4} top={4}>
|
||||
<FormGroup name="cns-enabled">
|
||||
<Flex alignCenter>
|
||||
<FormLabel>Disabled CNS</FormLabel>
|
||||
<Toggle checked={cnsEnabled} onChange={handleToggleCnsEnabled}>
|
||||
Enabled CNS
|
||||
</Toggle>
|
||||
</Flex>
|
||||
</FormGroup>
|
||||
</Margin>
|
||||
<Margin bottom={4}>
|
||||
<P>
|
||||
*All hostnames listed here will be confirmed after deployment.
|
||||
</P>
|
||||
</Margin>
|
||||
<Footer enabled={cnsEnabled} onToggle={handleToggleCnsEnabled} />
|
||||
<Margin bottom={4}>
|
||||
<Button type="button" onClick={handleNext}>
|
||||
Next
|
||||
@ -184,9 +106,8 @@ const CNSContainer = ({
|
||||
);
|
||||
|
||||
export default compose(
|
||||
graphql(getAccount, {
|
||||
props: ({ data: { loading, account: { id } = [] } }) => ({
|
||||
loading,
|
||||
graphql(GetAccount, {
|
||||
props: ({ data: { account: { id = '<account-id>' } = [] } }) => ({
|
||||
id
|
||||
})
|
||||
}),
|
||||
@ -252,7 +173,7 @@ export default compose(
|
||||
handleAddService: ({ name }) => {
|
||||
const serviceName = punycode
|
||||
.encode(name.toLowerCase().replace(/\s/g, '-'))
|
||||
.replace(/\-$/, '');
|
||||
.replace(/-$/, '');
|
||||
|
||||
dispatch([
|
||||
destroy(`${CNS_FORM}-new-service`),
|
||||
@ -262,11 +183,12 @@ export default compose(
|
||||
})
|
||||
]);
|
||||
},
|
||||
handleRemoveService: index => {
|
||||
serviceNames.splice(index, 1);
|
||||
|
||||
handleRemoveService: value => {
|
||||
return dispatch(
|
||||
set({ name: `${CNS_FORM}-services`, value: serviceNames.slice() })
|
||||
set({
|
||||
name: `${CNS_FORM}-services`,
|
||||
value: serviceNames.filter(name => name !== value)
|
||||
})
|
||||
);
|
||||
}
|
||||
}))
|
||||
|
@ -43,6 +43,7 @@ const Firewall = ({
|
||||
<a
|
||||
target="__blank"
|
||||
href="https://docs.joyent.com/public-cloud/network/firewall"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read more
|
||||
</a>
|
||||
|
@ -45,6 +45,7 @@ export const Metadata = ({
|
||||
<a
|
||||
target="__blank"
|
||||
href="https://docs.joyent.com/public-cloud/tags-metadata/metadata"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read the docs
|
||||
</a>
|
||||
|
@ -44,6 +44,7 @@ export const Networks = ({
|
||||
<a
|
||||
target="__blank"
|
||||
href="https://docs.joyent.com/public-cloud/network/sdn"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read more
|
||||
</a>
|
||||
@ -65,7 +66,7 @@ export const Networks = ({
|
||||
<form>
|
||||
{networks.map(
|
||||
({ id, selected, infoExpanded, machinesExpanded, ...network }) =>
|
||||
!expanded && !selected ? null : (
|
||||
expanded || (selected && proceeded) ? (
|
||||
<Network
|
||||
key={id}
|
||||
id={id}
|
||||
@ -79,7 +80,7 @@ export const Networks = ({
|
||||
}
|
||||
{...network}
|
||||
/>
|
||||
)
|
||||
) : null
|
||||
)}
|
||||
</form>
|
||||
)}
|
||||
|
@ -42,6 +42,7 @@ export const Tags = ({
|
||||
<a
|
||||
target="__blank"
|
||||
href="https://docs.joyent.com/public-cloud/tags-metadata/tags"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read the docs
|
||||
</a>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,205 @@
|
||||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import 'jest-styled-components';
|
||||
|
||||
import { Cns } from '../cns';
|
||||
import Theme from '@mocks/theme';
|
||||
|
||||
// services = [],
|
||||
// hostnames = [],
|
||||
// disabled = false,
|
||||
// loading = false,
|
||||
// mutationError = false,
|
||||
// loadingError = null
|
||||
|
||||
it('renders <Cns /> without throwing', () => {
|
||||
expect(
|
||||
renderer
|
||||
.create(
|
||||
<Theme>
|
||||
<Cns />
|
||||
</Theme>
|
||||
)
|
||||
.toJSON()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders <Cns loading /> without throwing', () => {
|
||||
expect(
|
||||
renderer
|
||||
.create(
|
||||
<Theme>
|
||||
<Cns loading />
|
||||
</Theme>
|
||||
)
|
||||
.toJSON()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders <Cns loadingError /> without throwing', () => {
|
||||
expect(
|
||||
renderer
|
||||
.create(
|
||||
<Theme>
|
||||
<Cns loadingError />
|
||||
</Theme>
|
||||
)
|
||||
.toJSON()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders <Cns mutationError /> without throwing', () => {
|
||||
expect(
|
||||
renderer
|
||||
.create(
|
||||
<Theme>
|
||||
<Cns mutationError="mutation error" />
|
||||
</Theme>
|
||||
)
|
||||
.toJSON()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders <Cns mutating /> without throwing', () => {
|
||||
const services = ['serbice', 'dssasda', 'dsasd'];
|
||||
|
||||
const hostnames = [
|
||||
{
|
||||
values: ['stuffy-stuff'],
|
||||
public: true
|
||||
},
|
||||
{
|
||||
values: ['stuffy-stuff']
|
||||
},
|
||||
{
|
||||
values: ['serbice', 'dssasda', 'dsasd'],
|
||||
public: true,
|
||||
service: true
|
||||
},
|
||||
{
|
||||
values: ['serbice', 'dssasda', 'dsasd'],
|
||||
service: true
|
||||
}
|
||||
];
|
||||
|
||||
expect(
|
||||
renderer
|
||||
.create(
|
||||
<Theme>
|
||||
<Cns mutating services={services} hostnames={hostnames} />
|
||||
</Theme>
|
||||
)
|
||||
.toJSON()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders <Cns disabled /> without throwing', () => {
|
||||
const services = ['serbice', 'dssasda', 'dsasd'];
|
||||
|
||||
const hostnames = [
|
||||
{
|
||||
values: ['stuffy-stuff'],
|
||||
public: true
|
||||
},
|
||||
{
|
||||
values: ['stuffy-stuff']
|
||||
},
|
||||
{
|
||||
values: ['serbice', 'dssasda', 'dsasd'],
|
||||
public: true,
|
||||
service: true
|
||||
},
|
||||
{
|
||||
values: ['serbice', 'dssasda', 'dsasd'],
|
||||
service: true
|
||||
}
|
||||
];
|
||||
|
||||
expect(
|
||||
renderer
|
||||
.create(
|
||||
<Theme>
|
||||
<Cns disabled services={services} hostnames={hostnames} />
|
||||
</Theme>
|
||||
)
|
||||
.toJSON()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders <Cns services /> without throwing', () => {
|
||||
const services = ['serbice', 'dssasda', 'dsasd'];
|
||||
|
||||
expect(
|
||||
renderer
|
||||
.create(
|
||||
<Theme>
|
||||
<Cns services={services} />
|
||||
</Theme>
|
||||
)
|
||||
.toJSON()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders <Cns hostnames /> without throwing', () => {
|
||||
const hostnames = [
|
||||
{
|
||||
values: ['stuffy-stuff'],
|
||||
public: true
|
||||
},
|
||||
{
|
||||
values: ['stuffy-stuff']
|
||||
},
|
||||
{
|
||||
values: ['serbice', 'dssasda', 'dsasd'],
|
||||
public: true,
|
||||
service: true
|
||||
},
|
||||
{
|
||||
values: ['serbice', 'dssasda', 'dsasd'],
|
||||
service: true
|
||||
}
|
||||
];
|
||||
|
||||
expect(
|
||||
renderer
|
||||
.create(
|
||||
<Theme>
|
||||
<Cns hostnames={hostnames} />
|
||||
</Theme>
|
||||
)
|
||||
.toJSON()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders <Cns services hostnames /> without throwing', () => {
|
||||
const services = ['serbice', 'dssasda', 'dsasd'];
|
||||
|
||||
const hostnames = [
|
||||
{
|
||||
values: ['stuffy-stuff'],
|
||||
public: true
|
||||
},
|
||||
{
|
||||
values: ['stuffy-stuff']
|
||||
},
|
||||
{
|
||||
values: ['serbice', 'dssasda', 'dsasd'],
|
||||
public: true,
|
||||
service: true
|
||||
},
|
||||
{
|
||||
values: ['serbice', 'dssasda', 'dsasd'],
|
||||
service: true
|
||||
}
|
||||
];
|
||||
|
||||
expect(
|
||||
renderer
|
||||
.create(
|
||||
<Theme>
|
||||
<Cns disabled services={services} hostnames={hostnames} />
|
||||
</Theme>
|
||||
)
|
||||
.toJSON()
|
||||
).toMatchSnapshot();
|
||||
});
|
@ -60,7 +60,7 @@ it('renders <Networks networks /> without throwing', () => {
|
||||
fabric: false,
|
||||
subnet: '255.255.255.0',
|
||||
provision_start_ip: '192.168.1.2',
|
||||
provision_end_ip: '192.168.1.253',
|
||||
provision_end_ip: '192.168.1.253'
|
||||
}
|
||||
];
|
||||
|
||||
|
350
packages/my-joy-beta/src/containers/instances/cns.js
Normal file
350
packages/my-joy-beta/src/containers/instances/cns.js
Normal file
@ -0,0 +1,350 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import intercept from 'apr-intercept';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import { connect } from 'react-redux';
|
||||
import { SubmissionError, destroy } from 'redux-form';
|
||||
import ReduxForm from 'declarative-redux-form';
|
||||
import { set, destroy as destroyValue } from 'react-redux-values';
|
||||
import { Margin } from 'styled-components-spacing';
|
||||
import find from 'lodash.find';
|
||||
import isBoolean from 'lodash.isboolean';
|
||||
import isArray from 'lodash.isarray';
|
||||
import get from 'lodash.get';
|
||||
|
||||
import {
|
||||
ViewContainer,
|
||||
StatusLoader,
|
||||
Message,
|
||||
MessageTitle,
|
||||
MessageDescription
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
import Description from '@components/description';
|
||||
import Cns, { Footer, AddServiceForm } from '@components/cns';
|
||||
import GetAccount from '@graphql/get-account.gql';
|
||||
import UpdateTags from '@graphql/update-tags.gql';
|
||||
import GetTags from '@graphql/list-tags.gql';
|
||||
import parseError from '@state/parse-error';
|
||||
|
||||
const CNS_FORM = 'cns-new-service';
|
||||
|
||||
const CnsContainer = ({
|
||||
services = [],
|
||||
hostnames = [],
|
||||
disabled = false,
|
||||
handleToggleCnsEnabled,
|
||||
handleAddService,
|
||||
handleRemoveService,
|
||||
mutating = false,
|
||||
loading = false,
|
||||
mutationError = false,
|
||||
loadingError = null
|
||||
}) => (
|
||||
<ViewContainer main>
|
||||
<Margin bottom={1}>
|
||||
<Description>
|
||||
Triton CNS is used to automatically update hostnames for your
|
||||
instances*. You can serve multiple instances (with multiple IP
|
||||
addresses) under the same hostname by matching the CNS service names.{' '}
|
||||
<a
|
||||
href="https://docs.joyent.com/private-cloud/install/cns"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Read the docs
|
||||
</a>
|
||||
</Description>
|
||||
</Margin>
|
||||
{loading ? <StatusLoader /> : null}
|
||||
{!loading && loadingError ? (
|
||||
<Message error>
|
||||
<MessageTitle>Ooops!</MessageTitle>
|
||||
<MessageDescription>
|
||||
An error occurred while loading your CNS services
|
||||
</MessageDescription>
|
||||
</Message>
|
||||
) : null}
|
||||
{!loading && mutationError ? (
|
||||
<Message error>
|
||||
<MessageTitle>Ooops!</MessageTitle>
|
||||
<MessageDescription>{mutationError}</MessageDescription>
|
||||
</Message>
|
||||
) : null}
|
||||
{!loading && !disabled ? (
|
||||
<Cns
|
||||
services={services}
|
||||
hostnames={hostnames}
|
||||
onRemoveService={
|
||||
!mutating && (name => handleRemoveService(name, services))
|
||||
}
|
||||
>
|
||||
<ReduxForm
|
||||
form={CNS_FORM}
|
||||
destroyOnUnmount={false}
|
||||
forceUnregisterOnUnmount={true}
|
||||
onSubmit={val => handleAddService(val, services)}
|
||||
>
|
||||
{props => <AddServiceForm {...props} disabled={mutating} />}
|
||||
</ReduxForm>
|
||||
</Cns>
|
||||
) : null}
|
||||
{!loading && !loadingError ? (
|
||||
<Footer
|
||||
enabled={!disabled}
|
||||
submitting={mutating}
|
||||
onToggle={() => handleToggleCnsEnabled(!disabled)}
|
||||
/>
|
||||
) : null}
|
||||
</ViewContainer>
|
||||
);
|
||||
|
||||
export { CnsContainer as Cns };
|
||||
|
||||
class CnsClass extends PureComponent {
|
||||
componentWillMount() {
|
||||
const { reset = () => null } = this.props;
|
||||
reset();
|
||||
}
|
||||
render() {
|
||||
const { reset, children, ...rest } = this.props;
|
||||
|
||||
return <CnsContainer {...rest}>{children}</CnsContainer>;
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
graphql(UpdateTags, { name: 'updateTags' }),
|
||||
graphql(GetAccount, {
|
||||
props: ({ data }) => {
|
||||
const { account = {} } = data;
|
||||
const { id = '<account-id>' } = account;
|
||||
|
||||
return { id };
|
||||
}
|
||||
}),
|
||||
graphql(GetTags, {
|
||||
options: ({ match }) => ({
|
||||
variables: {
|
||||
fetchPolicy: 'network-only',
|
||||
name: get(match, 'params.instance')
|
||||
}
|
||||
}),
|
||||
props: ({ data }) => {
|
||||
const { loading, error, variables, refetch, ...rest } = data;
|
||||
const { name } = variables;
|
||||
|
||||
const instance = find(get(rest, 'machines', []), ['name', name]);
|
||||
const tags = get(instance, 'tags', []);
|
||||
|
||||
return {
|
||||
tags,
|
||||
instance,
|
||||
loading,
|
||||
loadingError: error,
|
||||
refetch
|
||||
};
|
||||
}
|
||||
}),
|
||||
connect(
|
||||
({ values, form }, { id, instance = {}, tags = [] }) => {
|
||||
const { name = '<instance-name>' } = instance;
|
||||
|
||||
const cnsDisable = find(tags, ['name', 'triton.cns.disable']) || {};
|
||||
const cnsServices = find(tags, ['name', 'triton.cns.services']) || {};
|
||||
|
||||
let disabled = JSON.parse(cnsDisable.value || 'false');
|
||||
let services = (cnsServices.value || '').split(/,/gi).filter(Boolean);
|
||||
|
||||
const adding = get(form, `${CNS_FORM}.submitting`, false);
|
||||
const toggling = get(values, `cns-${instance.id}-toggling`, false);
|
||||
const removing = get(values, `cns-${instance.id}-removing`, false);
|
||||
const enabled = get(values, `cns-${instance.id}-enabled`, undefined);
|
||||
const togglingError = get(
|
||||
values,
|
||||
`cns-${instance.id}-toggling-error`,
|
||||
null
|
||||
);
|
||||
const removingError = get(
|
||||
values,
|
||||
`cns-${instance.id}-removing-error`,
|
||||
null
|
||||
);
|
||||
const svcs = get(values, `cns-${instance.id}-svcs`, undefined);
|
||||
|
||||
if (isBoolean(enabled)) {
|
||||
disabled = !enabled;
|
||||
}
|
||||
|
||||
if (isArray(svcs)) {
|
||||
services = svcs;
|
||||
}
|
||||
|
||||
// REPLACE WITH DATA CENTER
|
||||
const dataCenter = 'us-east-1';
|
||||
|
||||
const defaultHostnames = [
|
||||
{
|
||||
values: [`${name}.inst.${id}.${dataCenter}.triton.zone`],
|
||||
public: true
|
||||
},
|
||||
{
|
||||
values: [`${name}.inst.${id}.${dataCenter}.cns.joyent.com`]
|
||||
},
|
||||
{
|
||||
values: [],
|
||||
public: true,
|
||||
service: true
|
||||
},
|
||||
{
|
||||
values: [],
|
||||
service: true
|
||||
}
|
||||
];
|
||||
|
||||
const hostnames = defaultHostnames.map(hostname => {
|
||||
if (!hostname.service) {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
return {
|
||||
...hostname,
|
||||
values: services.map(name => {
|
||||
const postfix = hostname.public
|
||||
? '.triton.zone'
|
||||
: '.cns.joyent.com';
|
||||
return `${name}.svc.${id}.${dataCenter}${postfix}`;
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
hostnames,
|
||||
disabled,
|
||||
services,
|
||||
mutating: toggling || removing || adding,
|
||||
mutationError: togglingError || removingError
|
||||
};
|
||||
},
|
||||
(dispatch, { instance = {}, refetch, updateTags }) => ({
|
||||
reset: () => {
|
||||
dispatch([
|
||||
destroyValue({ name: `cns-${instance.id}-removing` }),
|
||||
destroyValue({ name: `cns-${instance.id}-svcs` }),
|
||||
destroyValue({ name: `cns-${instance.id}-removing-error` }),
|
||||
destroyValue({ name: `cns-${instance.id}-toggling` }),
|
||||
destroyValue({ name: `cns-${instance.id}-enabled` }),
|
||||
destroyValue({ name: `cns-${instance.id}-toggling-error` })
|
||||
]);
|
||||
|
||||
return refetch();
|
||||
},
|
||||
handleRemoveService: async (name, services) => {
|
||||
const value = services.filter(svc => name !== svc);
|
||||
|
||||
dispatch([
|
||||
set({ name: `cns-${instance.id}-removing`, value: true }),
|
||||
set({ name: `cns-${instance.id}-svcs`, value })
|
||||
]);
|
||||
|
||||
const [err] = await intercept(
|
||||
updateTags({
|
||||
variables: {
|
||||
id: instance.id,
|
||||
tags: [
|
||||
{
|
||||
name: 'triton.cns.services',
|
||||
value: value.join(',')
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const setLoadingFalse = set({
|
||||
name: `cns-${instance.id}-removing`,
|
||||
value: false
|
||||
});
|
||||
|
||||
if (err) {
|
||||
return dispatch([
|
||||
setLoadingFalse,
|
||||
set({
|
||||
name: `cns-${instance.id}-removing-error`,
|
||||
value: parseError(err)
|
||||
}),
|
||||
set({ name: `cns-${instance.id}-svcs`, value: null })
|
||||
]);
|
||||
}
|
||||
|
||||
return dispatch(setLoadingFalse);
|
||||
},
|
||||
handleToggleCnsEnabled: async disabled => {
|
||||
dispatch([
|
||||
set({ name: `cns-${instance.id}-toggling`, value: true }),
|
||||
set({ name: `cns-${instance.id}-enabled`, value: !disabled })
|
||||
]);
|
||||
|
||||
const [err] = await intercept(
|
||||
updateTags({
|
||||
variables: {
|
||||
id: instance.id,
|
||||
tags: [
|
||||
{
|
||||
name: 'triton.cns.disable',
|
||||
value: disabled ? 'true' : 'false'
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const setLoadingFalse = set({
|
||||
name: `cns-${instance.id}-toggling`,
|
||||
value: false
|
||||
});
|
||||
|
||||
if (err) {
|
||||
return dispatch([
|
||||
setLoadingFalse,
|
||||
set({
|
||||
name: `cns-${instance.id}-toggling-error`,
|
||||
value: parseError(err)
|
||||
}),
|
||||
set({ name: `cns-${instance.id}-enabled`, value: null })
|
||||
]);
|
||||
}
|
||||
|
||||
return dispatch(setLoadingFalse);
|
||||
},
|
||||
handleAddService: async ({ name }, services) => {
|
||||
const value = services.concat(name);
|
||||
|
||||
dispatch(set({ name: `cns-${instance.id}-svcs`, value }));
|
||||
|
||||
const [err] = await intercept(
|
||||
updateTags({
|
||||
variables: {
|
||||
id: instance.id,
|
||||
tags: [
|
||||
{
|
||||
name: 'triton.cns.services',
|
||||
value: value.join(',')
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if (err) {
|
||||
dispatch(set({ name: `cns-${instance.id}-svcs`, services }));
|
||||
|
||||
throw new SubmissionError({
|
||||
_error: parseError(err)
|
||||
});
|
||||
}
|
||||
|
||||
return dispatch(destroy(CNS_FORM));
|
||||
}
|
||||
})
|
||||
)
|
||||
)(CnsClass);
|
@ -1,62 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import find from 'lodash.find';
|
||||
import get from 'lodash.get';
|
||||
|
||||
import {
|
||||
ViewContainer,
|
||||
StatusLoader,
|
||||
Message,
|
||||
MessageDescription,
|
||||
MessageTitle
|
||||
} from 'joyent-ui-toolkit';
|
||||
|
||||
import ListDNS from '@graphql/list-dns.gql';
|
||||
|
||||
const DNS = ({ instance, loading, error }) => {
|
||||
// eslint-disable-next-line camelcase
|
||||
const { name, dns_names } = instance || {};
|
||||
// eslint-disable-next-line camelcase
|
||||
const _loading = loading && !name && !dns_names && <StatusLoader />;
|
||||
const _summary = !_loading &&
|
||||
instance && <pre>{JSON.stringify(dns_names, null, 2)}</pre>;
|
||||
|
||||
const _error = error &&
|
||||
!_loading &&
|
||||
!instance && (
|
||||
<Message error>
|
||||
<MessageTitle>Ooops!</MessageTitle>
|
||||
<MessageDescription>
|
||||
An error occurred while loading your instance DNS
|
||||
</MessageDescription>
|
||||
</Message>
|
||||
);
|
||||
|
||||
return (
|
||||
<ViewContainer center={Boolean(_loading)} main>
|
||||
{_loading}
|
||||
{_error}
|
||||
{_summary}
|
||||
</ViewContainer>
|
||||
);
|
||||
};
|
||||
|
||||
DNS.propTypes = {
|
||||
loading: PropTypes.bool
|
||||
};
|
||||
|
||||
export default compose(
|
||||
graphql(ListDNS, {
|
||||
options: ({ match }) => ({
|
||||
variables: {
|
||||
name: get(match, 'params.instance')
|
||||
}
|
||||
}),
|
||||
props: ({ data: { loading, error, variables, ...rest } }) => ({
|
||||
instance: find(get(rest, 'machines', []), ['name', variables.name]),
|
||||
loading,
|
||||
error
|
||||
})
|
||||
})
|
||||
)(DNS);
|
@ -4,6 +4,6 @@ export { default as Tags } from './tags';
|
||||
export { default as Metadata } from './metadata';
|
||||
export { default as Networks } from './networks';
|
||||
export { default as Firewall } from './firewall';
|
||||
export { default as Dns } from './dns';
|
||||
export { default as Cns } from './cns';
|
||||
export { default as Snapshots } from './snapshots';
|
||||
export { default as Resize } from './resize';
|
||||
|
@ -1,7 +1,4 @@
|
||||
import { connect } from 'react-redux';
|
||||
import paramCase from 'param-case';
|
||||
import titleCase from 'title-case';
|
||||
import isString from 'lodash.isstring';
|
||||
import get from 'lodash.get';
|
||||
|
||||
import { Menu } from '@components/navigation';
|
||||
@ -11,20 +8,10 @@ export default connect((state, { match }) => {
|
||||
const allSections = get(state, 'ui.sections');
|
||||
const sections = instanceSlug ? allSections.instances : [];
|
||||
|
||||
const links = sections
|
||||
.map(
|
||||
section =>
|
||||
!isString(section)
|
||||
? section
|
||||
: {
|
||||
pathname: paramCase(section),
|
||||
name: titleCase(section)
|
||||
}
|
||||
)
|
||||
.map(({ name, pathname }) => ({
|
||||
name,
|
||||
pathname: `/instances/${instanceSlug}/${pathname}`
|
||||
}));
|
||||
const links = sections.map(({ name, pathname }) => ({
|
||||
name,
|
||||
pathname: `/instances/${instanceSlug}/${pathname}`
|
||||
}));
|
||||
|
||||
return {
|
||||
links
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
Metadata as InstanceMetadata,
|
||||
Networks as InstanceNetworks,
|
||||
Firewall as InstanceFirewall,
|
||||
Dns as InstanceDns,
|
||||
Cns as InstanceCns,
|
||||
Snapshots as InstanceSnapshots,
|
||||
Resize as InstanceResize
|
||||
} from '@containers/instances';
|
||||
@ -77,12 +77,16 @@ export default () => (
|
||||
exact
|
||||
component={InstanceFirewall}
|
||||
/>
|
||||
<Route path="/instances/:instance/dns" exact component={InstanceDns} />
|
||||
<Route
|
||||
path="/instances/:instance/snapshots"
|
||||
exact
|
||||
component={InstanceSnapshots}
|
||||
/>
|
||||
<Route
|
||||
path="/instances/:instance/cns-dns"
|
||||
exact
|
||||
component={InstanceCns}
|
||||
/>
|
||||
<Route
|
||||
path="/instances/:instance"
|
||||
exact
|
||||
|
@ -5,6 +5,7 @@ import { ApolloClient } from 'apollo-client';
|
||||
import { HttpLink } from 'apollo-link-http';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import { reducer as valuesReducer } from 'react-redux-values';
|
||||
import paramCase from 'param-case';
|
||||
|
||||
const {
|
||||
REACT_APP_GQL_PORT = 443,
|
||||
@ -22,7 +23,17 @@ export const client = new ApolloClient({
|
||||
const initialState = {
|
||||
ui: {
|
||||
sections: {
|
||||
instances: ['summary', 'tags', 'metadata', 'networks', 'snapshots']
|
||||
instances: [
|
||||
'Summary',
|
||||
'CNS & DNS',
|
||||
'Snapshots',
|
||||
'Tags',
|
||||
'Metadata',
|
||||
'Networks'
|
||||
].map(name => ({
|
||||
pathname: paramCase(name),
|
||||
name
|
||||
}))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
12
yarn.lock
12
yarn.lock
@ -3829,8 +3829,8 @@ eslint-plugin-flowtype@2.39.1:
|
||||
lodash "^4.15.0"
|
||||
|
||||
eslint-plugin-flowtype@^2.39.1:
|
||||
version "2.41.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.41.0.tgz#fd5221c60ba917c059d7ef69686a99cca09fd871"
|
||||
version "2.41.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.41.1.tgz#0996e1ea1d501dfc945802453a304ae9e8098b78"
|
||||
dependencies:
|
||||
lodash "^4.15.0"
|
||||
|
||||
@ -4926,8 +4926,8 @@ graphql-tag@^2.6.1:
|
||||
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.6.1.tgz#4788d509f6e29607d947fc47a40c4e18f736d34a"
|
||||
|
||||
graphql-tools@^2.6.1:
|
||||
version "2.18.0"
|
||||
resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-2.18.0.tgz#8e2d6436f9adba1d579c1a1710ae95e7f5e7248b"
|
||||
version "2.19.0"
|
||||
resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-2.19.0.tgz#04e1065532ab877aff3ad1883530fb56804ce9bf"
|
||||
dependencies:
|
||||
apollo-link "^1.0.0"
|
||||
apollo-utilities "^1.0.1"
|
||||
@ -6656,6 +6656,10 @@ lodash.intersection@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.intersection/-/lodash.intersection-4.4.0.tgz#0a11ba631d0e95c23c7f2f4cbb9a692ed178e705"
|
||||
|
||||
lodash.isarray@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-4.0.0.tgz#2aca496b28c4ca6d726715313590c02e6ea34403"
|
||||
|
||||
lodash.isarraylike@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isarraylike/-/lodash.isarraylike-4.2.0.tgz#4623310ab318804b667ddc3619058137559400c4"
|
||||
|
Loading…
Reference in New Issue
Block a user