2018-01-09 20:14:20 +02:00
|
|
|
import React, { Fragment } from 'react';
|
|
|
|
import { compose, graphql } from 'react-apollo';
|
|
|
|
import ReduxForm from 'declarative-redux-form';
|
2018-01-30 01:20:22 +02:00
|
|
|
import { change } from 'redux-form';
|
2018-01-09 20:14:20 +02:00
|
|
|
import { connect } from 'react-redux';
|
2018-01-18 16:46:49 +02:00
|
|
|
import { set } from 'react-redux-values';
|
2018-01-30 01:20:22 +02:00
|
|
|
import { Margin } from 'styled-components-spacing';
|
2018-01-24 13:28:42 +02:00
|
|
|
import includes from 'lodash.includes';
|
2018-01-30 01:20:22 +02:00
|
|
|
import sortBy from 'lodash.sortby';
|
|
|
|
import findIndex from 'lodash.findindex';
|
|
|
|
import find from 'lodash.find';
|
|
|
|
import reverse from 'lodash.reverse';
|
2018-01-09 20:14:20 +02:00
|
|
|
import get from 'lodash.get';
|
|
|
|
|
2018-01-30 01:20:22 +02:00
|
|
|
import { InstanceTypeIcon, StatusLoader, Button } from 'joyent-ui-toolkit';
|
2018-01-23 14:20:36 +02:00
|
|
|
|
2018-01-30 01:20:22 +02:00
|
|
|
import Image, { Preview, ImageType } from '@components/create-instance/image';
|
2018-01-09 20:14:20 +02:00
|
|
|
import Title from '@components/create-instance/title';
|
2018-01-30 18:04:03 +02:00
|
|
|
import Description from '@components/description';
|
2018-01-23 14:20:36 +02:00
|
|
|
import imageData from '@data/images-map.json';
|
2018-01-30 01:20:22 +02:00
|
|
|
import GetImages from '@graphql/get-images.gql';
|
2018-03-01 16:32:55 +02:00
|
|
|
import { Forms, Values } from '@root/constants';
|
|
|
|
|
|
|
|
const { IC_IMG_F } = Forms;
|
|
|
|
const { IC_IMG_V_PROCEEDED, IC_IMG_V_VMS } = Values;
|
2018-02-15 16:37:59 +02:00
|
|
|
|
2018-02-26 18:42:25 +02:00
|
|
|
const HarcodedImage = (image = {}) => (
|
2018-02-15 16:37:59 +02:00
|
|
|
<Fragment>
|
2018-03-06 03:14:33 +02:00
|
|
|
<Title icon={<InstanceTypeIcon />} collapsed={true}>
|
2018-02-15 16:37:59 +02:00
|
|
|
Instance type and image
|
|
|
|
</Title>
|
2018-02-26 18:42:25 +02:00
|
|
|
{image.id ? (
|
|
|
|
<ReduxForm
|
2018-03-01 16:32:55 +02:00
|
|
|
form={IC_IMG_F}
|
2018-02-26 18:42:25 +02:00
|
|
|
destroyOnUnmount={false}
|
|
|
|
forceUnregisterOnUnmount={true}
|
|
|
|
initialValues={{ image: image.id }}
|
|
|
|
>
|
|
|
|
{props => (
|
|
|
|
<Margin bottom={7}>
|
|
|
|
<Preview {...image} />
|
|
|
|
</Margin>
|
|
|
|
)}
|
|
|
|
</ReduxForm>
|
|
|
|
) : null}
|
2018-02-15 16:37:59 +02:00
|
|
|
</Fragment>
|
|
|
|
);
|
2018-01-09 20:14:20 +02:00
|
|
|
|
|
|
|
const ImageContainer = ({
|
|
|
|
expanded,
|
2018-01-30 01:20:22 +02:00
|
|
|
proceeded,
|
2018-02-26 18:42:25 +02:00
|
|
|
hardcoded,
|
2018-01-30 01:20:22 +02:00
|
|
|
image = {},
|
2018-01-18 16:46:49 +02:00
|
|
|
handleNext,
|
|
|
|
handleEdit,
|
2018-01-30 01:20:22 +02:00
|
|
|
handleSelectLatest,
|
2018-02-26 18:42:25 +02:00
|
|
|
setImageType,
|
2018-01-09 20:14:20 +02:00
|
|
|
loading,
|
|
|
|
images,
|
2018-01-30 18:27:01 +02:00
|
|
|
vms,
|
2018-02-26 18:42:25 +02:00
|
|
|
step
|
2018-02-22 01:02:09 +02:00
|
|
|
}) =>
|
2018-02-26 18:42:25 +02:00
|
|
|
hardcoded ? (
|
2018-02-22 01:02:09 +02:00
|
|
|
<Fragment>
|
2018-02-26 18:42:25 +02:00
|
|
|
<HarcodedImage {...image} />
|
2018-02-22 01:02:09 +02:00
|
|
|
</Fragment>
|
|
|
|
) : (
|
|
|
|
<Fragment>
|
|
|
|
<Title
|
|
|
|
id={step}
|
|
|
|
onClick={!expanded && !proceeded && handleEdit}
|
|
|
|
collapsed={!expanded && !proceeded}
|
|
|
|
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
|
2018-03-01 16:32:55 +02:00
|
|
|
form={IC_IMG_F}
|
2018-02-22 01:02:09 +02:00
|
|
|
destroyOnUnmount={false}
|
|
|
|
forceUnregisterOnUnmount={true}
|
|
|
|
initialValues={{ vms: true }}
|
|
|
|
>
|
|
|
|
{props =>
|
|
|
|
loading && expanded ? (
|
|
|
|
<StatusLoader />
|
|
|
|
) : expanded ? (
|
2018-02-26 15:47:52 +02:00
|
|
|
<Fragment>
|
|
|
|
<ImageType setImageType={setImageType} vms={vms} />
|
|
|
|
<Image
|
|
|
|
{...props}
|
|
|
|
images={images.filter(i => i.isVm === vms)}
|
|
|
|
onSelectLatest={handleSelectLatest}
|
|
|
|
/>
|
|
|
|
</Fragment>
|
2018-02-22 01:02:09 +02:00
|
|
|
) : image.id ? (
|
|
|
|
<Preview {...image} />
|
2018-02-26 18:42:25 +02:00
|
|
|
) : null
|
|
|
|
}
|
2018-02-22 01:02:09 +02:00
|
|
|
</ReduxForm>
|
|
|
|
{expanded ? (
|
|
|
|
<Margin top={1} bottom={7}>
|
|
|
|
<Button
|
|
|
|
type="button"
|
|
|
|
onClick={handleNext}
|
|
|
|
disabled={!image.id || vms !== image.isVm}
|
|
|
|
>
|
|
|
|
Next
|
|
|
|
</Button>
|
|
|
|
</Margin>
|
|
|
|
) : proceeded ? (
|
|
|
|
<Margin top={4} bottom={7}>
|
|
|
|
<Button type="button" onClick={handleEdit} secondary>
|
|
|
|
Edit
|
|
|
|
</Button>
|
|
|
|
</Margin>
|
|
|
|
) : null}
|
|
|
|
</Fragment>
|
|
|
|
);
|
2018-01-09 20:14:20 +02:00
|
|
|
|
|
|
|
export default compose(
|
|
|
|
connect(
|
2018-01-30 01:20:22 +02:00
|
|
|
({ form, values }, ownProps) => {
|
2018-03-01 16:32:55 +02:00
|
|
|
const proceeded = get(values, IC_IMG_V_PROCEEDED, false);
|
|
|
|
const image = get(form, `${IC_IMG_F}.values.image`, null);
|
|
|
|
const vms = get(values, IC_IMG_V_VMS, true);
|
2018-02-21 18:22:30 +02:00
|
|
|
|
2018-01-09 20:14:20 +02:00
|
|
|
return {
|
|
|
|
...ownProps,
|
2018-02-21 18:22:30 +02:00
|
|
|
proceeded: proceeded || image,
|
|
|
|
vms,
|
|
|
|
image
|
2018-01-09 20:14:20 +02:00
|
|
|
};
|
|
|
|
},
|
|
|
|
(dispatch, { history }) => ({
|
2018-01-18 16:46:49 +02:00
|
|
|
handleNext: () => {
|
2018-03-01 16:32:55 +02:00
|
|
|
dispatch(set({ name: IC_IMG_V_PROCEEDED, value: true }));
|
2018-03-06 03:14:33 +02:00
|
|
|
return history.push(
|
|
|
|
`/instances/~create/package${history.location.search}`
|
|
|
|
);
|
2018-01-18 16:46:49 +02:00
|
|
|
},
|
2018-02-26 18:42:25 +02:00
|
|
|
handleEdit: () => {
|
2018-03-06 03:14:33 +02:00
|
|
|
return history.push(
|
|
|
|
`/instances/~create/image${history.location.search}`
|
|
|
|
);
|
2018-02-26 18:42:25 +02:00
|
|
|
},
|
2018-01-30 01:20:22 +02:00
|
|
|
handleSelectLatest: ({ versions }) => {
|
2018-03-01 16:32:55 +02:00
|
|
|
return dispatch(change(IC_IMG_F, 'image', versions[0].id));
|
2018-02-26 15:47:52 +02:00
|
|
|
},
|
2018-02-27 17:23:29 +02:00
|
|
|
setImageType: isVm => {
|
2018-03-01 16:32:55 +02:00
|
|
|
return dispatch(set({ name: IC_IMG_V_VMS, value: isVm }));
|
2018-01-30 01:20:22 +02:00
|
|
|
}
|
2018-01-09 20:14:20 +02:00
|
|
|
})
|
|
|
|
),
|
2018-01-30 01:20:22 +02:00
|
|
|
graphql(GetImages, {
|
2018-02-20 02:35:31 +02:00
|
|
|
options: () => ({
|
|
|
|
ssr: false
|
|
|
|
}),
|
2018-01-30 01:20:22 +02:00
|
|
|
props: ({ ownProps, data }) => {
|
2018-02-15 16:37:59 +02:00
|
|
|
const { image = '', query } = ownProps;
|
2018-01-30 01:20:22 +02:00
|
|
|
const { loading = false, images = [] } = data;
|
2018-01-09 20:14:20 +02:00
|
|
|
|
2018-02-26 18:42:25 +02:00
|
|
|
if (query.image) {
|
|
|
|
return {
|
|
|
|
loading,
|
|
|
|
image: find(images, ['name', query.image], {}),
|
|
|
|
hardcoded: true
|
|
|
|
};
|
|
|
|
}
|
2018-02-15 16:37:59 +02:00
|
|
|
|
2018-01-30 01:20:22 +02:00
|
|
|
const values = images
|
|
|
|
.reduce((acc, img) => {
|
|
|
|
const isVm = !includes(img.type, 'DATASET');
|
2018-01-09 20:14:20 +02:00
|
|
|
|
2018-01-30 01:20:22 +02:00
|
|
|
const imageName =
|
|
|
|
imageData[
|
|
|
|
img.name
|
|
|
|
.split('-')[0]
|
|
|
|
.split(' ')[0]
|
|
|
|
.toLowerCase()
|
|
|
|
];
|
2018-01-09 20:14:20 +02:00
|
|
|
|
2018-01-30 01:20:22 +02:00
|
|
|
const exists = Boolean(find(acc, { imageName, isVm }));
|
2018-01-09 20:14:20 +02:00
|
|
|
|
2018-01-30 01:20:22 +02:00
|
|
|
const version = {
|
|
|
|
name: img.name,
|
|
|
|
version: img.version,
|
|
|
|
id: img.id
|
|
|
|
};
|
2018-01-09 20:14:20 +02:00
|
|
|
|
2018-01-30 01:20:22 +02:00
|
|
|
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']))
|
2018-01-09 20:14:20 +02:00
|
|
|
}));
|
2018-01-30 01:20:22 +02:00
|
|
|
|
|
|
|
const selected = find(images, ['id', image]) || {};
|
|
|
|
|
|
|
|
return {
|
|
|
|
loading,
|
|
|
|
images: values,
|
|
|
|
image: {
|
|
|
|
...selected,
|
|
|
|
isVm: !includes(selected.type || '', 'DATASET')
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2018-01-09 20:14:20 +02:00
|
|
|
})
|
|
|
|
)(ImageContainer);
|