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

fixes #988
This commit is contained in:
Sara Vieira 2018-01-12 15:25:26 +00:00 committed by Sérgio Ramos
parent 5ff8d7165c
commit 069e56f921
27 changed files with 7877 additions and 6085 deletions

View File

@ -6,11 +6,14 @@
"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

@ -0,0 +1,967 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders <Header /> without throwing 1`] = `
Array [
<b>
:
</b>,
" be on a",
" ",
" node as the instance(s) identified by the instance ",
" ",
"key ",
" “",
"\\" and the instance tag value ",
"”",
]
`;
exports[`renders <Header tag/> without throwing 1`] = `
Array [
<b>
:
</b>,
" be on a",
" ",
" node as the instance(s) identified by the instance ",
" ",
"key ",
" “",
"\\" and the instance tag value ",
"”",
]
`;
exports[`renders <Rule/> without throwing 1`] = `
.c0 {
margin-top: 0.5rem;
margin-bottom: 2rem;
}
.c8 {
margin-right: 0.25rem;
}
.c1 {
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-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c2 {
color: rgba(73,73,73,1);
font-weight: normal;
line-height: 1.5rem;
font-size: 0.9375rem;
margin: 0;
display: inline-block;
}
.c3 {
display: inline-block;
margin: 0;
padding: 0;
border: none;
overflow: hidden;
height: auto;
-webkit-margin-start: 0;
-webkit-margin-end: 0;
-webkit-padding-before: 0;
-webkit-padding-start: 0;
-webkit-padding-end: 0;
-webkit-padding-after: 0;
}
.c9 {
box-sizing: border-box;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
margin-top: 0.5rem;
padding: 0.8125rem 1.125rem;
border-radius: 0.25rem;
background-color: rgb(255,255,255);
border: 0.0625rem solid rgb(216,216,216);
color: rgba(73,73,73,1);
border: none;
border-bottom: 0.0625rem solid rgba(73,73,73,1);
border-radius: 0;
background: transparent;
padding: 0;
padding-right: 0.75rem;
display: inline;
height: 1.5rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
min-height: 0;
max-width: 18.75rem;
text-overflow: ellipsis;
font-size: 0.9375rem;
line-height: normal !important;
font-style: normal;
font-stretch: normal;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: 0;
}
.c9::-webkit-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c9::-moz-placeholder {
color: rgba(73,73,73,0.5);
}
.c9:-ms-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c9:invalid {
box-shadow: none;
}
.c9:disabled {
background-color: rgb(250,250,250);
color: rgb(216,216,216);
}
.c9:disabled::-webkit-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c9:disabled::-moz-placeholder {
color: rgba(73,73,73,0.5);
}
.c9:disabled:-ms-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c9:focus {
border-color: rgb(59,70,204);
outline: 0;
}
.c4 {
position: relative;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
width: 100%;
max-width: 100%;
min-width: 18.75rem;
width: auto;
margin: 0 0.375rem;
min-width: 0;
}
.c4:after {
content: '';
width: 0.625rem;
height: 0.625rem;
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI2IiB2aWV3Qm94PSIwIDAgOSA2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5hcnJvdzogcmlnaHQ8L3RpdGxlPjxwYXRoIGQ9Ik05IDEuMzg2TDcuNjQ4IDAgNC41IDMuMjI4IDEuMzUyIDAgMCAxLjM4NiA0LjUgNnoiIGZpbGw9IiM0OTQ5NDkiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==) center center no-repeat;
display: block;
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
right: 0.75rem;
}
.c4:after {
right: 0rem;
}
.c7 {
position: relative;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
width: 100%;
max-width: 100%;
min-width: 18.75rem;
width: auto;
margin: 0 0.375rem;
min-width: 0;
margin-left: 0;
}
.c7:after {
content: '';
width: 0.625rem;
height: 0.625rem;
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI2IiB2aWV3Qm94PSIwIDAgOSA2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5hcnJvdzogcmlnaHQ8L3RpdGxlPjxwYXRoIGQ9Ik05IDEuMzg2TDcuNjQ4IDAgNC41IDMuMjI4IDEuMzUyIDAgMCAxLjM4NiA0LjUgNnoiIGZpbGw9IiM0OTQ5NDkiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==) center center no-repeat;
display: block;
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
right: 0.75rem;
}
.c7:after {
right: 0rem;
}
.c6 {
box-sizing: border-box;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
margin-top: 0.5rem;
padding: 0.8125rem 1.125rem;
border-radius: 0.25rem;
background-color: rgb(255,255,255);
border: 0.0625rem solid rgb(216,216,216);
color: rgba(73,73,73,1);
border: none;
border-bottom: 0.0625rem solid rgba(73,73,73,1);
border-radius: 0;
background: transparent;
padding: 0;
padding-right: 0.75rem;
display: inline;
height: 1.5rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
min-height: 0;
max-width: 18.75rem;
text-overflow: ellipsis;
font-size: 0.9375rem;
line-height: normal !important;
font-style: normal;
font-stretch: normal;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: 0;
}
.c6::-webkit-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c6::-moz-placeholder {
color: rgba(73,73,73,0.5);
}
.c6:-ms-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c6:invalid {
box-shadow: none;
}
.c6:disabled {
background-color: rgb(250,250,250);
color: rgb(216,216,216);
}
.c6:disabled::-webkit-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c6:disabled::-moz-placeholder {
color: rgba(73,73,73,0.5);
}
.c6:disabled:-ms-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c6:focus {
border-color: rgb(59,70,204);
outline: 0;
}
.c5 {
position: relative;
padding: 0.75rem;
padding-right: 1.5625rem;
width: auto;
border: none;
border-bottom: 0.0625rem solid rgba(73,73,73,1);
border-radius: 0;
background: transparent;
padding: 0;
padding-right: 0.75rem;
display: inline;
height: 1.5rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
min-height: 0;
color: rgb(216,216,216);
margin: 0 0.375rem;
}
<div
className="c0"
>
<div
className="c1"
wrap={true}
>
<h4
className="c2"
>
The instance
</h4>
<div
className="c3"
name="rule-instance-conditional"
role="group"
style={undefined}
>
<div
className="c4"
disabled={false}
>
<select
className="c5 c6"
disabled={false}
id="Y"
>
<option
value="must"
>
must
</option>
<option
value="should"
>
should
</option>
</select>
</div>
</div>
<h4
className="c2"
>
be on
</h4>
<div
className="c3"
name="rule-instance-placement"
role="group"
style={undefined}
>
<div
className="c4"
disabled={false}
>
<select
className="c5 c6"
disabled={false}
id="Z"
>
<option
value="same"
>
the same
</option>
<option
value="different"
>
a different
</option>
</select>
</div>
</div>
<h4
className="c2"
>
node as the instance(s) identified by the
</h4>
<div
className="c3"
name="rule-type"
role="group"
style={undefined}
>
<div
className="c7"
disabled={false}
>
<select
className="c5 c6"
disabled={false}
id="a"
>
<option
value="name"
>
instance name
</option>
<option
value="tag"
>
tag
</option>
</select>
</div>
</div>
<div
className="c3"
name="rule-instance-name-pattern"
role="group"
style={undefined}
>
<div
className="c8"
>
<div
className="c4"
disabled={false}
>
<select
className="c5 c6"
disabled={false}
id="bb"
>
<option
value="equalling"
>
equalling
</option>
<option
value="!equalling"
>
not equalling
</option>
<option
value="containing"
>
containing
</option>
<option
value="starting"
>
starting with
</option>
<option
value="ending"
>
ending with
</option>
</select>
</div>
</div>
</div>
<div
className="c3"
name="rule-instance-name"
role="group"
style={undefined}
>
<input
className="c9"
disabled={false}
id="bc"
placeholder="Example instance name: nginx"
required={true}
/>
</div>
</div>
</div>
`;
exports[`renders <Rule/> without throwing 2`] = `
.c0 {
margin-top: 0.5rem;
margin-bottom: 2rem;
}
.c8 {
margin-right: 0.25rem;
}
.c1 {
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-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.c2 {
color: rgba(73,73,73,1);
font-weight: normal;
line-height: 1.5rem;
font-size: 0.9375rem;
margin: 0;
display: inline-block;
}
.c3 {
display: inline-block;
margin: 0;
padding: 0;
border: none;
overflow: hidden;
height: auto;
-webkit-margin-start: 0;
-webkit-margin-end: 0;
-webkit-padding-before: 0;
-webkit-padding-start: 0;
-webkit-padding-end: 0;
-webkit-padding-after: 0;
}
.c9 {
box-sizing: border-box;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
margin-top: 0.5rem;
padding: 0.8125rem 1.125rem;
border-radius: 0.25rem;
background-color: rgb(255,255,255);
border: 0.0625rem solid rgb(216,216,216);
color: rgba(73,73,73,1);
border: none;
border-bottom: 0.0625rem solid rgba(73,73,73,1);
border-radius: 0;
background: transparent;
padding: 0;
padding-right: 0.75rem;
display: inline;
height: 1.5rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
min-height: 0;
max-width: 18.75rem;
text-overflow: ellipsis;
font-size: 0.9375rem;
line-height: normal !important;
font-style: normal;
font-stretch: normal;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: 0;
}
.c9::-webkit-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c9::-moz-placeholder {
color: rgba(73,73,73,0.5);
}
.c9:-ms-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c9:invalid {
box-shadow: none;
}
.c9:disabled {
background-color: rgb(250,250,250);
color: rgb(216,216,216);
}
.c9:disabled::-webkit-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c9:disabled::-moz-placeholder {
color: rgba(73,73,73,0.5);
}
.c9:disabled:-ms-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c9:focus {
border-color: rgb(59,70,204);
outline: 0;
}
.c4 {
position: relative;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
width: 100%;
max-width: 100%;
min-width: 18.75rem;
width: auto;
margin: 0 0.375rem;
min-width: 0;
}
.c4:after {
content: '';
width: 0.625rem;
height: 0.625rem;
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI2IiB2aWV3Qm94PSIwIDAgOSA2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5hcnJvdzogcmlnaHQ8L3RpdGxlPjxwYXRoIGQ9Ik05IDEuMzg2TDcuNjQ4IDAgNC41IDMuMjI4IDEuMzUyIDAgMCAxLjM4NiA0LjUgNnoiIGZpbGw9IiM0OTQ5NDkiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==) center center no-repeat;
display: block;
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
right: 0.75rem;
}
.c4:after {
right: 0rem;
}
.c7 {
position: relative;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
display: inline-flex;
width: 100%;
max-width: 100%;
min-width: 18.75rem;
width: auto;
margin: 0 0.375rem;
min-width: 0;
margin-left: 0;
}
.c7:after {
content: '';
width: 0.625rem;
height: 0.625rem;
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOSIgaGVpZ2h0PSI2IiB2aWV3Qm94PSIwIDAgOSA2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjx0aXRsZT5hcnJvdzogcmlnaHQ8L3RpdGxlPjxwYXRoIGQ9Ik05IDEuMzg2TDcuNjQ4IDAgNC41IDMuMjI4IDEuMzUyIDAgMCAxLjM4NiA0LjUgNnoiIGZpbGw9IiM0OTQ5NDkiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==) center center no-repeat;
display: block;
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
right: 0.75rem;
}
.c7:after {
right: 0rem;
}
.c6 {
box-sizing: border-box;
width: 18.75rem;
height: 3rem;
min-height: 3rem;
margin-bottom: 0.5rem;
margin-top: 0.5rem;
padding: 0.8125rem 1.125rem;
border-radius: 0.25rem;
background-color: rgb(255,255,255);
border: 0.0625rem solid rgb(216,216,216);
color: rgba(73,73,73,1);
border: none;
border-bottom: 0.0625rem solid rgba(73,73,73,1);
border-radius: 0;
background: transparent;
padding: 0;
padding-right: 0.75rem;
display: inline;
height: 1.5rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
min-height: 0;
max-width: 18.75rem;
text-overflow: ellipsis;
font-size: 0.9375rem;
line-height: normal !important;
font-style: normal;
font-stretch: normal;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: 0;
}
.c6::-webkit-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c6::-moz-placeholder {
color: rgba(73,73,73,0.5);
}
.c6:-ms-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c6:invalid {
box-shadow: none;
}
.c6:disabled {
background-color: rgb(250,250,250);
color: rgb(216,216,216);
}
.c6:disabled::-webkit-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c6:disabled::-moz-placeholder {
color: rgba(73,73,73,0.5);
}
.c6:disabled:-ms-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c6:focus {
border-color: rgb(59,70,204);
outline: 0;
}
.c5 {
position: relative;
padding: 0.75rem;
padding-right: 1.5625rem;
width: auto;
border: none;
border-bottom: 0.0625rem solid rgba(73,73,73,1);
border-radius: 0;
background: transparent;
padding: 0;
padding-right: 0.75rem;
display: inline;
height: 1.5rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
min-height: 0;
color: rgb(216,216,216);
margin: 0 0.375rem;
}
<div
className="c0"
>
<div
className="c1"
wrap={true}
>
<h4
className="c2"
>
The instance
</h4>
<div
className="c3"
name="rule-instance-conditional"
role="group"
style={undefined}
>
<div
className="c4"
disabled={false}
>
<select
className="c5 c6"
disabled={false}
id="bd"
>
<option
value="must"
>
must
</option>
<option
value="should"
>
should
</option>
</select>
</div>
</div>
<h4
className="c2"
>
be on
</h4>
<div
className="c3"
name="rule-instance-placement"
role="group"
style={undefined}
>
<div
className="c4"
disabled={false}
>
<select
className="c5 c6"
disabled={false}
id="be"
>
<option
value="same"
>
the same
</option>
<option
value="different"
>
a different
</option>
</select>
</div>
</div>
<h4
className="c2"
>
node as the instance(s) identified by the
</h4>
<div
className="c3"
name="rule-type"
role="group"
style={undefined}
>
<div
className="c7"
disabled={false}
>
<select
className="c5 c6"
disabled={false}
id="bf"
>
<option
value="name"
>
instance name
</option>
<option
value="tag"
>
tag
</option>
</select>
</div>
</div>
<div
className="c3"
name="rule-instance-name-pattern"
role="group"
style={undefined}
>
<div
className="c8"
>
<div
className="c4"
disabled={false}
>
<select
className="c5 c6"
disabled={false}
id="bg"
>
<option
value="equalling"
>
equalling
</option>
<option
value="!equalling"
>
not equalling
</option>
<option
value="containing"
>
containing
</option>
<option
value="starting"
>
starting with
</option>
<option
value="ending"
>
ending with
</option>
</select>
</div>
</div>
</div>
<div
className="c3"
name="rule-instance-name"
role="group"
style={undefined}
>
<input
className="c9"
disabled={false}
id="bh"
placeholder="Example instance name: nginx"
required={true}
/>
</div>
</div>
</div>
`;

View File

@ -216,6 +216,7 @@ exports[`renders <Network /> without throwing 1`] = `
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
}
@ -252,6 +253,7 @@ exports[`renders <Network /> without throwing 1`] = `
width: 2.875rem;
min-width: 2.875rem;
min-height: 2.875rem;
max-width: 100%;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
@ -303,6 +305,7 @@ exports[`renders <Network /> without throwing 1`] = `
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;
@ -1154,6 +1157,7 @@ exports[`renders <Network {...network} /> without throwing 1`] = `
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
}
@ -1190,6 +1194,7 @@ exports[`renders <Network {...network} /> without throwing 1`] = `
width: 2.875rem;
min-width: 2.875rem;
min-height: 2.875rem;
max-width: 100%;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
@ -1241,6 +1246,7 @@ exports[`renders <Network {...network} /> without throwing 1`] = `
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;
@ -2105,6 +2111,7 @@ exports[`renders <Network {...network} /> without throwing 3`] = `
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
}
@ -2141,6 +2148,7 @@ exports[`renders <Network {...network} /> without throwing 3`] = `
width: 2.875rem;
min-width: 2.875rem;
min-height: 2.875rem;
max-width: 100%;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
@ -2192,6 +2200,7 @@ exports[`renders <Network {...network} /> without throwing 3`] = `
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;
@ -3093,6 +3102,7 @@ exports[`renders <Network {...network} fabric /> without throwing 1`] = `
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
}
@ -3133,6 +3143,7 @@ exports[`renders <Network {...network} fabric /> without throwing 1`] = `
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
margin: -0.0625rem;
box-shadow: none;
@ -3171,6 +3182,7 @@ exports[`renders <Network {...network} fabric /> without throwing 1`] = `
width: 2.875rem;
min-width: 2.875rem;
min-height: 2.875rem;
max-width: 100%;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
@ -3222,6 +3234,7 @@ exports[`renders <Network {...network} fabric /> without throwing 1`] = `
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;
@ -3280,6 +3293,7 @@ exports[`renders <Network {...network} fabric /> without throwing 1`] = `
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;
@ -4260,6 +4274,7 @@ exports[`renders <Network {...network} infoExpanded /> without throwing 1`] = `
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
}
@ -4296,6 +4311,7 @@ exports[`renders <Network {...network} infoExpanded /> without throwing 1`] = `
width: 2.875rem;
min-width: 2.875rem;
min-height: 2.875rem;
max-width: 100%;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
@ -4347,6 +4363,7 @@ exports[`renders <Network {...network} infoExpanded /> without throwing 1`] = `
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;
@ -5425,6 +5442,7 @@ exports[`renders <Network {...network} public /> without throwing 1`] = `
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
}
@ -5461,6 +5479,7 @@ exports[`renders <Network {...network} public /> without throwing 1`] = `
width: 2.875rem;
min-width: 2.875rem;
min-height: 2.875rem;
max-width: 100%;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
@ -5512,6 +5531,7 @@ exports[`renders <Network {...network} public /> without throwing 1`] = `
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;

View File

@ -0,0 +1,90 @@
import React from 'react';
import renderer from 'react-test-renderer';
import 'jest-styled-components';
import { Rule, Header } from '../affinity';
import Theme from '@mocks/theme';
it('renders <Rule/> without throwing', () => {
expect(
renderer
.create(
<Theme>
<Rule />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Rule/> without throwing', () => {
expect(
renderer
.create(
<Theme>
<Rule
rule={{
'rule-instance-name': 'test',
'rule-instance-conditional': 'must',
'rule-instance-placement': 'same',
'rule-instance-tag-key-pattern': 'equalling',
'rule-instance-tag-value-pattern': 'equalling',
'rule-instance-name-pattern': 'equalling',
'rule-instance-tag-value': '',
'rule-instance-tag-key': '',
'rule-type': 'name'
}}
/>
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Header /> without throwing', () => {
expect(
renderer
.create(
<Theme>
<Header
rule={{
'rule-instance-name': 'test',
'rule-instance-conditional': 'must',
'rule-instance-placement': 'same',
'rule-instance-tag-key-pattern': 'equalling',
'rule-instance-tag-value-pattern': 'equalling',
'rule-instance-name-pattern': 'equalling',
'rule-instance-tag-value': '',
'rule-instance-tag-key': '',
'rule-type': 'name'
}}
/>
</Theme>
)
.toJSON()
).toMatchSnapshot();
});
it('renders <Header tag/> without throwing', () => {
expect(
renderer
.create(
<Theme>
<Header
rule={{
'rule-instance-name': 'test',
'rule-instance-conditional': 'must',
'rule-instance-placement': 'same',
'rule-instance-tag-key-pattern': 'equalling',
'rule-instance-tag-value-pattern': 'equalling',
'rule-instance-name-pattern': 'equalling',
'rule-instance-tag-value': 'one',
'rule-instance-tag-key': 'two',
'rule-type': 'tag'
}}
/>
</Theme>
)
.toJSON()
).toMatchSnapshot();
});

View File

@ -0,0 +1,108 @@
import React, { Fragment } from 'react';
import { Margin } from 'styled-components-spacing';
import Flex from 'styled-flex-component';
import { Field } from 'redux-form';
import titleCase from 'title-case';
import { H5, Select, Input, FormGroup } from 'joyent-ui-toolkit';
const Values = (
<Margin right={1}>
<Select embedded>
<option value="equalling">equalling</option>
<option value="!equalling">not equalling</option>
<option value="containing">containing</option>
<option value="starting">starting with</option>
<option value="ending">ending with</option>
</Select>
</Margin>
);
export const Rule = rule => (
<Margin top={2} bottom={4}>
<Flex alignCenter wrap>
<H5 inline noMargin>
The instance
</H5>
<FormGroup name="rule-instance-conditional" field={Field}>
<Select embedded>
<option value="must">must</option>
<option value="should">should</option>
</Select>
</FormGroup>
<H5 inline noMargin>
be on
</H5>
<FormGroup name="rule-instance-placement" field={Field}>
<Select embedded>
<option value="same">the same</option>
<option value="different">a different</option>
</Select>
</FormGroup>
<H5 inline noMargin>
node as the instance(s) identified by the
</H5>
<FormGroup name="rule-type" field={Field}>
<Select embedded left>
<option value="name">instance name</option>
<option value="tag">tag</option>
</Select>
</FormGroup>
{rule['rule-type'] === 'tag' ? (
<Fragment>
<FormGroup name="rule-instance-tag-key-pattern" field={Field}>
{Values}
</FormGroup>
<FormGroup name="rule-instance-tag-key" field={Field}>
<Input small embedded type="text" required placeholder="key" />
</FormGroup>
<H5 inline noMargin>
and value{' '}
</H5>
<FormGroup name="rule-instance-tag-value-pattern" field={Field}>
{Values}
</FormGroup>
<FormGroup name="rule-instance-tag-value" field={Field}>
<Input small embedded type="text" required placeholder="value" />
</FormGroup>
</Fragment>
) : (
<Fragment>
<FormGroup name="rule-instance-name-pattern" field={Field}>
{Values}
</FormGroup>
<FormGroup name="rule-instance-name" field={Field}>
<Input
embedded
type="text"
required
placeholder="Example instance name: nginx"
/>
</FormGroup>
</Fragment>
)}
</Flex>
</Margin>
);
export const Header = rule => (
<Fragment>
<b>{titleCase(rule['rule-instance-conditional'])}:</b> be on a{' '}
{rule['rule-instance-placement']} node as the instance(s) identified by the
instance {rule['rule-type']}
{rule['rule-type'] === 'name' ? (
<Fragment>
{' '}
{rule['rule-instance-name-pattern']} {rule['rule-instance-name']}
</Fragment>
) : (
<Fragment>
{' '}
key {rule['rule-instance-tag-key-pattern']} {rule['rule-instance-tag-key']}"
and the instance tag value {rule['rule-instance-tag-value-pattern']}
{rule['rule-instance-tag-value']}
</Fragment>
)}
</Fragment>
);

View File

@ -1,4 +1,4 @@
import React, { PureComponent } from 'react';
import React, { PureComponent, Fragment } from 'react';
import { Padding } from 'styled-components-spacing';
import PropTypes from 'prop-types';
import { withTheme } from 'styled-components';
@ -38,6 +38,13 @@ const CollapsedKeyValue = styled.div`
display: block;
`;
const PaddingMaxWidth = styled(Padding)`
word-wrap: break-word;
overflow-wrap: break-word;
width: 100%;
box-sizing: border-box;
`;
class ValueTextareaField extends PureComponent {
render() {
const { input = {}, submitting } = this.props;
@ -126,7 +133,8 @@ export const KeyValue = ({
onRemove = () => null,
theme = {},
onlyName = false,
noRemove = false
noRemove = false,
customHeader
}) => {
const handleHeaderClick = method === 'edit' && onToggleExpanded;
@ -138,22 +146,27 @@ export const KeyValue = ({
actionable={Boolean(handleHeaderClick)}
onClick={handleHeaderClick}
>
<Padding left={3} right={3}>
<PaddingMaxWidth 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>
{customHeader ? customHeader : null}
{initialValues.name ? (
<Fragment>
{expanded ? (
<span>{`${initialValues.name}: `}</span>
) : (
<b>{`${initialValues.name}: `}</b>
)}
<span>{initialValues.value}</span>
</Fragment>
) : null}
</CollapsedKeyValue>
)}
</CardHeaderMeta>
</Padding>
</PaddingMaxWidth>
</CardHeader>
{expanded ? (
<CardOutlet>
@ -174,9 +187,13 @@ export const KeyValue = ({
) : (
<InputKeyValue type={type} submitting={submitting} />
)
) : (
) : null}
{input === 'textarea' ? (
<TextareaKeyValue type={type} submitting={submitting} />
)}
) : null}
{input !== 'textarea' && input !== 'input'
? input(submitting)
: null}
<Row between="xs" middle="xs">
<Col xs={method === 'add' ? 12 : 7}>
<Button

View File

@ -0,0 +1,70 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders <Footer/> without throwing 1`] = `
.c0 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
list-style: none;
padding: 0.75rem 1.125rem;
border-top: 0.0625rem solid rgb(216,216,216);
width: 100%;
-webkit-box-pack: end;
-webkit-justify-content: flex-end;
-ms-flex-pack: end;
justify-content: flex-end;
position: absolute;
box-sizing: border-box;
margin: 0;
bottom: 0;
}
.c1 {
color: rgb(151,151,151);
}
.c1:not(:last-child) {
padding-right: 1.5rem;
}
.c2 {
color: rgb(151,151,151);
text-decoration: none;
}
<ul
className="c0"
>
<li
className="c1"
>
<a
className="c2"
href="https://www.joyent.com/about/policies"
target="_blank"
>
Policies
</a>
</li>
<li
className="c1"
>
<a
className="c2"
href="https://www.joyent.com/networking-and-security/security-compliance"
>
Compliance
</a>
</li>
<li
className="c1"
>
<b>
©
2018
Joyent, Inc.
</b>
</li>
</ul>
`;

