import React, { Component } from 'react'; import { reduxForm } from 'redux-form'; import { compose, graphql } from 'react-apollo'; import { Redirect } from 'react-router-dom'; import intercept from 'apr-intercept'; import PropTypes from 'prop-types'; import paramCase from 'param-case'; import DeploymentGroupBySlug from '@graphql/DeploymentGroupBySlug.gql'; import DeploymentGroupCreateMutation from '@graphql/DeploymentGroupCreate.gql'; import DeploymentGroupProvisionMutation from '@graphql/DeploymentGroupProvision.gql'; import { client } from '@state/store'; import { LayoutContainer } from '@components/layout'; import { Name, Manifest, Review } from '@components/deployment-groups/create'; import { H2 } from 'joyent-ui-toolkit'; const Title = H2.extend` margin-top: 0; `; const validateName = async ({ name = '' }) => { const { data } = await client.query({ fetchPolicy: 'network-only', query: DeploymentGroupBySlug, variables: { slug: paramCase(name.trim()) } }); if (data.deploymentGroups.length) { throw { name: `"${name}" already exists!` }; } }; const NameForm = reduxForm({ form: 'create-deployment-group', destroyOnUnmount: true, forceUnregisterOnUnmount: true, asyncValidate: validateName })(Name); const ManifestForm = reduxForm({ form: 'create-deployment-group', destroyOnUnmount: true, forceUnregisterOnUnmount: true })(Manifest); const ReviewForm = reduxForm({ form: 'create-deployment-group', destroyOnUnmount: true, forceUnregisterOnUnmount: true })(Review); // TODO: move state to redux. why: because in redux we can cache transactional // state between refreshes class DeploymentGroupCreate extends Component { state = { deploymentGroupName: '', manifest: '', loading: false, error: null }; constructor() { super(); this.stages = { name: this.renderNameForm.bind(this), manifest: this.renderManifestEditor.bind(this), review: this.renderReview.bind(this) }; this.handleNameSubmit = this.handleNameSubmit.bind(this); this.handleManifestSubmit = this.handleManifestSubmit.bind(this); this.handleReviewSubmit = this.handleReviewSubmit.bind(this); this.handleCancel = this.handleCancel.bind(this); } handleNameSubmit({ name = '' }) { this.setState({ deploymentGroupName: name }, () => this.redirect({ stage: 'manifest', prog: true }) ); } handleManifestSubmit({ manifest = '' }) { this.setState({ manifest }, () => this.redirect({ stage: 'review', prog: true }) ); } handleReviewSubmit() { const { history } = this.props; const submit = async () => { const { id, slug } = await this.createDeploymentGroup(); if (!id) { return; } const manifest = await this.provision(id); if (!manifest) { return; } history.push(`/deployment-groups/${slug}`); }; this.setState({ loading: true }, submit); } createDeploymentGroup = async () => { const { deploymentGroupName } = this.state; const { createDeploymentGroup } = this.props; const [err, res] = await intercept( createDeploymentGroup({ name: deploymentGroupName }) ); if (err) { this.setState({ error: err.message }); } return err ? null : res.data.createDeploymentGroup; }; provision = async deploymentGroupId => { const { manifest } = this.state; const { provisionManifest } = this.props; const [err, { data }] = await intercept( provisionManifest({ deploymentGroupId, type: 'COMPOSE', format: 'YAML', raw: manifest }) ); if (err) { this.setState({ error: err.message }); } return err ? null : true; }; renderNameForm() { return ( ); } renderManifestEditor() { return ( ); } renderReview() { return ( ); } handleCancel() { const { history } = this.props; history.push('/'); } redirect({ stage = 'name', prog = false }) { const { match, history } = this.props; const pathname = match.url.replace(/~create(.*)/, '~create'); const to = `${pathname}/${stage}`; if (!prog) { return ; } history.push(to); } render() { const { match } = this.props; const stage = match.params.stage; if (!stage) { return this.redirect({ stage: 'name' }); } if (!this.stages[stage]) { return this.redirect({ stage: 'name' }); } const view = this.stages[stage](); return ( Creating deployment group {view} ); } } export default compose( graphql(DeploymentGroupCreateMutation, { props: ({ mutate }) => ({ createDeploymentGroup: variables => mutate({ variables }) }) }), graphql(DeploymentGroupProvisionMutation, { props: ({ mutate }) => ({ provisionManifest: variables => mutate({ variables }) }) }) )(DeploymentGroupCreate);