joyent-portal/packages/my-joy-instances/src/containers/create-instance/affinity.js

230 lines
6.5 KiB
JavaScript
Raw Normal View History

import React, { Fragment } from 'react';
import { set } from 'react-redux-values';
import { Margin } from 'styled-components-spacing';
import { compose } from 'react-apollo';
import { destroy, reset } from 'redux-form';
import ReduxForm from 'declarative-redux-form';
import { connect } from 'react-redux';
import get from 'lodash.get';
import remcalc from 'remcalc';
2018-03-01 03:15:16 +02:00
import { AffinityIcon, Button, Divider, KeyValue } from 'joyent-ui-toolkit';
import Title from '@components/create-instance/title';
import { Rule, Header } from '@components/create-instance/affinity';
import Description from '@components/description';
2018-03-01 03:15:16 +02:00
import { addAffinityRule as validateRule } from '@state/validators';
2018-03-01 16:32:55 +02:00
import { Forms, Values } from '@root/constants';
2018-03-01 16:32:55 +02:00
const { IC_AFF_F_ADD, IC_AFF_F_EDIT } = Forms;
const { IC_AFF_V_ADD_OPEN, IC_AFF_V_EDIT_OPEN, IC_AFF_V_AFF } = Values;
const RULE_DEFAULTS = {
2018-03-01 03:15:16 +02:00
conditional: 'should',
placement: 'same',
type: 'name',
pattern: 'equalling',
name: '',
2018-03-01 03:15:16 +02:00
value: ''
};
export const Affinity = ({
2018-03-01 03:15:16 +02:00
step,
expanded,
addOpen,
2018-03-01 03:15:16 +02:00
editOpen,
editingRule,
creatingRule,
exitingRule,
shouldAsyncValidate,
handleAsyncValidate,
handleCreateAffinityRules,
handleRemoveAffinityRule,
handleUpdateAffinityRule,
handleToggleExpanded,
handleCancelEdit,
handleChangeAddOpen,
2018-03-01 03:15:16 +02:00
handleEdit
}) => (
<Fragment>
<Title
id={step}
2018-03-01 03:15:16 +02:00
onClick={!expanded && !exitingRule && handleEdit}
collapsed={!expanded && !exitingRule}
icon={<AffinityIcon />}
>
Affinity
</Title>
{expanded ? (
<Description>
Control placement of instances on the physical servers. Design
applications to adapt at failure by distributing application components.
Instances are only provisioned when the exact criteria is met.{' '}
<a
target="__blank"
href="https://docs.joyent.com/public-cloud/instances/docker/how/start-containers#controlling-container-placement"
rel="noopener noreferrer"
>
Read the docs
</a>
</Description>
) : null}
2018-03-01 03:15:16 +02:00
<ReduxForm
2018-03-01 16:32:55 +02:00
form={IC_AFF_F_EDIT}
2018-03-01 03:15:16 +02:00
initialValues={exitingRule}
destroyOnUnmount={false}
forceUnregisterOnUnmount={false}
shouldAsyncValidate={shouldAsyncValidate}
asyncValidate={handleAsyncValidate}
2018-03-01 03:15:16 +02:00
onSubmit={handleUpdateAffinityRule}
>
{formProps =>
exitingRule ? (
<Fragment>
<KeyValue
2018-03-01 03:15:16 +02:00
{...formProps}
expanded={editOpen}
2018-03-01 16:32:55 +02:00
customHeader={<Header rule={exitingRule} />}
method="edit"
2018-03-01 03:15:16 +02:00
input={inputProps => (
<Rule
{...editingRule}
{...inputProps}
valid={formProps.valid}
/>
)}
type="an affinity rule"
2018-03-01 03:15:16 +02:00
onToggleExpanded={() =>
handleToggleExpanded(!exitingRule.expanded)
}
onCancel={handleCancelEdit}
onRemove={handleRemoveAffinityRule}
/>
<Divider height={remcalc(12)} transparent />
</Fragment>
2018-03-01 03:15:16 +02:00
) : null
}
</ReduxForm>
<ReduxForm
2018-03-01 16:32:55 +02:00
form={IC_AFF_F_ADD}
2018-03-01 03:15:16 +02:00
initialValues={RULE_DEFAULTS}
destroyOnUnmount={false}
2018-03-01 03:15:16 +02:00
forceUnregisterOnUnmount={false}
shouldAsyncValidate={shouldAsyncValidate}
2018-03-01 03:15:16 +02:00
asyncValidate={handleAsyncValidate}
onSubmit={handleCreateAffinityRules}
>
2018-03-01 03:15:16 +02:00
{formProps =>
expanded && addOpen ? (
<Fragment>
<KeyValue
2018-03-01 03:15:16 +02:00
{...formProps}
method="create"
2018-03-01 03:15:16 +02:00
input={inputProps => (
<Rule
{...creatingRule}
{...inputProps}
valid={formProps.valid}
/>
)}
type="an affinity rule"
expanded
noRemove
onCancel={() => handleChangeAddOpen(false)}
/>
<Divider height={remcalc(12)} transparent />
</Fragment>
) : null
}
</ReduxForm>
{expanded ? (
<Margin top={2} bottom={4}>
2018-03-01 03:15:16 +02:00
{!addOpen && !exitingRule ? (
<Button
type="button"
onClick={() => handleChangeAddOpen(true)}
secondary
>
Create Affinity Rule
</Button>
) : null}
</Margin>
2018-03-01 03:15:16 +02:00
) : exitingRule ? (
<Margin top={2} bottom={4}>
<Button type="button" onClick={handleEdit} secondary>
Edit
</Button>
</Margin>
) : null}
<Margin bottom={7}>
2018-03-01 03:15:16 +02:00
{expanded ? <Divider height={remcalc(1)} /> : null}
</Margin>
</Fragment>
);
export default compose(
connect(({ values, form }, ownProps) => {
2018-03-01 16:32:55 +02:00
const editingRule = get(form, `${IC_AFF_F_EDIT}.values`, null);
const creatingRule = get(form, `${IC_AFF_F_ADD}.values`, null);
const exitingRule = get(values, IC_AFF_V_AFF, null);
2018-03-01 03:15:16 +02:00
2018-03-01 16:32:55 +02:00
const addOpen = get(values, IC_AFF_V_ADD_OPEN, false);
const editOpen = get(values, IC_AFF_V_EDIT_OPEN, false);
return {
addOpen,
2018-03-01 03:15:16 +02:00
editOpen,
creatingRule,
editingRule,
exitingRule
};
}),
2018-03-01 03:15:16 +02:00
connect(null, (dispatch, { history }) => ({
shouldAsyncValidate: ({ trigger }) => {
return trigger === 'submit';
},
2018-03-01 16:32:55 +02:00
handleAsyncValidate: ({ type, ...aff }) => {
return type === 'name'
? validateRule({ ...aff, type, name: 'default' })
2018-03-01 16:32:55 +02:00
: validateRule({ ...aff, type });
},
handleEdit: () => {
2018-03-06 03:14:33 +02:00
return history.push(
`/instances/~create/affinity${history.location.search}`
);
},
2018-03-01 03:15:16 +02:00
handleCreateAffinityRules: value => {
return dispatch([
2018-03-01 16:32:55 +02:00
destroy(IC_AFF_F_ADD),
set({ name: IC_AFF_V_ADD_OPEN, value: false }),
set({ name: IC_AFF_V_AFF, value })
]);
},
2018-03-01 03:15:16 +02:00
handleUpdateAffinityRule: value => {
return dispatch([
2018-03-01 16:32:55 +02:00
destroy(IC_AFF_F_EDIT),
set({ name: IC_AFF_V_EDIT_OPEN, value: false }),
set({ name: IC_AFF_V_AFF, value })
]);
},
handleChangeAddOpen: value => {
return dispatch([
2018-03-01 16:32:55 +02:00
reset(IC_AFF_F_ADD),
set({ name: IC_AFF_V_ADD_OPEN, value })
]);
},
2018-03-01 03:15:16 +02:00
handleToggleExpanded: value => {
2018-03-01 16:32:55 +02:00
return dispatch(set({ name: IC_AFF_V_EDIT_OPEN, value }));
},
2018-03-01 03:15:16 +02:00
handleCancelEdit: () => {
2018-03-01 16:32:55 +02:00
return dispatch([set({ name: IC_AFF_V_EDIT_OPEN, value: false })]);
},
2018-03-01 03:15:16 +02:00
handleRemoveAffinityRule: () => {
return dispatch([
2018-03-01 16:32:55 +02:00
destroy(IC_AFF_F_EDIT),
set({ name: IC_AFF_V_AFF, value: null })
]);
}
}))
)(Affinity);