feat(cp-frontend): improve review stage of deployment group creation

This commit is contained in:
Sérgio Ramos 2017-06-22 23:01:21 +01:00 committed by Judit Greskovits
parent 627761e98d
commit 2ea33c2a07
4 changed files with 135 additions and 29 deletions

View File

@ -1,9 +1,49 @@
import React from 'react';
import { FormGroup, FormMeta, Input, Button } from 'joyent-ui-toolkit';
import { Field } from 'redux-form';
import styled from 'styled-components';
import { Row, Col } from 'react-styled-flexboxgrid';
import { Dots2 } from 'styled-text-spinners';
import Bundle from 'react-bundle';
import remcalc from 'remcalc';
import forceArray from 'force-array';
import {
FormGroup,
FormMeta,
Input,
Button,
Card,
H3,
typography
} from 'joyent-ui-toolkit';
const Dl = styled.dl`
margin: ${remcalc(13)} ${remcalc(19)};
`;
const ServiceName = H3.extend`
margin-top: 0;
margin-bottom: 0;
line-height: 1.6;
font-weight: 600;
`;
const ServiceCard = Card.extend`
min-height: ${remcalc(72)};
`;
const ImageTitle = ServiceName.extend`
display: inline-block;
`;
const Image = styled.span`
${typography.fontFamily};
`;
const ButtonsRow = Row.extend`
margin-top: ${remcalc(29)};
margin-bottom: ${remcalc(60)};
`;
const Editor = ManifestEditor => ({ input }) =>
<ManifestEditor mode="yaml" {...input} />;
@ -18,13 +58,13 @@ export const Name = ({ handleSubmit, onCancel, dirty }) =>
</FormGroup>
</Col>
</Row>
<Row>
<ButtonsRow>
<Button onClick={onCancel} secondary>Cancel</Button>
<Button type="submit" disabled={!dirty}>Next</Button>
</Row>
</ButtonsRow>
</form>;
export const Manifest = ({ handleSubmit, onCancel, dirty, mode }) =>
export const Manifest = ({ handleSubmit, onCancel, dirty, mode, loading }) =>
<form onSubmit={handleSubmit}>
<Bundle load={() => import('joyent-manifest-editor')}>
{ManifestEditor =>
@ -32,22 +72,35 @@ export const Manifest = ({ handleSubmit, onCancel, dirty, mode }) =>
? <Field name="manifest" component={Editor(ManifestEditor)} />
: <Dots2 />}
</Bundle>
<Row>
<ButtonsRow>
<Button onClick={onCancel} secondary>Cancel</Button>
<Button type="submit" disabled={!dirty}>Review</Button>
</Row>
<Button disabled={loading || !dirty} type="submit">
{loading ? <Dots2 /> : 'Review'}
</Button>
</ButtonsRow>
</form>;
export const Review = ({ handleSubmit, onCancel, dirty, ...state }) =>
export const Review = ({ handleSubmit, onCancel, dirty, ...state }) => {
const serviceList = forceArray(state.services).map(({ name, image }) =>
<ServiceCard>
<Dl>
<dt><ServiceName>{name}</ServiceName></dt>
<dt><ImageTitle>Image:</ImageTitle> <Image>{image}</Image></dt>
</Dl>
</ServiceCard>
);
return (
<form onSubmit={handleSubmit}>
<pre>{state.deploymentGroupName}</pre>
<pre>{state.manifest}</pre>
<Row>
{serviceList}
<ButtonsRow>
<Button onClick={onCancel} disabled={state.loading} secondary>
Cancel
</Button>
<Button disabled={state.loading} type="submit">
{state.loading ? <Dots2 /> : 'Provision'}
{state.loading ? <Dots2 /> : 'Confirm and Deploy'}
</Button>
</Row>
</form>;
</ButtonsRow>
</form>
);
};

View File

