joyent-portal/packages/my-joy-beta/src/containers/create-instance/image.js

225 lines
5.9 KiB
JavaScript

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, Button } from 'joyent-ui-toolkit';
import Image, { Preview, ImageType } from '@components/create-instance/image';
import Title from '@components/create-instance/title';
import Description from '@components/description';
import imageData from '@data/images-map.json';
import GetImages from '@graphql/get-images.gql';
const HarcodedImage = image => (
<Fragment>
<Title icon={<InstanceTypeIcon />} collapsed={false}>
Instance type and image
</Title>
<Margin bottom={7}>
<Preview {...image} />
</Margin>
</Fragment>
);
const ImageContainer = ({
expanded,
proceeded,
queryImage,
image = {},
handleNext,
handleEdit,
handleSelectLatest,
loading,
images,
vms,
step
}) =>
queryImage ? (
<Fragment>
<HarcodedImage {...queryImage} />
</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
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 }}
>
{props =>
loading && expanded ? (
<StatusLoader />
) : expanded ? (
<Image
{...props}
images={images.filter(i => i.isVm === vms)}
onSelectLatest={handleSelectLatest}
/>
) : image.id ? (
<Preview {...image} />
) : null
}
</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>
);
export default compose(
connect(
({ form, values }, ownProps) => {
const proceeded = get(values, 'create-instance-image-proceeded', false);
const vms = get(form, 'create-instance-vms.values.vms', false);
const image = get(form, 'create-instance-image.values.image', null);
return {
...ownProps,
proceeded: proceeded || image,
vms,
image
};
},
(dispatch, { history }) => ({
handleNext: () => {
dispatch(set({ name: 'create-instance-image-proceeded', value: true }));
return history.push(`/~create/package${history.location.search}`);
},
handleEdit: () =>
history.push(`/~create/image${history.location.search}`),
handleSelectLatest: ({ versions }) => {
const id = versions[0].id;
return dispatch(change('create-instance-image', 'image', id));
}
})
),
graphql(GetImages, {
options: () => ({
ssr: false
}),
props: ({ ownProps, data }) => {
const { image = '', query } = ownProps;
const { loading = false, images = [] } = data;
const queryImage = query.image
? find(images, ['name', query.image])
: null;
const values = images
.reduce((acc, img) => {
const isVm = !includes(img.type, 'DATASET');
const imageName =
imageData[
img.name
.split('-')[0]
.split(' ')[0]
.toLowerCase()
];
const exists = Boolean(find(acc, { imageName, isVm }));
const version = {
name: img.name,
version: img.version,
id: img.id
};
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,
queryImage,
image: {
...selected,
isVm: !includes(selected.type || '', 'DATASET')
}
};
}
})
)(ImageContainer);