View File

@ -0,0 +1,18 @@
import React from 'react';
import renderer from 'react-test-renderer';
import 'jest-styled-components';
import Footer from '../footer';
import Theme from '@mocks/theme';
it('renders <Footer/> without throwing', () => {
expect(
renderer
.create(
<Theme>
<Footer />
</Theme>
)
.toJSON()
).toMatchSnapshot();
});

View File

@ -0,0 +1,46 @@
import React from 'react';
import styled from 'styled-components';
import remcalc from 'remcalc';
const List = styled.ul`
display: flex;
list-style: none;
padding: ${remcalc(12)} ${remcalc(18)};
border-top: ${remcalc(1)} solid ${props => props.theme.grey};
width: 100%;
justify-content: flex-end;
position: absolute;
box-sizing: border-box;
margin: 0;
bottom: 0;
`;
const ListItem = styled.li`
color: ${props => props.theme.greyDark};
&:not(:last-child) {
padding-right: ${remcalc(24)};
}
`;
const Link = styled.a`
color: ${props => props.theme.greyDark};
text-decoration: none;
`;
export default () => (
<List>
<ListItem>
<Link href="https://www.joyent.com/about/policies" target="_blank">
Policies
</Link>
</ListItem>
<ListItem>
<Link href="https://www.joyent.com/networking-and-security/security-compliance">
Compliance
</Link>
</ListItem>
<ListItem>
<b>© {new Date().getFullYear()} Joyent, Inc.</b>
</ListItem>
</List>
);