@ -8,6 +8,7 @@ import paramCase from 'param-case';
import DeploymentGroupBySlug from '@graphql/DeploymentGroupBySlug.gql';
import DeploymentGroupCreateMutation from '@graphql/DeploymentGroupCreate.gql';
import DeploymentGroupProvisionMutation from '@graphql/DeploymentGroupProvision.gql';
import DeploymentGroupConfigMutation from '@graphql/DeploymentGroupConfig.gql';
import { client } from '@state/store';
import { LayoutContainer } from '@components/layout';
@ -52,8 +53,9 @@ const ReviewForm = reduxForm({
// state between refreshes
class DeploymentGroupCreate extends Component {
state = {
deploymentGroupName: '',
name: '',
manifest: '',
services: [],
loading: false,
error: null
};
@ -74,15 +76,40 @@ class DeploymentGroupCreate extends Component {
}
handleNameSubmit({ name = '' }) {
this.setState({ deploymentGroupName: name }, () =>
this.setState({ name }, () =>
this.redirect({ stage: 'manifest', prog: true })
);
}
handleManifestSubmit({ manifest = '' }) {
this.setState({ manifest }, () =>
this.redirect({ stage: 'review', prog: true })
const { config } = this.props;
const { name } = this.state;
const getConfig = async () => {
const [err, conf] = await intercept(
config({
deploymentGroupName: name,
type: 'COMPOSE',
format: 'YAML',
raw: manifest
})
);
if (err) {
return this.setState({
error: err.message
});
}
const { data } = conf;
const { config: services } = data;
this.setState({ loading: false, services }, () => {
this.redirect({ stage: 'review', prog: true });
});
};
this.setState({ manifest, loading: true }, getConfig);
}
handleReviewSubmit() {
@ -108,12 +135,10 @@ class DeploymentGroupCreate extends Component {
}
createDeploymentGroup = async () => {
const { deploymentGroupName } = this.state;
const { name } = this.state;
const { createDeploymentGroup } = this.props;
const [err, res] = await intercept(
createDeploymentGroup({ name: deploymentGroupName })
);
const [err, res] = await intercept(createDeploymentGroup({ name }));
if (err) {
this.setState({
@ -157,6 +182,7 @@ class DeploymentGroupCreate extends Component {
<ManifestForm
onSubmit={this.handleManifestSubmit}
onCancel={this.handleCancel}
loading={this.state.loading}
/>
);
}
@ -191,6 +217,7 @@ class DeploymentGroupCreate extends Component {
}
render() {
const { err } = this.state;
const { match } = this.props;
const stage = match.params.stage;
@ -202,11 +229,22 @@ class DeploymentGroupCreate extends Component {
return this.redirect({ stage: 'name' });
}
if (stage !== 'name' && !this.state.name) {
return this.redirect({ stage: 'name' });
}
if (stage === 'review' && !this.state.manifest) {
return this.redirect({ stage: 'manifest' });
}
const view = this.stages[stage]();
const error = err ? <span>{err}</span> : null;
return (
<LayoutContainer>
<H2>Creating deployment group</H2>
{error}
{view}
</LayoutContainer>
);
@ -223,5 +261,10 @@ export default compose(
props: ({ mutate }) => ({
provisionManifest: variables => mutate({ variables })
})
}),
graphql(DeploymentGroupConfigMutation, {
props: ({ mutate }) => ({
config: variables => mutate({ variables })
})
})
)(DeploymentGroupCreate);

View File

@ -53,7 +53,9 @@ const InstanceListGql = graphql(InstancesQuery, {
const params = props.match.params;
const deploymentGroupSlug = params.deploymentGroup;
const serviceSlug = params.service;
return {
pollInterval: 1000,
variables: {
deploymentGroupSlug,
serviceSlug

View File

@ -0,0 +1,8 @@
#import "./ServiceInfo.gql"
mutation config($deploymentGroupName: String!, $type: ManifestType!, $format: ManifestFormat!, $raw: String!) {
config(deploymentGroupName: $deploymentGroupName, type: $type, format: $format, raw: $raw) {
image
...ServiceInfo
}
}