fix(my-joy-beta): simplify create-instance images implementation

fixes #1027
fixes #1028
This commit is contained in:
Sérgio Ramos 2018-01-29 23:20:22 +00:00 committed by Sérgio Ramos
parent 26894e25d2
commit 0ce87d3edd
30 changed files with 237 additions and 2578 deletions

View File

@ -12,7 +12,7 @@
"lint-ci": "eslint . --ext .js --ext .md",
"lint": "eslint . --fix --ext .js --ext .md",
"test-ci": "NODE_ENV=test joyent-react-scripts test --env=jsdom --testPathIgnorePatterns='.ui.js'",
"test": "DEFAULT_TIMEOUT_INTERVAL=50000 NODE_ENV=test joyent-react-scripts test --env=jsdom",
"test": "DEFAULT_TIMEOUT_INTERVAL=80000 NODE_ENV=test joyent-react-scripts test --env=jsdom",
"prepublish": "echo 0"
},
"dependencies": {
@ -27,6 +27,7 @@
"joyent-manifest-editor": "3.0.1",
"joyent-ui-toolkit": "^4.5.0",
"lodash.find": "^4.6.0",
"lodash.findindex": "^4.6.0",
"lodash.get": "^4.4.2",
"lodash.includes": "^4.3.0",
"lodash.isarray": "^4.0.0",
@ -34,6 +35,7 @@
"lodash.isfunction": "^3.0.8",
"lodash.isstring": "^4.0.1",
"lodash.omit": "^4.5.0",
"lodash.reverse": "^4.0.1",
"lodash.sortby": "^4.7.0",
"lodash.uniqby": "^4.7.0",
"lunr": "^2.1.5",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -6,6 +6,7 @@ import Flex from 'styled-flex-component';
import remcalc from 'remcalc';
import { Row, Col } from 'react-styled-flexboxgrid';
import titleCase from 'title-case';
import includes from 'lodash.includes';
import {
H3,
@ -47,47 +48,54 @@ const getImage = name => {
}
};
const getImageByID = (id, images) => {
const image = images
.map(image => ({
...image,
versions: (image.versions || []).filter(version => version.id === id)
}))
.filter(e => e.versions.length)[0];
return image
? {
imageName: image.imageName,
name: image.versions[0].name,
version: image.versions[0].version
}
: {};
};
export const Preview = ({ imageID, images, isVmSelected, onEdit }) => (
export const Preview = ({ name, version, isVm }) => (
<Fragment>
<Margin bottom={2} top={3}>
<H3 bold>
{titleCase(getImageByID(imageID, images).name)} -{' '}
{getImageByID(imageID, images).version}
{name} - {version}
</H3>
<P>
{isVmSelected ? 'Hardware Virtual Machine' : 'Infrastructure Container'}{' '}
</P>
<P>{isVm ? 'Hardware Virtual Machine' : 'Infrastructure Container'} </P>
</Margin>
<Button type="button" secondary onClick={onEdit}>
Edit
</Button>
</Fragment>
);
export default ({
handleSubmit,
pristine,
imageID,
images = [],
isVmSelected
}) => (
<form onSubmit={handleSubmit}>
const Image = ({ onClick, active, ...image }) => {
const { imageName = '', versions = [] } = image;
const ids = [`image-card-${imageName}`, `image-img-${imageName}`];
const handleClick = ev =>
includes(ids, ev.target.id) ? onClick(image) : null;
return (
<Col md={2} sm={3}>
<Card id={ids[0]} onClick={handleClick} active={active} preview>
<img
id={ids[1]}
src={getImage(imageName).url}
width={getImage(imageName).size}
height={getImage(imageName).size}
style={{ marginBottom: getImage(imageName).bottom }}
alt={imageName}
/>
<H4>{titleCase(imageName)}</H4>
<FormGroup name="image" field={Field}>
<Version onBlur={null}>
<option selected>Version</option>
{versions.map(({ name, version, id }) => (
<option
key={`${name} - ${version}`}
value={id}
>{`${name} - ${version}`}</option>
))}
</Version>
</FormGroup>
</Card>
</Col>
);
};
export const ImageType = () => (
<form>
<Margin bottom={4}>
<FormGroup name="vms" field={Field}>
<Flex alignCenter>
@ -96,46 +104,20 @@ export default ({
</Flex>
</FormGroup>
</Margin>
<Row>
{images &&
images.filter(i => i.isVm === isVmSelected).map(image => (
<Col md={2} sm={3}>
<Card
active={
image.imageName === getImageByID(imageID, images).imageName
}
preview
>
<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>
</Card>
</Col>
))}
</Row>
<Margin top={4}>
<Button type="submit" disabled={pristine || !imageID}>
Next
</Button>
</Margin>
</form>
);
export default ({ images = [], onSelectLatest }) => (
<form>
<Row>
{images.map(({ imageName, ...image }) => (
<Image
{...image}
key={imageName}
imageName={imageName}
onClick={onSelectLatest}
/>
))}
</Row>
</form>
);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -1,31 +1,40 @@
import React, { Fragment } from 'react';
import { compose, graphql } from 'react-apollo';
import ReduxForm from 'declarative-redux-form';
import { change } from 'redux-form';
import { connect } from 'react-redux';
import { set } from 'react-redux-values';
import { Margin } from 'styled-components-spacing';
import includes from 'lodash.includes';
import sortBy from 'lodash.sortby';
import findIndex from 'lodash.findindex';
import find from 'lodash.find';
import reverse from 'lodash.reverse';
import get from 'lodash.get';
import { InstanceTypeIcon, StatusLoader } from 'joyent-ui-toolkit';
import { InstanceTypeIcon, StatusLoader, Button } from 'joyent-ui-toolkit';
import Description from '@components/description';
import Image, { Preview } from '@components/create-instance/image';
import Image, { Preview, ImageType } from '@components/create-instance/image';
import Title from '@components/create-instance/title';
import imageData from '@data/images-map.json';
import getImages from '@graphql/get-images.gql';
import GetImages from '@graphql/get-images.gql';
const ImageContainer = ({
expanded,
image,
proceeded,
image = {},
handleNext,
handleEdit,
handleSelectLatest,
loading,
images,
vms
}) => (
<Fragment>
{console.log({ image, vms })}
<Title
onClick={!expanded && !image && handleEdit}
onClick={!expanded && !image.id && handleEdit}
icon={<InstanceTypeIcon />}
>
Instance type and image
@ -44,12 +53,19 @@ const ImageContainer = ({
</a>
</Description>
) : null}
<ReduxForm
form="create-instance-vms"
destroyOnUnmount={false}
forceUnregisterOnUnmount={true}
initialValues={{ vms: true }}
>
{props => (loading || !expanded ? null : <ImageType {...props} />)}
</ReduxForm>
<ReduxForm
form="create-instance-image"
destroyOnUnmount={false}
forceUnregisterOnUnmount={true}
initialValues={{ vms: true }}
onSubmit={handleNext}
>
{props =>
loading && expanded ? (
@ -57,30 +73,44 @@ const ImageContainer = ({
) : expanded ? (
<Image
{...props}
isVmSelected={vms}
imageID={image}
images={images}
/>
) : image ? (
<Preview
isVmSelected={vms}
imageID={image}
images={images}
onEdit={handleEdit}
images={images.filter(i => i.isVm === vms)}
onSelectLatest={handleSelectLatest}
/>
) : image.id ? (
<Preview {...image} />
) : null
}
</ReduxForm>
<Fragment>
{expanded ? (
<Margin bottom={4}>
<Button
type="button"
onClick={handleNext}
disabled={!image.id || vms !== image.isVm}
>
Next
</Button>
</Margin>
) : proceeded ? (
<Margin bottom={4}>
<Button type="button" onClick={handleEdit} secondary>
Edit
</Button>
</Margin>
) : null}
</Fragment>
</Fragment>
);
export default compose(
connect(
(state, ownProps) => {
({ form, values }, ownProps) => {
return {
...ownProps,
vms: get(state, 'form.create-instance-image.values.vms', false),
image: get(state, 'form.create-instance-image.values.image', null)
proceeded: get(values, 'create-instance-image-proceeded', false),
vms: get(form, 'create-instance-vms.values.vms', false),
image: get(form, 'create-instance-image.values.image', null)
};
},
(dispatch, { history }) => ({
@ -89,58 +119,76 @@ export default compose(
return history.push(`/instances/~create/package`);
},
handleEdit: () => history.push(`/instances/~create/image`)
handleEdit: () => history.push(`/instances/~create/image`),
handleSelectLatest: ({ versions }) => {
const id = versions[versions.length - 1].id;
return dispatch(change('create-instance-image', 'image', id));
}
})
),
graphql(getImages, {
props: ({ ownProps: { vms = false }, data: { loading, images = [] } }) => ({
loading,
images: images.reduce((accumulator, image) => {
const isVm = !includes(image.type, 'DATASET');
graphql(GetImages, {
props: ({ ownProps, data }) => {
const { image = '' } = ownProps;
const { loading = false, images = [] } = data;
if (isVm && !vms) {
return accumulator;
}
const values = images
.reduce((acc, img) => {
const isVm = !includes(img.type, 'DATASET');
const name =
imageData[
image.name
.split('-')[0]
.split(' ')[0]
.toLowerCase()
];
const imageName =
imageData[
img.name
.split('-')[0]
.split(' ')[0]
.toLowerCase()
];
const exists = Boolean(
accumulator.filter(e => e.imageName === name && isVm === e.isVm)
.length
);
const exists = Boolean(find(acc, { imageName, isVm }));
if (!exists) {
return accumulator.concat([
{
imageName: name,
versions: [
{
name: image.name,
version: image.version,
id: image.id
}
],
isVm
}
]);
}
const version = {
name: img.name,
version: img.version,
id: img.id
};
return accumulator.map(({ versions, ...rest }) => ({
...rest,
versions:
rest.imageName === name && rest.isVm === isVm
? versions.concat([
{ name: image.name, version: image.version, id: image.id }
])
: versions
if (!exists) {
return acc.concat([
{
isVm,
imageName,
versions: [version]
}
]);
}
const index = findIndex(acc, {
imageName,
isVm
});
acc[index] = {
...acc[index],
versions: acc[index].versions.concat([version])
};
return acc;
}, [])
.map(({ versions, ...img }) => ({
...img,
active: Boolean(find(versions, ['id', image])),
versions: reverse(sortBy(versions, ['name']))
}));
}, [])
})
const selected = find(images, ['id', image]) || {};
return {
loading,
images: values,
image: {
...selected,
isVm: !includes(selected.type || '', 'DATASET')
}
};
}
})
)(ImageContainer);

View File

@ -8,6 +8,7 @@ import { set } from 'react-redux-values';
import sortBy from 'lodash.sortby';
import find from 'lodash.find';
import includes from 'lodash.includes';
import reverse from 'lodash.reverse';
import constantCase from 'constant-case';
import { reset } from 'redux-form';
@ -192,7 +193,7 @@ export default compose(
...ownProps,
sortBy: _sortBy,
sortOrder: _sortOrder,
packages: _sortOrder === 'asc' ? filtered : filtered.reverse(),
packages: _sortOrder === 'asc' ? filtered : reverse(filtered),
hasVms: vmSelected,
selected: find(packages, ['id', pkgSelected])
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -8,6 +8,7 @@ import forceArray from 'force-array';
import get from 'lodash.get';
import intercept from 'apr-intercept';
import find from 'lodash.find';
import reverse from 'lodash.reverse';
import sort from 'lodash.sortby';
import remcalc from 'remcalc';
@ -231,7 +232,7 @@ export default compose(
return {
// is sortOrder !== asc, reverse order
instances: sortOrder === 'asc' ? ascSorted : ascSorted.reverse(),
instances: sortOrder === 'asc' ? ascSorted : reverse(ascSorted),
allowedActions,
selected,
statuses,

View File

@ -5,6 +5,7 @@ import { set } from 'react-redux-values';
import forceArray from 'force-array';
import { Margin } from 'styled-components-spacing';
import find from 'lodash.find';
import reverse from 'lodash.reverse';
import sortBy from 'lodash.sortby';
import get from 'lodash.get';
@ -82,7 +83,7 @@ export default compose(
const instance = find(forceArray(machines), ['name', name]);
const values = get(instance, 'networks', []);
const networks = sortBy(values, 'public').reverse();
const networks = reverse(sortBy(values, 'public'));
return {
networks,

View File

@ -4,6 +4,7 @@ import { connect } from 'react-redux';
import { stopSubmit, startSubmit, change, reset } from 'redux-form';
import { compose, graphql } from 'react-apollo';
import find from 'lodash.find';
import reverse from 'lodash.reverse';
import get from 'lodash.get';
import sort from 'lodash.sortby';
import { set } from 'react-redux-values';
@ -223,7 +224,7 @@ export default compose(
return {
...rest,
snapshots: sortOrder === 'asc' ? ascSorted : ascSorted.reverse(),
snapshots: sortOrder === 'asc' ? ascSorted : reverse(ascSorted),
selected,
sortBy,
sortOrder,

View File

@ -107,6 +107,10 @@ const Preview = styled.div`
margin-bottom: ${remcalc(20)};
animation: ${fadeIn} 0.2s ease-in-out;
${is('onClick')`
cursor: pointer;
`};
${is('active')`
border: ${remcalc(1)} solid ${props => props.theme.primaryActive};

View File

@ -6662,6 +6662,10 @@ lodash.find@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
lodash.findindex@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.findindex/-/lodash.findindex-4.6.0.tgz#a3245dee61fb9b6e0624b535125624bb69c11106"
lodash.flatten@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
@ -6746,6 +6750,10 @@ lodash.pick@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
lodash.reverse@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.reverse/-/lodash.reverse-4.0.1.tgz#1f2afedace2e16e660f3aa7c59d3300a6f25d13c"
lodash.some@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"