feat(cp-frontend): improve review stage of deployment group creation
This commit is contained in:
parent
627761e98d
commit
2ea33c2a07
@ -1,9 +1,49 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormGroup, FormMeta, Input, Button } from 'joyent-ui-toolkit';
|
|
||||||
import { Field } from 'redux-form';
|
import { Field } from 'redux-form';
|
||||||
|
import styled from 'styled-components';
|
||||||
import { Row, Col } from 'react-styled-flexboxgrid';
|
import { Row, Col } from 'react-styled-flexboxgrid';
|
||||||
import { Dots2 } from 'styled-text-spinners';
|
import { Dots2 } from 'styled-text-spinners';
|
||||||
import Bundle from 'react-bundle';
|
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 }) =>
|
const Editor = ManifestEditor => ({ input }) =>
|
||||||
<ManifestEditor mode="yaml" {...input} />;
|
<ManifestEditor mode="yaml" {...input} />;
|
||||||
@ -18,13 +58,13 @@ export const Name = ({ handleSubmit, onCancel, dirty }) =>
|
|||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<ButtonsRow>
|
||||||
<Button onClick={onCancel} secondary>Cancel</Button>
|
<Button onClick={onCancel} secondary>Cancel</Button>
|
||||||
<Button type="submit" disabled={!dirty}>Next</Button>
|
<Button type="submit" disabled={!dirty}>Next</Button>
|
||||||
</Row>
|
</ButtonsRow>
|
||||||
</form>;
|
</form>;
|
||||||
|
|
||||||
export const Manifest = ({ handleSubmit, onCancel, dirty, mode }) =>
|
export const Manifest = ({ handleSubmit, onCancel, dirty, mode, loading }) =>
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<Bundle load={() => import('joyent-manifest-editor')}>
|
<Bundle load={() => import('joyent-manifest-editor')}>
|
||||||
{ManifestEditor =>
|
{ManifestEditor =>
|
||||||
@ -32,22 +72,35 @@ export const Manifest = ({ handleSubmit, onCancel, dirty, mode }) =>
|
|||||||
? <Field name="manifest" component={Editor(ManifestEditor)} />
|
? <Field name="manifest" component={Editor(ManifestEditor)} />
|
||||||
: <Dots2 />}
|
: <Dots2 />}
|
||||||
</Bundle>
|
</Bundle>
|
||||||
<Row>
|
<ButtonsRow>
|
||||||
<Button onClick={onCancel} secondary>Cancel</Button>
|
<Button onClick={onCancel} secondary>Cancel</Button>
|
||||||
<Button type="submit" disabled={!dirty}>Review</Button>
|
<Button disabled={loading || !dirty} type="submit">
|
||||||
</Row>
|
{loading ? <Dots2 /> : 'Review'}
|
||||||
|
</Button>
|
||||||
|
</ButtonsRow>
|
||||||
</form>;
|
</form>;
|
||||||
|
|
||||||
export const Review = ({ handleSubmit, onCancel, dirty, ...state }) =>
|
export const Review = ({ handleSubmit, onCancel, dirty, ...state }) => {
|
||||||
<form onSubmit={handleSubmit}>
|
const serviceList = forceArray(state.services).map(({ name, image }) =>
|
||||||
<pre>{state.deploymentGroupName}</pre>
|
<ServiceCard>
|
||||||
<pre>{state.manifest}</pre>
|
<Dl>
|
||||||
<Row>
|
<dt><ServiceName>{name}</ServiceName></dt>
|
||||||
<Button onClick={onCancel} disabled={state.loading} secondary>
|
<dt><ImageTitle>Image:</ImageTitle> <Image>{image}</Image></dt>
|
||||||
Cancel
|
</Dl>
|
||||||
</Button>
|
</ServiceCard>
|
||||||
<Button disabled={state.loading} type="submit">
|
);
|
||||||
{state.loading ? <Dots2 /> : 'Provision'}
|
|
||||||
</Button>
|
return (
|
||||||
</Row>
|
<form onSubmit={handleSubmit}>
|
||||||
</form>;
|
{serviceList}
|
||||||
|
<ButtonsRow>
|
||||||
|
<Button onClick={onCancel} disabled={state.loading} secondary>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button disabled={state.loading} type="submit">
|
||||||
|
{state.loading ? <Dots2 /> : 'Confirm and Deploy'}
|
||||||
|
</Button>
|
||||||
|
</ButtonsRow>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -8,6 +8,7 @@ import paramCase from 'param-case';
|
|||||||
import DeploymentGroupBySlug from '@graphql/DeploymentGroupBySlug.gql';
|
import DeploymentGroupBySlug from '@graphql/DeploymentGroupBySlug.gql';
|
||||||
import DeploymentGroupCreateMutation from '@graphql/DeploymentGroupCreate.gql';
|
import DeploymentGroupCreateMutation from '@graphql/DeploymentGroupCreate.gql';
|
||||||
import DeploymentGroupProvisionMutation from '@graphql/DeploymentGroupProvision.gql';
|
import DeploymentGroupProvisionMutation from '@graphql/DeploymentGroupProvision.gql';
|
||||||
|
import DeploymentGroupConfigMutation from '@graphql/DeploymentGroupConfig.gql';
|
||||||
|
|
||||||
import { client } from '@state/store';
|
import { client } from '@state/store';
|
||||||
import { LayoutContainer } from '@components/layout';
|
import { LayoutContainer } from '@components/layout';
|
||||||
@ -52,8 +53,9 @@ const ReviewForm = reduxForm({
|
|||||||
// state between refreshes
|
// state between refreshes
|
||||||
class DeploymentGroupCreate extends Component {
|
class DeploymentGroupCreate extends Component {
|
||||||
state = {
|
state = {
|
||||||
deploymentGroupName: '',
|
name: '',
|
||||||
manifest: '',
|
manifest: '',
|
||||||
|
services: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null
|
error: null
|
||||||
};
|
};
|
||||||
@ -74,15 +76,40 @@ class DeploymentGroupCreate extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleNameSubmit({ name = '' }) {
|
handleNameSubmit({ name = '' }) {
|
||||||
this.setState({ deploymentGroupName: name }, () =>
|
this.setState({ name }, () =>
|
||||||
this.redirect({ stage: 'manifest', prog: true })
|
this.redirect({ stage: 'manifest', prog: true })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleManifestSubmit({ manifest = '' }) {
|
handleManifestSubmit({ manifest = '' }) {
|
||||||
this.setState({ manifest }, () =>
|
const { config } = this.props;
|
||||||
this.redirect({ stage: 'review', prog: true })
|
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() {
|
handleReviewSubmit() {
|
||||||
@ -108,12 +135,10 @@ class DeploymentGroupCreate extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createDeploymentGroup = async () => {
|
createDeploymentGroup = async () => {
|
||||||
const { deploymentGroupName } = this.state;
|
const { name } = this.state;
|
||||||
const { createDeploymentGroup } = this.props;
|
const { createDeploymentGroup } = this.props;
|
||||||
|
|
||||||
const [err, res] = await intercept(
|
const [err, res] = await intercept(createDeploymentGroup({ name }));
|
||||||
createDeploymentGroup({ name: deploymentGroupName })
|
|
||||||
);
|
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -157,6 +182,7 @@ class DeploymentGroupCreate extends Component {
|
|||||||
<ManifestForm
|
<ManifestForm
|
||||||
onSubmit={this.handleManifestSubmit}
|
onSubmit={this.handleManifestSubmit}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
|
loading={this.state.loading}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -191,6 +217,7 @@ class DeploymentGroupCreate extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { err } = this.state;
|
||||||
const { match } = this.props;
|
const { match } = this.props;
|
||||||
const stage = match.params.stage;
|
const stage = match.params.stage;
|
||||||
|
|
||||||
@ -202,11 +229,22 @@ class DeploymentGroupCreate extends Component {
|
|||||||
return this.redirect({ stage: 'name' });
|
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 view = this.stages[stage]();
|
||||||
|
|
||||||
|
const error = err ? <span>{err}</span> : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutContainer>
|
<LayoutContainer>
|
||||||
<H2>Creating deployment group</H2>
|
<H2>Creating deployment group</H2>
|
||||||
|
{error}
|
||||||
{view}
|
{view}
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
@ -223,5 +261,10 @@ export default compose(
|
|||||||
props: ({ mutate }) => ({
|
props: ({ mutate }) => ({
|
||||||
provisionManifest: variables => mutate({ variables })
|
provisionManifest: variables => mutate({ variables })
|
||||||
})
|
})
|
||||||
|
}),
|
||||||
|
graphql(DeploymentGroupConfigMutation, {
|
||||||
|
props: ({ mutate }) => ({
|
||||||
|
config: variables => mutate({ variables })
|
||||||
|
})
|
||||||
})
|
})
|
||||||
)(DeploymentGroupCreate);
|
)(DeploymentGroupCreate);
|
||||||
|
@ -53,7 +53,9 @@ const InstanceListGql = graphql(InstancesQuery, {
|
|||||||
const params = props.match.params;
|
const params = props.match.params;
|
||||||
const deploymentGroupSlug = params.deploymentGroup;
|
const deploymentGroupSlug = params.deploymentGroup;
|
||||||
const serviceSlug = params.service;
|
const serviceSlug = params.service;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
pollInterval: 1000,
|
||||||
variables: {
|
variables: {
|
||||||
deploymentGroupSlug,
|
deploymentGroupSlug,
|
||||||
serviceSlug
|
serviceSlug
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user