parent
57eecf0552
commit
67f36a464b
@ -41,7 +41,7 @@
|
||||
"react-apollo": "^2.0.4",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-redux-values": "^1.0.2",
|
||||
"react-redux-values": "^1.1.2",
|
||||
"react-router": "^4.2.0",
|
||||
"react-router-dom": "^4.2.2",
|
||||
"redux": "^3.7.2",
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,38 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders <Title /> without throwing 1`] = `
|
||||
Array [
|
||||
.c3 {
|
||||
.c3 {
|
||||
font-size: 80%;
|
||||
color: rgba(73,73,73,1);
|
||||
line-height: 1.125rem;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.c7 {
|
||||
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;
|
||||
}
|
||||
|
||||
.c6 {
|
||||
background-color: rgb(216,216,216);
|
||||
margin: 0;
|
||||
height: 0.0625rem;
|
||||
}
|
||||
|
||||
.c0 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
@ -62,75 +86,77 @@ Array [
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
<div
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
className="c1"
|
||||
>
|
||||
<div
|
||||
className="c2"
|
||||
/>
|
||||
</div>
|
||||
<small
|
||||
className="c3"
|
||||
/>
|
||||
</div>,
|
||||
.c3 {
|
||||
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;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
background-color: rgb(216,216,216);
|
||||
margin: 0;
|
||||
height: 0.0625rem;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
.c5 {
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.c0 + div:empty,
|
||||
.c0 + form:empty {
|
||||
.c4 + div:empty,
|
||||
.c4 + form:empty {
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
<div
|
||||
className="c0 c1"
|
||||
className=""
|
||||
>
|
||||
<div
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
className="c2 c3"
|
||||
height="0.0625rem"
|
||||
className="c1"
|
||||
>
|
||||
<div
|
||||
className="c2"
|
||||
/>
|
||||
</div>
|
||||
<small
|
||||
className="c3"
|
||||
/>
|
||||
</div>,
|
||||
]
|
||||
</div>
|
||||
<div
|
||||
className="c4 c5"
|
||||
>
|
||||
<div
|
||||
className="c6 c7"
|
||||
height="0.0625rem"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders <Title icon="NameIcon"/> without throwing 1`] = `
|
||||
Array [
|
||||
.c3 {
|
||||
.c3 {
|
||||
font-size: 80%;
|
||||
color: rgba(73,73,73,1);
|
||||
line-height: 1.125rem;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.c7 {
|
||||
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;
|
||||
}
|
||||
|
||||
.c6 {
|
||||
background-color: rgb(216,216,216);
|
||||
margin: 0;
|
||||
height: 0.0625rem;
|
||||
}
|
||||
|
||||
.c0 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
@ -184,96 +210,98 @@ Array [
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
<div
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
className="c1"
|
||||
>
|
||||
<div
|
||||
className="c2"
|
||||
>
|
||||
<svg
|
||||
className=""
|
||||
height="17"
|
||||
innerRef={undefined}
|
||||
style={
|
||||
Object {
|
||||
"transform": "rotate(0deg)",
|
||||
}
|
||||
}
|
||||
version="1.1"
|
||||
viewBox="0 0 16.24 13.55"
|
||||
width="17"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<path
|
||||
d="M.24,13.55c-1-2,1.39-6.73,1.52-7C4.47,1.5,6.77-.55,9,.12a2.34,2.34,0,0,1,1.4,1.16c.54,1.06-.26,2.41-1.18,4-.55.91-1.69,3.42-1.78,3.67-.37,1-.88,2.35-.52,2.86.19.28.73.34,1.14.34s1-.77,1.31-1.49c.56-1.48,1.87-4.94,4.1-4.27,1.78.53,1.27,2.56.93,3.91s-.11,1.51-.1,1.52a2.21,2.21,0,0,0,1.95-.24v1c-1.41.73-2.11.72-2.74.21-.88-.71-.48-2.19-.33-2.75.38-1.52.47-2.3-.07-2.46-.73-.22-1.6,1-2.57,3.52-.4,1.1-1.26,2.3-2.48,2.3a2.48,2.48,0,0,1-2.17-.88c-.72-1.05-.14-2.62.38-4,.09-.23,1.3-2.91,1.87-3.87s2.11-3.06.49-3.29S5.18,2.83,2.87,7.16c-1.71,3.21-1.78,5.95-1.62,6.39Z"
|
||||
fill="rgba(73, 73, 73, 1)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<small
|
||||
className="c3"
|
||||
/>
|
||||
</div>,
|
||||
.c3 {
|
||||
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;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
background-color: rgb(216,216,216);
|
||||
margin: 0;
|
||||
height: 0.0625rem;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
.c5 {
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.c0 + div:empty,
|
||||
.c0 + form:empty {
|
||||
.c4 + div:empty,
|
||||
.c4 + form:empty {
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
<div
|
||||
className="c0 c1"
|
||||
className=""
|
||||
>
|
||||
<div
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
className="c2 c3"
|
||||
height="0.0625rem"
|
||||
className="c1"
|
||||
>
|
||||
<div
|
||||
className="c2"
|
||||
>
|
||||
<svg
|
||||
className=""
|
||||
height="17"
|
||||
innerRef={undefined}
|
||||
style={
|
||||
Object {
|
||||
"transform": "rotate(0deg)",
|
||||
}
|
||||
}
|
||||
version="1.1"
|
||||
viewBox="0 0 16.24 13.55"
|
||||
width="17"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<path
|
||||
d="M.24,13.55c-1-2,1.39-6.73,1.52-7C4.47,1.5,6.77-.55,9,.12a2.34,2.34,0,0,1,1.4,1.16c.54,1.06-.26,2.41-1.18,4-.55.91-1.69,3.42-1.78,3.67-.37,1-.88,2.35-.52,2.86.19.28.73.34,1.14.34s1-.77,1.31-1.49c.56-1.48,1.87-4.94,4.1-4.27,1.78.53,1.27,2.56.93,3.91s-.11,1.51-.1,1.52a2.21,2.21,0,0,0,1.95-.24v1c-1.41.73-2.11.72-2.74.21-.88-.71-.48-2.19-.33-2.75.38-1.52.47-2.3-.07-2.46-.73-.22-1.6,1-2.57,3.52-.4,1.1-1.26,2.3-2.48,2.3a2.48,2.48,0,0,1-2.17-.88c-.72-1.05-.14-2.62.38-4,.09-.23,1.3-2.91,1.87-3.87s2.11-3.06.49-3.29S5.18,2.83,2.87,7.16c-1.71,3.21-1.78,5.95-1.62,6.39Z"
|
||||
fill="rgba(73, 73, 73, 1)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<small
|
||||
className="c3"
|
||||
/>
|
||||
</div>,
|
||||
]
|
||||
</div>
|
||||
<div
|
||||
className="c4 c5"
|
||||
>
|
||||
<div
|
||||
className="c6 c7"
|
||||
height="0.0625rem"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders <Title icon="Test" label="Instance name"/> without throwing 1`] = `
|
||||
Array [
|
||||
.c3 {
|
||||
.c3 {
|
||||
font-size: 80%;
|
||||
color: rgba(73,73,73,1);
|
||||
line-height: 1.125rem;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.c7 {
|
||||
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;
|
||||
}
|
||||
|
||||
.c6 {
|
||||
background-color: rgb(216,216,216);
|
||||
margin: 0;
|
||||
height: 0.0625rem;
|
||||
}
|
||||
|
||||
.c0 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
@ -327,96 +355,99 @@ Array [
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
<div
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
className="c1"
|
||||
>
|
||||
<div
|
||||
className="c2"
|
||||
>
|
||||
<svg
|
||||
className=""
|
||||
height="17"
|
||||
innerRef={undefined}
|
||||
style={
|
||||
Object {
|
||||
"transform": "rotate(0deg)",
|
||||
}
|
||||
}
|
||||
version="1.1"
|
||||
viewBox="0 0 16.24 13.55"
|
||||
width="17"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<path
|
||||
d="M.24,13.55c-1-2,1.39-6.73,1.52-7C4.47,1.5,6.77-.55,9,.12a2.34,2.34,0,0,1,1.4,1.16c.54,1.06-.26,2.41-1.18,4-.55.91-1.69,3.42-1.78,3.67-.37,1-.88,2.35-.52,2.86.19.28.73.34,1.14.34s1-.77,1.31-1.49c.56-1.48,1.87-4.94,4.1-4.27,1.78.53,1.27,2.56.93,3.91s-.11,1.51-.1,1.52a2.21,2.21,0,0,0,1.95-.24v1c-1.41.73-2.11.72-2.74.21-.88-.71-.48-2.19-.33-2.75.38-1.52.47-2.3-.07-2.46-.73-.22-1.6,1-2.57,3.52-.4,1.1-1.26,2.3-2.48,2.3a2.48,2.48,0,0,1-2.17-.88c-.72-1.05-.14-2.62.38-4,.09-.23,1.3-2.91,1.87-3.87s2.11-3.06.49-3.29S5.18,2.83,2.87,7.16c-1.71,3.21-1.78,5.95-1.62,6.39Z"
|
||||
fill="rgba(73, 73, 73, 1)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<small
|
||||
className="c3"
|
||||
/>
|
||||
</div>,
|
||||
.c3 {
|
||||
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;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
background-color: rgb(216,216,216);
|
||||
margin: 0;
|
||||
height: 0.0625rem;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
.c5 {
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.c0 + div:empty,
|
||||
.c0 + form:empty {
|
||||
.c4 + div:empty,
|
||||
.c4 + form:empty {
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
<div
|
||||
className="c0 c1"
|
||||
className=""
|
||||
label="Instance name"
|
||||
>
|
||||
<div
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
className="c2 c3"
|
||||
height="0.0625rem"
|
||||
className="c1"
|
||||
>
|
||||
<div
|
||||
className="c2"
|
||||
>
|
||||
<svg
|
||||
className=""
|
||||
height="17"
|
||||
innerRef={undefined}
|
||||
style={
|
||||
Object {
|
||||
"transform": "rotate(0deg)",
|
||||
}
|
||||
}
|
||||
version="1.1"
|
||||
viewBox="0 0 16.24 13.55"
|
||||
width="17"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<path
|
||||
d="M.24,13.55c-1-2,1.39-6.73,1.52-7C4.47,1.5,6.77-.55,9,.12a2.34,2.34,0,0,1,1.4,1.16c.54,1.06-.26,2.41-1.18,4-.55.91-1.69,3.42-1.78,3.67-.37,1-.88,2.35-.52,2.86.19.28.73.34,1.14.34s1-.77,1.31-1.49c.56-1.48,1.87-4.94,4.1-4.27,1.78.53,1.27,2.56.93,3.91s-.11,1.51-.1,1.52a2.21,2.21,0,0,0,1.95-.24v1c-1.41.73-2.11.72-2.74.21-.88-.71-.48-2.19-.33-2.75.38-1.52.47-2.3-.07-2.46-.73-.22-1.6,1-2.57,3.52-.4,1.1-1.26,2.3-2.48,2.3a2.48,2.48,0,0,1-2.17-.88c-.72-1.05-.14-2.62.38-4,.09-.23,1.3-2.91,1.87-3.87s2.11-3.06.49-3.29S5.18,2.83,2.87,7.16c-1.71,3.21-1.78,5.95-1.62,6.39Z"
|
||||
fill="rgba(73, 73, 73, 1)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<small
|
||||
className="c3"
|
||||
/>
|
||||
</div>,
|
||||
]
|
||||
</div>
|
||||
<div
|
||||
className="c4 c5"
|
||||
>
|
||||
<div
|
||||
className="c6 c7"
|
||||
height="0.0625rem"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders <Title label="Test"/> without throwing 1`] = `
|
||||
Array [
|
||||
.c3 {
|
||||
.c3 {
|
||||
font-size: 80%;
|
||||
color: rgba(73,73,73,1);
|
||||
line-height: 1.125rem;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.c7 {
|
||||
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;
|
||||
}
|
||||
|
||||
.c6 {
|
||||
background-color: rgb(216,216,216);
|
||||
margin: 0;
|
||||
height: 0.0625rem;
|
||||
}
|
||||
|
||||
.c0 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
@ -470,62 +501,41 @@ Array [
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
<div
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
className="c1"
|
||||
>
|
||||
<div
|
||||
className="c2"
|
||||
/>
|
||||
</div>
|
||||
<small
|
||||
className="c3"
|
||||
/>
|
||||
</div>,
|
||||
.c3 {
|
||||
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;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
background-color: rgb(216,216,216);
|
||||
margin: 0;
|
||||
height: 0.0625rem;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
.c5 {
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.c0 + div:empty,
|
||||
.c0 + form:empty {
|
||||
.c4 + div:empty,
|
||||
.c4 + form:empty {
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
<div
|
||||
className="c0 c1"
|
||||
className=""
|
||||
label="Test"
|
||||
>
|
||||
<div
|
||||
className="c0"
|
||||
>
|
||||
<div
|
||||
className="c2 c3"
|
||||
height="0.0625rem"
|
||||
className="c1"
|
||||
>
|
||||
<div
|
||||
className="c2"
|
||||
/>
|
||||
</div>
|
||||
<small
|
||||
className="c3"
|
||||
/>
|
||||
</div>,
|
||||
]
|
||||
</div>
|
||||
<div
|
||||
className="c4 c5"
|
||||
>
|
||||
<div
|
||||
className="c6 c7"
|
||||
height="0.0625rem"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -16,10 +16,8 @@ import {
|
||||
Button,
|
||||
Toggle,
|
||||
H4,
|
||||
Select,
|
||||
StatusLoader
|
||||
Select
|
||||
} from 'joyent-ui-toolkit';
|
||||
import Description from '@components/create-instance/description';
|
||||
|
||||
const fadeIn = keyframes`
|
||||
from {
|
||||
@ -88,7 +86,7 @@ const getImageByID = (id, images) => {
|
||||
const image = images
|
||||
.map(image => ({
|
||||
...image,
|
||||
versions: image.versions.filter(version => version.id === id)
|
||||
versions: (image.versions || []).filter(version => version.id === id)
|
||||
}))
|
||||
.filter(e => e.versions.length)[0];
|
||||
return image
|
||||
@ -100,105 +98,77 @@ const getImageByID = (id, images) => {
|
||||
: {};
|
||||
};
|
||||
|
||||
export const Preview = ({ imageID, images, isVmSelected, onEdit }) => (
|
||||
<Fragment>
|
||||
<Margin bottom={2} top={3}>
|
||||
<H3 bold>
|
||||
{titleCase(getImageByID(imageID, images).name)} -{' '}
|
||||
{getImageByID(imageID, images).version}
|
||||
</H3>
|
||||
<P>
|
||||
{isVmSelected ? 'Hardware Virtual Machine' : 'Infrastructure Container'}{' '}
|
||||
</P>
|
||||
</Margin>
|
||||
<Button type="button" secondary onClick={onEdit}>
|
||||
Edit
|
||||
</Button>
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
export default ({
|
||||
handleSubmit,
|
||||
pristine,
|
||||
expanded,
|
||||
imageID,
|
||||
onCancel,
|
||||
loading,
|
||||
images,
|
||||
images = [],
|
||||
isVmSelected
|
||||
}) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
{expanded && (
|
||||
<Fragment>
|
||||
<Description>
|
||||
Hardware virtual machines are generally used for non-containerized
|
||||
applications. Infrastructure containers are generally for running any
|
||||
Linux image on secure, bare metal containers.{' '}
|
||||
<a
|
||||
href="https://docs.joyent.com/private-cloud/images"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Read the docs
|
||||
</a>
|
||||
</Description>
|
||||
{loading ? (
|
||||
<StatusLoader />
|
||||
) : (
|
||||
<Fragment>
|
||||
<Margin bottom={4}>
|
||||
<FormGroup name="vms" field={Field}>
|
||||
<Flex alignCenter>
|
||||
<FormLabel>Infrastructure Container </FormLabel>
|
||||
<Toggle onBlur={null}>Hardware Virtual Machine</Toggle>
|
||||
</Flex>
|
||||
<Margin bottom={4}>
|
||||
<FormGroup name="vms" field={Field}>
|
||||
<Flex alignCenter>
|
||||
<FormLabel>Infrastructure Container </FormLabel>
|
||||
<Toggle onBlur={null}>Hardware Virtual Machine</Toggle>
|
||||
</Flex>
|
||||
</FormGroup>
|
||||
</Margin>
|
||||
<Row>
|
||||
{images &&
|
||||
images.filter(i => i.isVm === isVmSelected).map(image => (
|
||||
<Col md={2} sm={3}>
|
||||
<Card
|
||||
selected={
|
||||
image.imageName === getImageByID(imageID, images).imageName
|
||||
}
|
||||
>
|
||||
<img
|
||||
src={getImage(image.imageName).url}
|
||||
width={getImage(image.imageName).size}
|
||||
height={getImage(image.imageName).size}
|
||||
style={{
|
||||
marginBottom: getImage(image.imageName).bottom
|
||||
}}
|
||||
alt={image.imageName}
|
||||
/>
|
||||
<H4>{titleCase(image.imageName)}</H4>
|
||||
<FormGroup name="image" field={Field}>
|
||||
<Version onBlur={null}>
|
||||
<option selected>Version</option>
|
||||
{image.versions && image.versions.map(version => (
|
||||
<option
|
||||
key={`${version.name} - ${version.version}`}
|
||||
value={version.id}
|
||||
>{`${version.name} - ${version.version}`}</option>
|
||||
))}
|
||||
</Version>
|
||||
</FormGroup>
|
||||
</Margin>
|
||||
<Row>
|
||||
{images &&
|
||||
images.filter(i => i.isVm === isVmSelected).map(image => (
|
||||
<Col md={2} sm={3}>
|
||||
<Card
|
||||
selected={
|
||||
image.imageName ===
|
||||
getImageByID(imageID, images).imageName
|
||||
}
|
||||
>
|
||||
<img
|
||||
src={getImage(image.imageName).url}
|
||||
width={getImage(image.imageName).size}
|
||||
height={getImage(image.imageName).size}
|
||||
style={{
|
||||
marginBottom: getImage(image.imageName).bottom
|
||||
}}
|
||||
alt={image.imageName}
|
||||
/>
|
||||
<H4>{titleCase(image.imageName)}</H4>
|
||||
<FormGroup name="image" field={Field}>
|
||||
<Version onBlur={null}>
|
||||
<option selected>Version</option>
|
||||
{image.versions.map(version => (
|
||||
<option
|
||||
key={`${version.name} - ${version.version}`}
|
||||
value={version.id}
|
||||
>{`${version.name} - ${version.version}`}</option>
|
||||
))}
|
||||
</Version>
|
||||
</FormGroup>
|
||||
</Card>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
<Margin top={4}>
|
||||
<Button type="submit" disabled={pristine || !imageID}>
|
||||
Next
|
||||
</Button>
|
||||
</Margin>
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
{!expanded &&
|
||||
imageID && (
|
||||
<Fragment>
|
||||
<Margin bottom={2} top={3}>
|
||||
<H3 bold>
|
||||
{titleCase(getImageByID(imageID, images).name)} -{' '}
|
||||
{getImageByID(imageID, images).version}
|
||||
</H3>
|
||||
<P>
|
||||
{isVmSelected
|
||||
? 'Hardware Virtual Machine'
|
||||
: 'Infrastructure Container'}{' '}
|
||||
</P>
|
||||
</Margin>
|
||||
<Button type="button" secondary onClick={onCancel}>
|
||||
Edit
|
||||
</Button>
|
||||
</Fragment>
|
||||
)}
|
||||
</Card>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
<Margin top={4}>
|
||||
<Button type="submit" disabled={pristine || !imageID}>
|
||||
Next
|
||||
</Button>
|
||||
</Margin>
|
||||
</form>
|
||||
);
|
||||
|
@ -1,11 +1,10 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
import { Field } from 'redux-form';
|
||||
import { Margin } from 'styled-components-spacing';
|
||||
import Flex, { FlexItem } from 'styled-flex-component';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import {
|
||||
H3,
|
||||
FormGroup,
|
||||
FormLabel,
|
||||
Input,
|
||||
@ -20,64 +19,44 @@ export default ({
|
||||
handleSubmit,
|
||||
pristine,
|
||||
asyncValidating,
|
||||
expanded,
|
||||
name,
|
||||
placeholderName,
|
||||
randomizing,
|
||||
onCancel,
|
||||
onRandomize
|
||||
}) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
{expanded ? (
|
||||
<Fragment>
|
||||
<Description>
|
||||
Your instance name will be used to identify this specific instance.
|
||||
</Description>
|
||||
<Flex>
|
||||
<FlexItem>
|
||||
<FormGroup name="name" fluid field={Field}>
|
||||
<FormLabel>Instance Name</FormLabel>
|
||||
<Input placeholder={placeholderName} onBlur={null} />
|
||||
<FormMeta marginless />
|
||||
</FormGroup>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<FormLabel>⁣</FormLabel>
|
||||
<Margin left={1}>
|
||||
<Button
|
||||
type="button"
|
||||
marginTop={remcalc(8)}
|
||||
onClick={onRandomize}
|
||||
loading={randomizing}
|
||||
marginless
|
||||
secondary
|
||||
icon
|
||||
>
|
||||
<RandomizeIcon />
|
||||
<span>Randomize</span>
|
||||
</Button>
|
||||
</Margin>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
<Margin top={2} bottom={4}>
|
||||
<Button type="submit" disabled={pristine} loading={asyncValidating}>
|
||||
Next
|
||||
<Description>
|
||||
Your instance name will be used to identify this specific instance.
|
||||
</Description>
|
||||
<Flex>
|
||||
<FlexItem>
|
||||
<FormGroup name="name" fluid field={Field}>
|
||||
<FormLabel>Instance Name</FormLabel>
|
||||
<Input placeholder={placeholderName} onBlur={null} />
|
||||
<FormMeta marginless />
|
||||
</FormGroup>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<FormLabel>⁣</FormLabel>
|
||||
<Margin left={1}>
|
||||
<Button
|
||||
type="button"
|
||||
marginTop={remcalc(8)}
|
||||
onClick={onRandomize}
|
||||
loading={randomizing}
|
||||
marginless
|
||||
secondary
|
||||
icon
|
||||
>
|
||||
<RandomizeIcon />
|
||||
<span>Randomize</span>
|
||||
</Button>
|
||||
</Margin>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Fragment>
|
||||
{name ? (
|
||||
<Fragment>
|
||||
<Margin bottom={2} top={3}>
|
||||
<H3 bold>{name}</H3>
|
||||
</Margin>
|
||||
<Button type="button" secondary onClick={onCancel}>
|
||||
Edit
|
||||
</Button>
|
||||
</Fragment>
|
||||
) : null}
|
||||
</Fragment>
|
||||
)}
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
<Margin top={2} bottom={4}>
|
||||
<Button type="submit" disabled={pristine} loading={asyncValidating}>
|
||||
Next
|
||||
</Button>
|
||||
</Margin>
|
||||
</form>
|
||||
);
|
||||
|
@ -1,8 +1,9 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
import Flex from 'styled-flex-component';
|
||||
import { Margin } from 'styled-components-spacing';
|
||||
import remcalc from 'remcalc';
|
||||
import styled from 'styled-components';
|
||||
import is from 'styled-is';
|
||||
|
||||
import { Divider, Small } from 'joyent-ui-toolkit';
|
||||
|
||||
@ -13,8 +14,14 @@ const IsEmpty = styled(Margin)`
|
||||
}
|
||||
`;
|
||||
|
||||
export default ({ icon, children }) => (
|
||||
<Fragment>
|
||||
const Container = styled.div`
|
||||
${is('onClick')`
|
||||
cursor: pointer;
|
||||
`};
|
||||
`;
|
||||
|
||||
export default ({ icon, children, ...rest }) => (
|
||||
<Container {...rest}>
|
||||
<Flex>
|
||||
<Margin right={1}>
|
||||
<Flex alignCenter full>
|
||||
@ -26,5 +33,5 @@ export default ({ icon, children }) => (
|
||||
<IsEmpty top={1} bottom={3}>
|
||||
<Divider height={remcalc(1)} />
|
||||
</IsEmpty>
|
||||
</Fragment>
|
||||
</Container>
|
||||
);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -46,7 +46,12 @@ export const Affinity = ({
|
||||
rule
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Title icon={<AffinityIcon />}>Affinity</Title>
|
||||
<Title
|
||||
onClick={!expanded && !proceeded && handleEdit}
|
||||
icon={<AffinityIcon />}
|
||||
>
|
||||
Affinity
|
||||
</Title>
|
||||
{expanded ? (
|
||||
<Description>
|
||||
Control placement of instances on the physical servers. Design
|
||||
|
@ -54,7 +54,9 @@ const CNSContainer = ({
|
||||
loading
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Title icon={<CnsIcon />}>Container Name Service</Title>
|
||||
<Title onClick={!expanded && !proceeded && handleEdit} icon={<CnsIcon />}>
|
||||
Container Name Service
|
||||
</Title>
|
||||
{expanded ? (
|
||||
<Description>
|
||||
Triton CNS is used to automatically update hostnames for your
|
||||
|
@ -29,7 +29,12 @@ const Firewall = ({
|
||||
handleEdit
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Title icon={<FirewallIcon />}>Firewall</Title>
|
||||
<Title
|
||||
onClick={!expanded && !proceeded && handleEdit}
|
||||
icon={<FirewallIcon />}
|
||||
>
|
||||
Firewall
|
||||
</Title>
|
||||
{expanded ? (
|
||||
<Description>
|
||||
Cloud Firewall rules control traffic across instances. Enabling the
|
||||
@ -59,7 +64,8 @@ const Firewall = ({
|
||||
tagRules={tagRules}
|
||||
enabled={enabled}
|
||||
/>
|
||||
) : null}
|
||||
) : null
|
||||
}
|
||||
</ReduxForm>
|
||||
) : null}
|
||||
{proceeded && !expanded ? (
|
||||
|
@ -2,11 +2,13 @@ import React, { Fragment } from 'react';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import ReduxForm from 'declarative-redux-form';
|
||||
import { connect } from 'react-redux';
|
||||
import { set } from 'react-redux-values';
|
||||
import get from 'lodash.get';
|
||||
|
||||
import { InstanceTypeIcon } from 'joyent-ui-toolkit';
|
||||
import Image from '@components/create-instance/image';
|
||||
import { InstanceTypeIcon, StatusLoader } from 'joyent-ui-toolkit';
|
||||
import Image, { Preview } from '@components/create-instance/image';
|
||||
import Title from '@components/create-instance/title';
|
||||
import Description from '@components/create-instance/description';
|
||||
import imageData from '../../data/images-map.json';
|
||||
|
||||
import getImages from '../../graphql/get-images.gql';
|
||||
@ -14,31 +16,58 @@ import getImages from '../../graphql/get-images.gql';
|
||||
const ImageContainer = ({
|
||||
expanded,
|
||||
image,
|
||||
handleSubmit,
|
||||
handleCancel,
|
||||
handleNext,
|
||||
handleEdit,
|
||||
loading,
|
||||
images,
|
||||
vms
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Title icon={<InstanceTypeIcon />}>Instance type and image</Title>
|
||||
<Title
|
||||
onClick={!expanded && !image && handleEdit}
|
||||
icon={<InstanceTypeIcon />}
|
||||
>
|
||||
Instance type and image
|
||||
</Title>
|
||||
{expanded ? (
|
||||
<Description>
|
||||
Hardware virtual machines are generally used for non-containerized
|
||||
applications. Infrastructure containers are generally for running any
|
||||
Linux image on secure, bare metal containers.{' '}
|
||||
<a
|
||||
href="https://docs.joyent.com/private-cloud/images"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Read the docs
|
||||
</a>
|
||||
</Description>
|
||||
) : null}
|
||||
<ReduxForm
|
||||
form="create-instance-image"
|
||||
destroyOnUnmount={false}
|
||||
forceUnregisterOnUnmount={true}
|
||||
onSubmit={handleSubmit}
|
||||
onSubmit={handleNext}
|
||||
>
|
||||
{props => (
|
||||
<Image
|
||||
{...props}
|
||||
isVmSelected={vms}
|
||||
loading={loading}
|
||||
imageID={image}
|
||||
images={images}
|
||||
expanded={expanded}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
)}
|
||||
{props =>
|
||||
(loading && expanded) ? (
|
||||
<StatusLoader />
|
||||
) : expanded ? (
|
||||
<Image
|
||||
{...props}
|
||||
isVmSelected={vms}
|
||||
imageID={image}
|
||||
images={images}
|
||||
/>
|
||||
) : image ? (
|
||||
<Preview
|
||||
isVmSelected={vms}
|
||||
imageID={image}
|
||||
images={images}
|
||||
onEdit={handleEdit}
|
||||
/>
|
||||
) : null
|
||||
}
|
||||
</ReduxForm>
|
||||
</Fragment>
|
||||
);
|
||||
@ -53,8 +82,12 @@ export default compose(
|
||||
};
|
||||
},
|
||||
(dispatch, { history }) => ({
|
||||
handleSubmit: () => history.push(`/instances/~create/package`),
|
||||
handleCancel: () => history.push(`/instances/~create/image`)
|
||||
handleNext: () => {
|
||||
dispatch(set({ name: 'create-instance-image-proceeded', value: true }));
|
||||
|
||||
return history.push(`/instances/~create/package`);
|
||||
},
|
||||
handleEdit: () => history.push(`/instances/~create/image`)
|
||||
})
|
||||
),
|
||||
graphql(getImages, {
|
||||
|
@ -5,6 +5,7 @@ import { Margin } from 'styled-components-spacing';
|
||||
import ReduxForm from 'declarative-redux-form';
|
||||
import { stopSubmit, destroy } from 'redux-form';
|
||||
import { connect } from 'react-redux';
|
||||
import { destroyAll } from 'react-redux-values';
|
||||
import { graphql, compose } from 'react-apollo';
|
||||
import intercept from 'apr-intercept';
|
||||
import constantCase from 'constant-case';
|
||||
@ -28,43 +29,59 @@ import parseError from '@state/parse-error';
|
||||
|
||||
const CREATE_FORM = 'CREATE-INSTANCE';
|
||||
|
||||
const CreateInstance = ({ step, handleSubmit, ...props }) => (
|
||||
const CreateInstance = ({ step, disabled, handleSubmit, history, match }) => (
|
||||
<ViewContainer>
|
||||
<Margin top={4} bottom={4}>
|
||||
<H2>Create Instances</H2>
|
||||
</Margin>
|
||||
<Margin bottom={4}>
|
||||
<Name {...props} expanded={step === 'name'} />
|
||||
<Name history={history} match={match} expanded={step === 'name'} />
|
||||
</Margin>
|
||||
<Margin bottom={4}>
|
||||
<Image {...props} expanded={step === 'image'} />
|
||||
<Image history={history} match={match} expanded={step === 'image'} />
|
||||
</Margin>
|
||||
<Margin bottom={4}>
|
||||
<Package {...props} expanded={step === 'package'} />
|
||||
<Package history={history} match={match} expanded={step === 'package'} />
|
||||
</Margin>
|
||||
<Margin bottom={4}>
|
||||
<Tags {...props} expanded={step === 'tags'} />
|
||||
<Tags history={history} match={match} expanded={step === 'tags'} />
|
||||
</Margin>
|
||||
<Margin bottom={4}>
|
||||
<Metadata {...props} expanded={step === 'metadata'} />
|
||||
<Metadata
|
||||
history={history}
|
||||
match={match}
|
||||
expanded={step === 'metadata'}
|
||||
/>
|
||||
</Margin>
|
||||
<Margin bottom={4}>
|
||||
<Networks {...props} expanded={step === 'networks'} />
|
||||
<Networks
|
||||
history={history}
|
||||
match={match}
|
||||
expanded={step === 'networks'}
|
||||
/>
|
||||
</Margin>
|
||||
<Margin bottom={5}>
|
||||
<Firewall {...props} expanded={step === 'firewall'} />
|
||||
<Firewall
|
||||
history={history}
|
||||
match={match}
|
||||
expanded={step === 'firewall'}
|
||||
/>
|
||||
</Margin>
|
||||
<Margin bottom={4}>
|
||||
<CNS {...props} expanded={step === 'cns'} />
|
||||
<CNS history={history} match={match} expanded={step === 'cns'} />
|
||||
</Margin>
|
||||
<Margin bottom={4}>
|
||||
<Affinity {...props} expanded={step === 'affinity'} />
|
||||
<Affinity
|
||||
history={history}
|
||||
match={match}
|
||||
expanded={step === 'affinity'}
|
||||
/>
|
||||
</Margin>
|
||||
<Margin top={7} bottom={10}>
|
||||
<ReduxForm form={CREATE_FORM} onSubmit={handleSubmit}>
|
||||
{({ handleSubmit, submitting }) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Button disabled={step !== 'summary'} loading={submitting}>
|
||||
<Button disabled={disabled} loading={submitting}>
|
||||
Deploy
|
||||
</Button>
|
||||
</form>
|
||||
@ -76,14 +93,22 @@ const CreateInstance = ({ step, handleSubmit, ...props }) => (
|
||||
|
||||
export default compose(
|
||||
graphql(CreateInstanceMutation, { name: 'createInstance' }),
|
||||
connect(({ form, values }, ownProps) => {
|
||||
connect(({ form, values }, { step }) => {
|
||||
const disabled = ['name', 'image', 'package', 'networks'].some(
|
||||
step => !get(values, `create-instance-${step}-proceeded`, false)
|
||||
);
|
||||
|
||||
if (disabled) {
|
||||
return { disabled };
|
||||
}
|
||||
|
||||
const name = get(
|
||||
form,
|
||||
'create-instance-name.values.name',
|
||||
'<instance-name>'
|
||||
);
|
||||
|
||||
const firewall = get(
|
||||
const firewall_enabled = get(
|
||||
form,
|
||||
'CREATE-INSTANCE-FIREWALL.values.enabled',
|
||||
false
|
||||
@ -98,14 +123,10 @@ export default compose(
|
||||
const pkg = get(
|
||||
form,
|
||||
'create-instance-package.values.package',
|
||||
'<instance-image>'
|
||||
'<instance-pkg>'
|
||||
);
|
||||
|
||||
const networks = get(
|
||||
form,
|
||||
'CREATE-INSTANCE-NETWORKS.values',
|
||||
'<instance-image>'
|
||||
);
|
||||
const networks = get(form, 'CREATE-INSTANCE-NETWORKS.values', {});
|
||||
|
||||
const metadata = get(values, 'create-instance-metadata', []);
|
||||
const receivedTags = get(values, 'create-instance-tags', []);
|
||||
@ -121,52 +142,17 @@ export default compose(
|
||||
tags.push({ name: 'triton.cns.services', value: cnsServices.join(',') });
|
||||
}
|
||||
|
||||
const affRules = affinity
|
||||
.map(aff => ({
|
||||
conditional: aff['rule-instance-conditional'],
|
||||
placement: aff['rule-instance-placement'],
|
||||
identity: aff['rule-type'],
|
||||
key: aff['rule-instance-tag-key'],
|
||||
pattern: aff['rule-instance-tag-value-pattern'],
|
||||
value:
|
||||
aff['rule-type'] === 'name'
|
||||
? aff['rule-instance-name']
|
||||
: aff['rule-instance-tag-value']
|
||||
}))
|
||||
.map(({ conditional, placement, identity, key, pattern, value }) => {
|
||||
const type = constantCase(
|
||||
`${conditional}_${placement === 'same' ? 'equal' : 'not_equal'}`
|
||||
);
|
||||
|
||||
console.log(pattern);
|
||||
const patterns = {
|
||||
equalling: value => value,
|
||||
'not-equalling': value => `/^!${value}$/`,
|
||||
containing: value => `/${value}/`,
|
||||
starting: value => `/^${value}/`,
|
||||
ending: value => `/${value}$/`
|
||||
};
|
||||
|
||||
const _key = identity === 'name' ? 'instance' : key;
|
||||
const _value = patterns[pattern](value);
|
||||
|
||||
return {
|
||||
type,
|
||||
key: _key,
|
||||
value: _value
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
forms: Object.keys(form), // improve this
|
||||
name: name.toLowerCase(),
|
||||
name,
|
||||
pkg,
|
||||
image,
|
||||
affinity: affRules,
|
||||
metadata: metadata.map(a => omit(a, 'expanded')),
|
||||
tags: uniqBy(tags, 'name'),
|
||||
firewall_enabled: firewall,
|
||||
networks: Object.keys(networks).filter(network => networks[network])
|
||||
affinity,
|
||||
metadata,
|
||||
tags,
|
||||
firewall_enabled,
|
||||
networks,
|
||||
disabled
|
||||
};
|
||||
}),
|
||||
connect(null, (dispatch, ownProps) => {
|
||||
@ -186,17 +172,59 @@ export default compose(
|
||||
|
||||
return {
|
||||
handleSubmit: async () => {
|
||||
const _affinity = affinity
|
||||
.map(aff => ({
|
||||
conditional: aff['rule-instance-conditional'],
|
||||
placement: aff['rule-instance-placement'],
|
||||
identity: aff['rule-type'],
|
||||
key: aff['rule-instance-tag-key'],
|
||||
pattern: aff['rule-instance-tag-value-pattern'],
|
||||
value:
|
||||
aff['rule-type'] === 'name'
|
||||
? aff['rule-instance-name']
|
||||
: aff['rule-instance-tag-value']
|
||||
}))
|
||||
.map(({ conditional, placement, identity, key, pattern, value }) => {
|
||||
const type = constantCase(
|
||||
`${conditional}_${placement === 'same' ? 'equal' : 'not_equal'}`
|
||||
);
|
||||
|
||||
const patterns = {
|
||||
equalling: value => value,
|
||||
'not-equalling': value => `/^!${value}$/`,
|
||||
containing: value => `/${value}/`,
|
||||
starting: value => `/^${value}/`,
|
||||
ending: value => `/${value}$/`
|
||||
};
|
||||
|
||||
const _key = identity === 'name' ? 'instance' : key;
|
||||
const _value = patterns[pattern](value);
|
||||
|
||||
return {
|
||||
type,
|
||||
key: _key,
|
||||
value: _value
|
||||
};
|
||||
});
|
||||
|
||||
const _metadata = metadata.map(a => omit(a, 'expanded'));
|
||||
const _tags = uniqBy(tags, 'name');
|
||||
const _networks = Object.keys(networks).filter(
|
||||
network => networks[network]
|
||||
);
|
||||
const _name = name.toLowerCase();
|
||||
|
||||
const [err, res] = await intercept(
|
||||
createInstance({
|
||||
variables: {
|
||||
name,
|
||||
name: _name,
|
||||
package: pkg,
|
||||
image,
|
||||
affinity,
|
||||
metadata,
|
||||
tags,
|
||||
affinity: _affinity,
|
||||
metadata: _metadata,
|
||||
tags: _tags,
|
||||
firewall_enabled,
|
||||
networks
|
||||
networks: _networks
|
||||
}
|
||||
})
|
||||
);
|
||||
@ -209,7 +237,7 @@ export default compose(
|
||||
);
|
||||
}
|
||||
|
||||
dispatch(forms.map(name => destroy(name)));
|
||||
dispatch([destroyAll(), forms.map(name => destroy(name))]);
|
||||
|
||||
history.push(`/instances/${res.data.createMachine.name}`);
|
||||
}
|
||||
|
@ -31,7 +31,12 @@ export const Metadata = ({
|
||||
handleEdit
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Title icon={<MetadataIcon />}>Metadata</Title>
|
||||
<Title
|
||||
onClick={!expanded && !proceeded && handleEdit}
|
||||
icon={<MetadataIcon />}
|
||||
>
|
||||
Metadata
|
||||
</Title>
|
||||
{expanded ? (
|
||||
<Description>
|
||||
Metadata can be used to pass data to the instance. It can also be used
|
||||
|
@ -2,13 +2,14 @@ import React, { Fragment } from 'react';
|
||||
import { compose, graphql } from 'react-apollo';
|
||||
import { set } from 'react-redux-values';
|
||||
import ReduxForm from 'declarative-redux-form';
|
||||
import { Margin } from 'styled-components-spacing';
|
||||
import { change } from 'redux-form';
|
||||
import { connect } from 'react-redux';
|
||||
import intercept from 'apr-intercept';
|
||||
import get from 'lodash.get';
|
||||
import punycode from 'punycode';
|
||||
|
||||
import { NameIcon } from 'joyent-ui-toolkit';
|
||||
import { NameIcon, H3, Button } from 'joyent-ui-toolkit';
|
||||
|
||||
import Name from '@components/create-instance/name';
|
||||
import Title from '@components/create-instance/title';
|
||||
@ -17,7 +18,7 @@ import GetRandomName from '@graphql/get-random-name.gql';
|
||||
import { client } from '@state/store';
|
||||
import parseError from '@state/parse-error';
|
||||
|
||||
const FORM_NAME = 'CREATE_INSTANCE_NAME';
|
||||
const FORM_NAME = 'create-instance-name';
|
||||
|
||||
const NameContainer = ({
|
||||
expanded,
|
||||
@ -27,11 +28,13 @@ const NameContainer = ({
|
||||
handleAsyncValidation,
|
||||
shouldAsyncValidate,
|
||||
handleNext,
|
||||
handleCancel,
|
||||
handleRandomize
|
||||
handleRandomize,
|
||||
handleEdit
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Title icon={<NameIcon />}>Instance name</Title>
|
||||
<Title onClick={!expanded && !name && handleEdit} icon={<NameIcon />}>
|
||||
Instance name
|
||||
</Title>
|
||||
<ReduxForm
|
||||
form={FORM_NAME}
|
||||
destroyOnUnmount={false}
|
||||
@ -40,17 +43,25 @@ const NameContainer = ({
|
||||
asyncValidate={handleAsyncValidation}
|
||||
shouldAsyncValidate={shouldAsyncValidate}
|
||||
>
|
||||
{props => (
|
||||
<Name
|
||||
{...props}
|
||||
name={name}
|
||||
placeholderName={placeholderName}
|
||||
expanded={expanded}
|
||||
randomizing={randomizing}
|
||||
onCancel={handleCancel}
|
||||
onRandomize={handleRandomize}
|
||||
/>
|
||||
)}
|
||||
{props =>
|
||||
expanded ? (
|
||||
<Name
|
||||
{...props}
|
||||
placeholderName={placeholderName}
|
||||
randomizing={randomizing}
|
||||
onRandomize={handleRandomize}
|
||||
/>
|
||||
) : name ? (
|
||||
<Fragment>
|
||||
<Margin bottom={2} top={3}>
|
||||
<H3 bold>{name}</H3>
|
||||
</Margin>
|
||||
<Button type="button" secondary onClick={handleEdit}>
|
||||
Edit
|
||||
</Button>
|
||||
</Fragment>
|
||||
) : null
|
||||
}
|
||||
</ReduxForm>
|
||||
</Fragment>
|
||||
);
|
||||
@ -80,14 +91,21 @@ export default compose(
|
||||
(dispatch, { history }) => ({
|
||||
shouldAsyncValidate: ({ trigger }) => trigger === 'submit',
|
||||
handleAsyncValidation: async ({ name }) => {
|
||||
const sanitized = punycode.encode(name).replace(/\-$/, '');
|
||||
const sanitized = punycode.encode(name).replace(/-$/, '');
|
||||
|
||||
if (sanitized !== name) {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw {
|
||||
name: 'Special characters are not accepted'
|
||||
};
|
||||
}
|
||||
|
||||
if (!(/^[a-zA-Z0-9][a-zA-Z0-9\\_\\.\\-]*$/).test(name)) {
|
||||
throw {
|
||||
name: 'Invalid name'
|
||||
};
|
||||
}
|
||||
|
||||
const [err, res] = await intercept(
|
||||
client.query({
|
||||
fetchPolicy: 'network-only',
|
||||
@ -97,6 +115,7 @@ export default compose(
|
||||
);
|
||||
|
||||
if (err) {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw {
|
||||
name: parseError(err)
|
||||
};
|
||||
@ -106,13 +125,18 @@ export default compose(
|
||||
const { machines = [] } = data;
|
||||
|
||||
if (machines.length) {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw {
|
||||
name: `${name} already exists`
|
||||
};
|
||||
}
|
||||
},
|
||||
handleNext: () => history.push(`/instances/~create/image`),
|
||||
handleCancel: () => history.push(`/instances/~create/name`),
|
||||
handleNext: () => {
|
||||
dispatch(set({ name: 'create-instance-name-proceeded', value: true }));
|
||||
|
||||
return history.push(`/instances/~create/image`);
|
||||
},
|
||||
handleEdit: () => history.push(`/instances/~create/name`),
|
||||
handleRandomize: async () => {
|
||||
dispatch(
|
||||
set({ name: 'create-instance-name-randomizing', value: true })
|
||||
|
@ -29,7 +29,12 @@ export const Networks = ({
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Title icon={<NetworkIcon />}>Networks</Title>
|
||||
<Title
|
||||
onClick={!expanded && !proceeded && handleEdit}
|
||||
icon={<NetworkIcon />}
|
||||
>
|
||||
Networks
|
||||
</Title>
|
||||
{expanded ? (
|
||||
<Description>
|
||||
Instances are automatically connected to a private fabric network,
|
||||
|
@ -29,8 +29,8 @@ const FILTERS = 'create-instance-package-filters';
|
||||
const PackageContainer = ({
|
||||
expanded,
|
||||
hasVms,
|
||||
handleSubmit,
|
||||
handleCancel,
|
||||
handleNext,
|
||||
handleEdit,
|
||||
loading,
|
||||
packages,
|
||||
selected = {},
|
||||
@ -40,7 +40,12 @@ const PackageContainer = ({
|
||||
resetFilters
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Title icon={<PackageIcon />}>Package</Title>
|
||||
<Title
|
||||
onClick={!expanded && !selected.id && handleEdit}
|
||||
icon={<PackageIcon />}
|
||||
>
|
||||
Package
|
||||
</Title>
|
||||
<div>
|
||||
{expanded ? (
|
||||
<Description>
|
||||
@ -71,7 +76,7 @@ const PackageContainer = ({
|
||||
form={FORM_NAME}
|
||||
destroyOnUnmount={false}
|
||||
forceUnregisterOnUnmount={true}
|
||||
onSubmit={handleSubmit}
|
||||
onSubmit={handleNext}
|
||||
>
|
||||
{props => (
|
||||
<Fragment>
|
||||
@ -98,11 +103,7 @@ const PackageContainer = ({
|
||||
</Fragment>
|
||||
) : null}
|
||||
{!expanded && selected.id ? (
|
||||
<Overview
|
||||
{...selected}
|
||||
hasVms={hasVms}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
<Overview {...selected} hasVms={hasVms} onCancel={handleEdit} />
|
||||
) : null}
|
||||
</Fragment>
|
||||
)}
|
||||
@ -195,8 +196,14 @@ export default compose(
|
||||
};
|
||||
},
|
||||
(dispatch, { history }) => ({
|
||||
handleSubmit: () => history.push('/instances/~create/tags'),
|
||||
handleCancel: () => history.push('/instances/~create/package'),
|
||||
handleNext: () => {
|
||||
dispatch(
|
||||
set({ name: 'create-instance-package-proceeded', value: true })
|
||||
);
|
||||
|
||||
return history.push('/instances/~create/tags');
|
||||
},
|
||||
handleEdit: () => history.push('/instances/~create/package'),
|
||||
resetFilters: () => {
|
||||
dispatch(reset(`${FILTERS}-filters`));
|
||||
},
|
||||
|
@ -32,7 +32,9 @@ export const Tags = ({
|
||||
handleEdit
|
||||
}) => (
|
||||
<Fragment>
|
||||
<Title icon={<TagsIcon />}>Tags</Title>
|
||||
<Title onClick={!expanded && !proceeded && handleEdit} icon={<TagsIcon />}>
|
||||
Tags
|
||||
</Title>
|
||||
{expanded ? (
|
||||
<Description>
|
||||
Tags can be used to identify your instances, group multiple instances
|
||||
|
10
yarn.lock
10
yarn.lock
@ -6762,8 +6762,8 @@ multicast-dns-service-types@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
|
||||
|
||||
multicast-dns@^6.0.1:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.1.tgz#c5035defa9219d30640558a49298067352098060"
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.2.tgz#300b6133361f8aaaf2b8d1248e85c363fe5b95a0"
|
||||
dependencies:
|
||||
dns-packet "^1.0.1"
|
||||
thunky "^0.1.0"
|
||||
@ -8234,9 +8234,9 @@ react-popper@^0.7.4:
|
||||
popper.js "^1.12.5"
|
||||
prop-types "^15.5.10"
|
||||
|
||||
react-redux-values@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-redux-values/-/react-redux-values-1.0.2.tgz#f626997a1107626883147e45612cb8d1c0bce8fb"
|
||||
react-redux-values@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-redux-values/-/react-redux-values-1.1.2.tgz#e55e72fe74db1370e26aa96b27f15c262b1afa0c"
|
||||
dependencies:
|
||||
lodash.isundefined "^3.0.1"
|
||||
prop-types "^15.6.0"
|
||||
|
Loading…
Reference in New Issue
Block a user