View File

@ -1622,6 +1622,7 @@ Array [
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
}
@ -1662,6 +1663,7 @@ Array [
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
margin: -0.0625rem;
box-shadow: none;
@ -1706,6 +1708,7 @@ Array [
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
}
@ -1742,6 +1745,7 @@ Array [
width: 2.875rem;
min-width: 2.875rem;
min-height: 2.875rem;
max-width: 100%;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
@ -1797,6 +1801,7 @@ Array [
width: 2.875rem;
min-width: 2.875rem;
min-height: 2.875rem;
max-width: 100%;
display: -webkit-inline-box;
display: -webkit-inline-flex;
display: -ms-inline-flexbox;
@ -1848,6 +1853,7 @@ Array [
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;
@ -1906,6 +1912,7 @@ Array [
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;
@ -1966,6 +1973,7 @@ Array [
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;

View File

@ -414,7 +414,7 @@ Array [
<ul
className="c0"
/>,
.c18 {
.c19 {
font-family: sans-serif;
font-size: 100%;
line-height: 1.15;
@ -427,30 +427,30 @@ Array [
min-width: 7.5rem;
}
.c18::-moz-focus-inner,
.c18[type='button']::-moz-focus-inner,
.c18[type='reset']::-moz-focus-inner,
.c18[type='submit']::-moz-focus-inner {
.c19::-moz-focus-inner,
.c19[type='button']::-moz-focus-inner,
.c19[type='reset']::-moz-focus-inner,
.c19[type='submit']::-moz-focus-inner {
border-style: none;
padding: 0;
}
.c18:-moz-focusring,
.c18[type='button']:-moz-focusring,
.c18[type='reset']:-moz-focusring,
.c18[type='submit']:-moz-focusring {
.c19:-moz-focusring,
.c19[type='button']:-moz-focusring,
.c19[type='reset']:-moz-focusring,
.c19[type='submit']:-moz-focusring {
outline: 0.0625rem dotted ButtonText;
}
.c18 + button {
.c19 + button {
margin-left: 0.375rem;
}
.c17 {
.c18 {
display: inline-block;
}
.c16 {
.c17 {
box-sizing: border-box;
display: inline-block;
-webkit-box-pack: center;
@ -495,50 +495,50 @@ Array [
margin: 0;
}
.c16:focus {
.c17:focus {
outline: 0;
text-decoration: none;
background-color: rgb(59,70,204);
border-color: rgb(45,56,132);
}
.c16:hover {
.c17:hover {
background-color: rgb(72,83,217);
border: solid 0.0625rem rgb(45,56,132);
}
.c16:active,
.c16:active:hover,
.c16:active:focus {
.c17:active,
.c17:active:hover,
.c17:active:focus {
background-image: none;
outline: 0;
background-color: rgb(45,56,132);
border-color: rgb(45,56,132);
}
.c16[disabled] {
.c17[disabled] {
cursor: not-allowed;
pointer-events: none;
}
.c16:focus {
.c17:focus {
background-color: rgb(255,255,255);
border-color: rgb(216,216,216);
}
.c16:hover {
.c17:hover {
background-color: rgb(247,247,247);
border-color: rgb(216,216,216);
}
.c16:active,
.c16:active:hover,
.c16:active:focus {
.c17:active,
.c17:active:hover,
.c17:active:focus {
background-color: rgb(230,230,230);
border-color: rgb(216,216,216);
}
.c19 {
.c20 {
box-sizing: border-box;
display: inline-block;
-webkit-box-pack: center;
@ -584,50 +584,50 @@ Array [
margin: 0;
}
.c19:focus {
.c20:focus {
outline: 0;
text-decoration: none;
background-color: rgb(59,70,204);
border-color: rgb(45,56,132);
}
.c19:hover {
.c20:hover {
background-color: rgb(72,83,217);
border: solid 0.0625rem rgb(45,56,132);
}
.c19:active,
.c19:active:hover,
.c19:active:focus {
.c20:active,
.c20:active:hover,
.c20:active:focus {
background-image: none;
outline: 0;
background-color: rgb(45,56,132);
border-color: rgb(45,56,132);
}
.c19[disabled] {
.c20[disabled] {
cursor: not-allowed;
pointer-events: none;
}
.c19:focus {
.c20:focus {
background-color: rgb(250,250,250);
border-color: rgb(216,216,216);
}
.c19:hover {
.c20:hover {
background-color: rgb(250,250,250);
border-color: rgb(250,250,250);
}
.c19:active,
.c19:active:hover,
.c19:active:focus {
.c20:active,
.c20:active:hover,
.c20:active:focus {
background-color: rgb(250,250,250);
border-color: rgb(250,250,250);
}
.c21 {
.c22 {
box-sizing: border-box;
display: inline-block;
-webkit-box-pack: center;
@ -685,94 +685,75 @@ Array [
float: right;
}
.c21:focus {
.c22:focus {
outline: 0;
text-decoration: none;
background-color: rgb(59,70,204);
border-color: rgb(45,56,132);
}
.c21:hover {
.c22:hover {
background-color: rgb(72,83,217);
border: solid 0.0625rem rgb(45,56,132);
}
.c21:active,
.c21:active:hover,
.c21:active:focus {
.c22:active,
.c22:active:hover,
.c22:active:focus {
background-image: none;
outline: 0;
background-color: rgb(45,56,132);
border-color: rgb(45,56,132);
}
.c21[disabled] {
.c22[disabled] {
cursor: not-allowed;
pointer-events: none;
}
.c21:focus {
.c22:focus {
background-color: rgb(255,255,255);
border-color: rgb(216,216,216);
}
.c21:hover {
.c22:hover {
background-color: rgb(247,247,247);
border-color: rgb(216,216,216);
}
.c21:active,
.c21:active:hover,
.c21:active:focus {
.c22:active,
.c22:active:hover,
.c22:active:focus {
background-color: rgb(230,230,230);
border-color: rgb(216,216,216);
}
.c21:focus {
.c22:focus {
background-color: rgb(255,255,255);
border-color: rgb(210,67,58);
}
.c21:hover {
.c22:hover {
background-color: rgb(247,247,247);
border-color: rgb(210,67,58);
}
.c21:active,
.c21:active:hover,
.c21:active:focus {
.c22:active,
.c22:active:hover,
.c22:active:focus {
background-color: rgb(230,230,230);
border-color: rgb(210,67,58);
}
.c21 svg + span {
.c22 svg + span {
margin-left: 0.75rem;
}
.c21 svg {
.c22 svg {
max-height: 1.125rem;
}
.c23 {
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;
}
.c14 {
.c24 {
box-sizing: border-box;
display: -webkit-box;
display: -webkit-flex;
@ -793,14 +774,24 @@ Array [
.c15 {
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;
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;
}
.c20 {
.c16 {
box-sizing: border-box;
-webkit-flex: 0 0 auto;
-ms-flex: 0 0 auto;
@ -809,7 +800,16 @@ Array [
padding-left: 0.5rem;
}
.c4 {
.c21 {
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;
}
.c5 {
color: rgba(73,73,73,1);
font-weight: 600;
line-height: 1.5rem;
@ -817,20 +817,20 @@ Array [
margin: 0;
}
.c4 + p,
.c4 + small,
.c4 + h1,
.c4 + h2,
.c4 + label,
.c4 + h3,
.c4 + h4,
.c4 + h5,
.c4 + div,
.c4 + span {
.c5 + p,
.c5 + small,
.c5 + h1,
.c5 + h2,
.c5 + label,
.c5 + h3,
.c5 + h4,
.c5 + h5,
.c5 + div,
.c5 + span {
margin-top: 0.75rem;
}
.c22 {
.c23 {
background-color: rgb(216,216,216);
margin: 0;
background-color: transparent;
@ -860,7 +860,7 @@ Array [
box-shadow: 0 0.125rem 0 0 rgba(0,0,0,0.05);
}
.c5 {
.c6 {
box-sizing: content-box;
display: -webkit-box;
display: -webkit-flex;
@ -896,11 +896,11 @@ Array [
background-color: transparent;
}
.c5 > [name='card']:not(:last-child) {
.c6 > [name='card']:not(:last-child) {
margin-bottom: 0.8125rem;
}
.c5 > [name='card']:last-child {
.c6 > [name='card']:last-child {
margin-bottom: 0.4375rem;
}
@ -935,6 +935,7 @@ Array [
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
}
@ -943,7 +944,7 @@ Array [
margin-top: 0;
}
.c3 {
.c4 {
box-sizing: content-box;
display: -webkit-box;
display: -webkit-flex;
@ -970,6 +971,7 @@ Array [
flex: 0 0 2.875rem;
box-sizing: border-box;
min-height: 2.9375rem;
max-width: 100%;
width: auto;
height: auto;
display: -webkit-inline-box;
@ -1000,7 +1002,7 @@ Array [
color: inherit;
}
.c9 {
.c10 {
display: inline-block;
margin: 0;
padding: 0;
@ -1016,7 +1018,7 @@ Array [
width: 100%;
}
.c11 {
.c12 {
box-sizing: border-box;
width: 18.75rem;
height: 3rem;
@ -1040,45 +1042,45 @@ Array [
outline: 0;
}
.c11::-webkit-input-placeholder {
.c12::-webkit-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c11::-moz-placeholder {
.c12::-moz-placeholder {
color: rgba(73,73,73,0.5);
}
.c11:-ms-input-placeholder {
.c12:-ms-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c11:invalid {
.c12:invalid {
box-shadow: none;
}
.c11:disabled {
.c12:disabled {
background-color: rgb(250,250,250);
color: rgb(216,216,216);
}
.c11:disabled::-webkit-input-placeholder {
.c12:disabled::-webkit-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c11:disabled::-moz-placeholder {
.c12:disabled::-moz-placeholder {
color: rgba(73,73,73,0.5);
}
.c11:disabled:-ms-input-placeholder {
.c12:disabled:-ms-input-placeholder {
color: rgba(73,73,73,0.5);
}
.c11:focus {
.c12:focus {
border-color: rgb(59,70,204);
outline: 0;
}
.c10 {
.c11 {
font-size: 0.9375rem;
font-style: normal;
font-stretch: normal;
@ -1091,7 +1093,7 @@ Array [
font-size: 0.8125rem;
}
.c12 {
.c13 {
font-size: 0.9375rem;
font-style: normal;
font-stretch: normal;
@ -1104,16 +1106,16 @@ Array [
margin-left: 1.75rem;
}
.c2 {
.c3 {
padding-right: 1rem;
padding-left: 1rem;
}
.c6 {
.c7 {
padding: 1rem;
}
.c7 {
.c8 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@ -1140,7 +1142,7 @@ Array [
align-content: stretch;
}
.c8 {
.c9 {
-webkit-order: 0;
-ms-flex-order: 0;
order: 0;
@ -1159,7 +1161,7 @@ Array [
flex-basis: auto;
}
.c13 {
.c14 {
-webkit-order: 0;
-ms-flex-order: 0;
order: 0;
@ -1178,8 +1180,15 @@ Array [
flex-basis: 0.75rem;
}
.c2 {
word-wrap: break-word;
overflow-wrap: break-word;
width: 100%;
box-sizing: border-box;
}
@media only screen and (min-width:0em) {
.c14 {
.c15 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
@ -1188,7 +1197,7 @@ Array [
}
@media only screen and (min-width:0em) {
.c14 {
.c15 {
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
@ -1197,7 +1206,7 @@ Array [
}
@media only screen and (min-width:0em) {
.c15 {
.c16 {
-webkit-flex-basis: 100%;
-ms-flex-preferred-size: 100%;
flex-basis: 100%;
@ -1207,7 +1216,7 @@ Array [
}
@media only screen and (min-width:0em) {
.c20 {
.c21 {
display: none;
}
}
@ -1227,15 +1236,15 @@ Array [
onClick={false}
>
<div
className="c2"
className="c2 c3"
>
<div
className="c3"
className="c4"
disabled={false}
name="card-header-meta"
>
<h4
className="c4"
className="c5"
>
Add tag
</h4>
@ -1243,79 +1252,79 @@ Array [
</div>
</div>
<div
className="c5"
className="c6"
name="card-outlet"
>
<div
className="c6"
className="c7"
>
<div
className="c7"
className="c8"
>
<div
className="c8"
className="c9"
>
<div
className="c9"
className="c10"
name="name"
role="group"
style={undefined}
>
<label
className="c10"
className="c11"
htmlFor="Y"
>
Tag
key
</label>
<input
className="c11"
className="c12"
disabled={false}
id="Y"
/>
<label
className="c12"
className="c13"
/>
</div>
</div>
<div
className="c13"
className="c14"
/>
<div
className="c8"
className="c9"
>
<div
className="c9"
className="c10"
name="value"
role="group"
style={undefined}
>
<label
className="c10"
className="c11"
htmlFor="Z"
>
Tag
value
</label>
<input
className="c11"
className="c12"
disabled={false}
id="Z"
/>
<label
className="c12"
className="c13"
/>
</div>
</div>
</div>
<div
className="c14"
className="c15"
>
<div
className="c15"
className="c16"
>
<button
className="c16 c17 c18"
className="c17 c18 c19"
disabled={false}
href=""
onClick={[Function]}
@ -1326,7 +1335,7 @@ Array [
</span>
</button>
<button
className="c19 c17 c18"
className="c20 c18 c19"
disabled={true}
href=""
type="submit"
@ -1337,10 +1346,10 @@ Array [
</button>
</div>
<div
className="c20"
className="c21"
>
<button
className="c21 c17 c18"
className="c22 c18 c19"
disabled={false}
href=""
icon={true}
@ -1390,7 +1399,7 @@ Array [
</div>
</div>
<div
className="c22 c23"
className="c23 c24"
height="0.8125rem"
/>
</form>,

View File

@ -0,0 +1,224 @@
import React, { Fragment } from 'react';
import { set } from 'react-redux-values';
import { Margin } from 'styled-components-spacing';
import { compose } from 'react-apollo';
import { destroy, reset } from 'redux-form';
import ReduxForm from 'declarative-redux-form';
import { connect } from 'react-redux';
import get from 'lodash.get';
import { AffinityIcon, P, Button, H3 } from 'joyent-ui-toolkit';
import Title from '@components/create-instance/title';
import { Rule, Header } from '@components/create-instance/affinity';
import KeyValue from '@components/instances/key-value';
const FORM_NAME_CREATE = 'CREATE-INSTANCE-AFFINITY-ADD';
const FORM_NAME_EDIT = i => `CREATE-INSTANCE-AFFINITY-EDIT-${i}`;
const RULE_DEFAULTS = {
'rule-instance-name': '',
'rule-instance-conditional': 'must',
'rule-instance-placement': 'same',
'rule-instance-tag-key-pattern': 'equalling',
'rule-instance-tag-value-pattern': 'equalling',
'rule-instance-name-pattern': 'equalling',
'rule-instance-tag-value': '',
'rule-instance-tag-key': '',
'rule-type': 'name'
};
export const Affinity = ({
affinityRules = [],
expanded,
proceeded,
addOpen,
handleAddAffinityRules,
handleRemoveAffinityRule,
handleUpdateAffinityRule,
handleToggleExpanded,
handleCancelEdit,
handleChangeAddOpen,
handleNext,
handleEdit,
rule
}) => (
<Fragment>
<Title icon={<AffinityIcon />}>Affinity</Title>
{expanded ? (
<Margin bottom={3}>
<P>
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
target="__blank"
href="https://apidocs.joyent.com/docker/features/placement"
>
Read the docs
</a>
</P>
</Margin>
) : null}
{proceeded ? (
<Margin bottom={4}>
<H3>
{affinityRules.length} Affinity Rule{affinityRules.length === 1 ? '' : 's'}
</H3>
</Margin>
) : null}
{affinityRules.map((rule, index) => (
<ReduxForm
form={FORM_NAME_EDIT(index)}
key={index}
initialValues={rule}
destroyOnUnmount={false}
forceUnregisterOnUnmount={true}
onSubmit={newValue => handleUpdateAffinityRule(index, newValue)}
>
{props => (
<KeyValue
{...props}
expanded={rule.expanded}
customHeader={<Header {...rule} />}
method="edit"
input={props => <Rule {...rule} {...props} />}
type="an affinity rule"
onToggleExpanded={() => handleToggleExpanded(index)}
onCancel={() => handleCancelEdit(index)}
onRemove={() => handleRemoveAffinityRule(index)}
/>
)}
</ReduxForm>
))}
{expanded && addOpen ? (
<ReduxForm
form={FORM_NAME_CREATE}
destroyOnUnmount={false}
forceUnregisterOnUnmount={true}
onSubmit={handleAddAffinityRules}
>
{props => (
<KeyValue
{...props}
method="create"
input={props => <Rule {...rule} {...props} />}
type="an affinity rule"
expanded
noRemove
onCancel={() => handleChangeAddOpen(false)}
/>
)}
</ReduxForm>
) : null}
<div>
{expanded ? (
<Fragment>
<Button
type="button"
onClick={() => handleChangeAddOpen(true)}
secondary
>
Create affinity rule
</Button>
<Button type="button" onClick={handleNext}>
Next
</Button>
</Fragment>
) : proceeded ? (
<Button type="button" onClick={handleEdit} secondary>
Edit
</Button>
) : null}
</div>
</Fragment>
);
export default compose(
connect(({ values, form }, ownProps) => ({
proceeded: get(values, 'create-instance-affinity-proceeded', false),
addOpen: get(values, 'create-instance-affinity-add-open', false),
affinityRules: get(values, 'create-instance-affinity', []),
rule: get(form, `${FORM_NAME_CREATE}.values`, {})
})),
connect(null, (dispatch, { affinityRules = [], history }) => ({
handleNext: () => {
dispatch(
set({ name: 'create-instance-affinity-proceeded', value: true })
);
return history.push(`/instances/~create/done`);
},
handleEdit: () => {
return history.push(`/instances/~create/affinity`);
},
handleAddAffinityRules: ({ ...rule }) => {
const toggleToClosed = set({
name: `create-instance-affinity-add-open`,
value: false
});
const appendAffinityRule = set({
name: `create-instance-affinity`,
value: affinityRules.concat([
{ ...RULE_DEFAULTS, ...rule, expanded: false }
])
});
return dispatch([
destroy(FORM_NAME_CREATE),
toggleToClosed,
appendAffinityRule
]);
},
handleUpdateAffinityRule: (index, newAffinityRule) => {
affinityRules[index] = {
...newAffinityRule,
expanded: false
};
return dispatch([
destroy(FORM_NAME_EDIT(index)),
set({ name: `create-instance-affinity`, value: affinityRules.slice() })
]);
},
handleChangeAddOpen: value => {
return dispatch([
reset(FORM_NAME_CREATE),
set({ name: `create-instance-affinity-add-open`, value })
]);
},
handleToggleExpanded: index => {
affinityRules[index] = {
...affinityRules[index],
expanded: !affinityRules[index].expanded
};
return dispatch(
set({
name: `create-instance-affinity`,
value: affinityRules.slice()
})
);
},
handleCancelEdit: index => {
affinityRules[index] = {
...affinityRules[index],
expanded: false
};
return dispatch([
reset(FORM_NAME_EDIT(index)),
set({ name: `create-instance-affinity`, value: affinityRules.slice() })
]);
},
handleRemoveAffinityRule: index => {
affinityRules.splice(index, 1);
return dispatch([
destroy(FORM_NAME_EDIT(index)),
set({ name: `create-instance-affinity`, value: affinityRules.slice() })
]);
}
}))
)(Affinity);

View File

@ -1,7 +1,8 @@
import React from 'react';
import { Margin } from 'styled-components-spacing';
import remcalc from 'remcalc';
import { ViewContainer, H2 } from 'joyent-ui-toolkit';
import { ViewContainer, H2, Button, Divider } from 'joyent-ui-toolkit';
import Name from '@containers/create-instance/name';
import Image from '@containers/create-instance/image';
@ -9,6 +10,7 @@ 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';
import Affinity from '@containers/create-instance/affinity';
import CNS from '@containers/create-instance/cns';
export default ({ step, ...props }) => (
@ -37,5 +39,16 @@ export default ({ step, ...props }) => (
<Margin bottom={4}>
<CNS {...props} expanded={step === 'cns'} />
</Margin>
<Margin bottom={4}>
<Affinity {...props} expanded={step === 'affinity'} />
</Margin>
{step === 'done' || step === 'affinity' ? (
<Divider height={remcalc(1)} />
) : null}
<Margin top={7} bottom={10}>
<Button disabled={step !== 'done'} onClick={() => console.log('DONE')}>
Deploy
</Button>
</Margin>
</ViewContainer>
);

View File

@ -6,6 +6,7 @@ import { PageContainer } from 'joyent-ui-toolkit';
import { Breadcrumb, Menu } from '@containers/navigation';
import { Header } from '@components/navigation';
import Footer from '@components/navigation/footer';
import {
List as Instances,
@ -18,7 +19,6 @@ import {
Snapshots as InstanceSnapshots,
Resize as InstanceResize
} from '@containers/instances';
import CreateInstance from '@containers/create-instance';
export default () => (
@ -157,9 +157,9 @@ export default () => (
component={props => <CreateInstance {...props} step="affinity" />}
/>
<Route
path="/instances/~create/summary"
path="/instances/~create/done"
exact
component={props => <CreateInstance {...props} step="summary" />}
component={props => <CreateInstance {...props} step="done" />}
/>
<Route
@ -175,6 +175,7 @@ export default () => (
</Switch>
<Route path="/" exact component={() => <Redirect to="/instances" />} />
<Footer />
</PageContainer>
</BrowserRouter>
);

View File

@ -31,7 +31,7 @@ export default ({ theme }) => css`
html,
body,
#root {
height: 100%;
min-height: 100vh;
}
body > #root {

View File

@ -57,6 +57,7 @@ exports[`Card Card With Header 1`] = `
z-index: 1;
line-height: 1.5rem;
height: auto;
max-width: 100%;
margin: -0.0625rem -0.0625rem 0 -0.0625rem;
}

View File

@ -13,6 +13,7 @@ const BaseHeader = BaseCard.extend`
z-index: 1;
line-height: ${remcalc(24)};
height: auto;
max-width: 100%;
margin: ${remcalc(-1)} ${remcalc(-1)} 0 ${remcalc(-1)};
@ -45,6 +46,7 @@ const BaseBox = BaseCard.extend`
width: ${remcalc(46)};
min-width: ${remcalc(46)};
min-height: ${remcalc(46)};
max-width: 100%;
display: inline-flex;
flex: 0 0 auto;
@ -83,6 +85,7 @@ const BaseBox = BaseCard.extend`
const BaseMeta = BaseCard.extend`
box-sizing: border-box;
min-height: ${remcalc(47)};
max-width: 100%;
width: auto;
height: auto;

View File

@ -37,7 +37,9 @@ const SelectWrapper = styled.div`
}
${is('embedded')`
width: auto;
margin: 0 ${remcalc(6)};
min-width: 0;
&:after {
right: ${remcalc(0)};
}
@ -66,6 +68,7 @@ const StyledSelect = select.extend`
`};
${is('embedded')`
width: auto;
border: none;
border-bottom: ${remcalc(1)} solid ${props => props.theme.text};
border-radius: 0;
@ -76,6 +79,8 @@ const StyledSelect = select.extend`
height: ${remcalc(24)};
appearance: none;
min-height: 0;
color: ${props => props.theme.grey};
margin: 0 ${remcalc(6)};
`};
${is('wrapped')`

View File

@ -1,7 +1,7 @@
import styled from 'styled-components';
import { H1 as NH1 } from 'normalized-styled-components';
import remcalc from 'remcalc';
import is from 'styled-is';
import is, { isNot } from 'styled-is';
export const H1 = NH1.extend`
color: ${props => props.theme.text};
@ -21,18 +21,20 @@ export const H1 = NH1.extend`
color: ${props => props.theme.white}
`};
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(24)};
}
${isNot('noMargin')`
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(24)};
}
`};
`;
export const H2 = styled.h2`
@ -51,18 +53,20 @@ export const H2 = styled.h2`
color: ${props => props.theme.white}
`};
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(24)};
}
${isNot('noMargin')`
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(24)};
}
`};
`;
export const H3 = styled.h3`
@ -81,18 +85,20 @@ export const H3 = styled.h3`
color: ${props => props.theme.white}
`};
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(24)};
}
${isNot('noMargin')`
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(24)};
}
`};
`;
export const H4 = styled.h4`
@ -112,18 +118,20 @@ export const H4 = styled.h4`
color: ${props => props.theme.white}
`};
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(12)};
}
${isNot('noMargin')`
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(12)};
}
`};
`;
export const H5 = styled.h4`
@ -142,18 +150,20 @@ export const H5 = styled.h4`
color: ${props => props.theme.white}
`};
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(12)};
}
${isNot('noMargin')`
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(12)};
}
`};
`;
export const H6 = styled.h6`
@ -172,16 +182,18 @@ export const H6 = styled.h6`
color: ${props => props.theme.white}
`};
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(12)};
}
${isNot('noMargin')`
& + p,
& + small,
& + h1,
& + h2,
& + label,
& + h3,
& + h4,
& + h5,
& + div,
& + span {
margin-top: ${remcalc(12)};
}
`};
`;