feat: constants in IC (phase 1)

This commit is contained in:
Sérgio Ramos 2018-03-01 14:32:55 +00:00 committed by Sérgio Ramos
parent cd242d7505
commit d7f83c59fa
41 changed files with 326 additions and 321 deletions

View File

@ -56,7 +56,8 @@
"styled-components-spacing": "^2.1.3", "styled-components-spacing": "^2.1.3",
"styled-flex-component": "^2.2.1", "styled-flex-component": "^2.2.1",
"styled-is": "^1.1.2", "styled-is": "^1.1.2",
"title-case": "^2.1.1" "title-case": "^2.1.1",
"yup": "^0.24.1"
}, },
"devDependencies": { "devDependencies": {
"babel-cli": "^6.26.0", "babel-cli": "^6.26.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -104,7 +104,7 @@ export const AddServiceForm = ({
<Margin top={3.5} left={2}> <Margin top={3.5} left={2}>
<Button <Button
type="submit" type="submit"
disabled={submitting || invalid} disabled={submitting}
loading={submitting} loading={submitting}
inline inline
> >

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -9,16 +9,17 @@ Array [
<span <span
className="c0" className="c0"
> >
Must
: :
</span>, </span>,
" be on a ", " be on a ",
"same",
" node as the instance(s) identified by the instance ", " node as the instance(s) identified by the instance ",
"name",
" ", " ",
"key “", "equalling",
"\\" and the instance tag value", " “",
" ", "test",
" \\"",
"”", "”",
] ]
`; `;
@ -32,16 +33,21 @@ Array [
<span <span
className="c0" className="c0"
> >
Must
: :
</span>, </span>,
" be on a ", " be on a ",
"same",
" node as the instance(s) identified by the instance ", " node as the instance(s) identified by the instance ",
"tag",
" ", " ",
"key “", "key “",
"two",
"\\" and the instance tag value", "\\" and the instance tag value",
" ", " ",
"equalling",
" \\"", " \\"",
"one",
"”", "”",
] ]
`; `;
@ -83,7 +89,7 @@ exports[`renders <Rule/> without throwing 1`] = `
} }
.c5 { .c5 {
width: 4.125rem; width: 4.5rem;
position: relative; position: relative;
padding: 0.75rem; padding: 0.75rem;
padding-right: 1.5625rem; padding-right: 1.5625rem;
@ -383,8 +389,8 @@ exports[`renders <Rule/> without throwing 1`] = `
appearance: none; appearance: none;
min-height: 0; min-height: 0;
max-width: 22.1875rem; max-width: 22.1875rem;
width: 4.125rem; width: 4.5rem;
max-width: 4.125rem; max-width: 4.5rem;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
@ -685,7 +691,7 @@ exports[`renders <Rule/> without throwing 1`] = `
"lineHeight": "3rem", "lineHeight": "3rem",
} }
} }
width="4.125rem" width="4.5rem"
> >
<select <select
className="c5 c6" className="c5 c6"
@ -698,7 +704,7 @@ exports[`renders <Rule/> without throwing 1`] = `
"lineHeight": "3rem", "lineHeight": "3rem",
} }
} }
width="4.125rem" width="4.5rem"
> >
<option <option
value="should" value="should"
@ -945,7 +951,7 @@ exports[`renders <Rule/> without throwing 2`] = `
} }
.c5 { .c5 {
width: 4.125rem; width: 4.5rem;
position: relative; position: relative;
padding: 0.75rem; padding: 0.75rem;
padding-right: 1.5625rem; padding-right: 1.5625rem;
@ -1245,8 +1251,8 @@ exports[`renders <Rule/> without throwing 2`] = `
appearance: none; appearance: none;
min-height: 0; min-height: 0;
max-width: 22.1875rem; max-width: 22.1875rem;
width: 4.125rem; width: 4.5rem;
max-width: 4.125rem; max-width: 4.5rem;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
@ -1547,7 +1553,7 @@ exports[`renders <Rule/> without throwing 2`] = `
"lineHeight": "3rem", "lineHeight": "3rem",
} }
} }
width="4.125rem" width="4.5rem"
> >
<select <select
className="c5 c6" className="c5 c6"
@ -1560,7 +1566,7 @@ exports[`renders <Rule/> without throwing 2`] = `
"lineHeight": "3rem", "lineHeight": "3rem",
} }
} }
width="4.125rem" width="4.5rem"
> >
<option <option
value="should" value="should"

View File

@ -39,7 +39,7 @@ export const Rule = ({ valid, ...rule }) => (
<Select <Select
style={style} style={style}
touched={rule.conditional} touched={rule.conditional}
width={remcalc(66)} width={remcalc(72)}
embedded embedded
> >
<option value="should">should</option> <option value="should">should</option>
@ -129,7 +129,7 @@ export const Rule = ({ valid, ...rule }) => (
</Margin> </Margin>
); );
export const Header = rule => ( export const Header = ({ rule }) => (
<Fragment> <Fragment>
<Bold>{titleCase(rule.conditional)}:</Bold> be on a {rule.placement} node as <Bold>{titleCase(rule.conditional)}:</Bold> be on a {rule.placement} node as
the instance(s) identified by the instance {rule.type} the instance(s) identified by the instance {rule.type}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1,48 @@
export const Forms = {
IC_AFF_F_ADD: 'INSTANCE_CREATION_AFFINITY_FORM_ADD',
IC_AFF_F_EDIT: 'INSTANCE_CREATION_AFFINITY_FORM_EDIT',
IC_CNS_F: 'INSTANCE_CREATION_CNS_FORM',
IC_NAME_F: 'INSTANCE_CREATION_NAME_FORM',
IC_FW_F_ENABLED: 'INSTANCE_CREATION_FW_ENABLED',
IC_FW_F_INACTIVE: 'INSTANCE_CREATION_FW_INACTIVE',
IC_IMG_F: 'INSTANCE_CREATION_IMAGE_FORM',
IC_MD_F_ADD: 'INSTANCE_CREATION_METADATA_FORM_ADD',
IC_MD_F_EDIT: index => `INSTANCE_CREATION_METADATA_FORM_EDIT_${index}`,
IC_TAG_F_ADD: 'INSTANCE_CREATION_TAG_FORM_ADD',
IC_TAG_F_EDIT: index => `INSTANCE_CREATION_TAG_FORM_EDIT_${index}`,
IC_NW_F: 'INSTANCE_CREATION_NETWORKS_FORM',
IC_PKG_F_SELECT: 'INSTANCE_CREATION_PACKAGE_FORM_SELECT',
IC_PKG_F_FILTER: 'INSTANCE_CREATION_PACKAGE_FORM_FILTER',
IC_US_F: 'INSTANCE_CREATION_USERSCRIPT_FORM',
IC_F: 'INSTANCE_CREATION_FORM'
};
export const Values = {
IC_AFF_V_ADD_OPEN: 'INSTANCE_CREATION_AFFINITY_VALUE_ADD_OPEN',
IC_AFF_V_EDIT_OPEN: 'INSTANCE_CREATION_AFFINITY_VALUE_EDIT_OPEN',
IC_AFF_V_AFF: 'INSTANCE_CREATION_AFFINITY_VALUE_AFFINITY',
IC_CNS_V_ENABLED: 'INSTANCE_CREATION_CNS_VALUE_ENABLED',
IC_CNS_V_PROCEEDED: 'INSTANCE_CREATION_CNS_VALUE_PROCEEDED',
IC_CNS_V_SERVICES: 'INSTANCE_CREATION_CNS_VALUE_SERVICES',
IC_FW_V_PROCEEDED: 'INSTANCE_CREATION_FIREWALL_VALUE_PROCEEDED',
IC_IMG_V_PROCEEDED: 'INSTANCE_CREATION_IMG_VALUE_PROCEEDED',
IC_IMG_V_VMS: 'INSTANCE_CREATION_IMG_VALUE_VMS',
IC_MD_V_PROCEEDED: 'INSTANCE_CREATION_METADATA_VALUE_PROCEEDED',
IC_MD_V_ADD_OPEN: 'INSTANCE_CREATION_METADATA_VALUE_ADD_OPEN',
IC_MD_V_MD: 'INSTANCE_CREATION_METADATA_VALUE_ADD_METADATA',
IC_NAME_V_PROCEEDED: 'INSTANCE_CREATION_NAME_VALUE_PROCEEDED',
IC_NAME_V_RANDOMIZING: 'INSTANCE_CREATION_NAME_VALUE_RANDOMIZING',
IC_NW_V_PROCEEDED: 'INSTANCE_CREATION_NETWORKS_VALUE_PROCEEDED',
IC_NW_V_INFO_EXPANDED: id =>
`INSTANCE_CREATION_NETWORKS_VALUE_${id}_INFO_EXPANDED`,
IC_NW_V_MACHINES_EXPANDED: id =>
`INSTANCE_CREATION_NETWORKS_VALUE_${id}_MACHINES_EXPANDED`,
IC_PKG_V_PROCEEDED: 'INSTANCE_CREATION_PACKAGE_VALUE_PROCEEDED',
IC_PKG_V_SORT_BY: 'INSTANCE_CREATION_PACKAGE_VALUE_SORT_BY',
IC_PKG_V_SORT_ORDER: 'INSTANCE_CREATION_PACKAGE_VALUE_SORT_ORDER',
IC_TAG_V_PROCEEDED: 'INSTANCE_CREATION_TAG_VALUE_PROCEEDED',
IC_TAG_V_ADD_OPEN: 'INSTANCE_CREATION_TAG_VALUE_ADD_OPEN',
IC_TAG_V_TAGS: 'INSTANCE_CREATION_TAG_VALUE_TAGS',
IC_US_V_PROCEEDED: 'INSTANCE_CREATION_USERSCRIPT_VALUE_PROCEEDED',
IC_US_V_OPEN: 'INSTANCE_CREATION_USERSCRIPT_VALUE_OPEN'
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -14,9 +14,10 @@ import Title from '@components/create-instance/title';
import { Rule, Header } from '@components/create-instance/affinity'; import { Rule, Header } from '@components/create-instance/affinity';
import Description from '@components/description'; import Description from '@components/description';
import { addAffinityRule as validateRule } from '@state/validators'; import { addAffinityRule as validateRule } from '@state/validators';
import { Forms, Values } from '@root/constants';
const FORM_NAME_CREATE = 'CREATE-INSTANCE-AFFINITY-ADD'; const { IC_AFF_F_ADD, IC_AFF_F_EDIT } = Forms;
const FORM_NAME_EDIT = 'CREATE-INSTANCE-AFFINITY-EDIT'; const { IC_AFF_V_ADD_OPEN, IC_AFF_V_EDIT_OPEN, IC_AFF_V_AFF } = Values;
const RULE_DEFAULTS = { const RULE_DEFAULTS = {
conditional: 'should', conditional: 'should',
@ -69,7 +70,7 @@ export const Affinity = ({
</Description> </Description>
) : null} ) : null}
<ReduxForm <ReduxForm
form={FORM_NAME_EDIT} form={IC_AFF_F_EDIT}
initialValues={exitingRule} initialValues={exitingRule}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={false} forceUnregisterOnUnmount={false}
@ -83,7 +84,7 @@ export const Affinity = ({
<KeyValue <KeyValue
{...formProps} {...formProps}
expanded={editOpen} expanded={editOpen}
customHeader={<Header {...exitingRule} />} customHeader={<Header rule={exitingRule} />}
method="edit" method="edit"
input={inputProps => ( input={inputProps => (
<Rule <Rule
@ -105,7 +106,7 @@ export const Affinity = ({
} }
</ReduxForm> </ReduxForm>
<ReduxForm <ReduxForm
form={FORM_NAME_CREATE} form={IC_AFF_F_ADD}
initialValues={RULE_DEFAULTS} initialValues={RULE_DEFAULTS}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={false} forceUnregisterOnUnmount={false}
@ -163,12 +164,12 @@ export const Affinity = ({
export default compose( export default compose(
connect(({ values, form }, ownProps) => { connect(({ values, form }, ownProps) => {
const editingRule = get(form, `${FORM_NAME_EDIT}.values`, null); const editingRule = get(form, `${IC_AFF_F_EDIT}.values`, null);
const creatingRule = get(form, `${FORM_NAME_CREATE}.values`, null); const creatingRule = get(form, `${IC_AFF_F_ADD}.values`, null);
const exitingRule = get(values, 'create-instance-affinity', null); const exitingRule = get(values, IC_AFF_V_AFF, null);
const addOpen = get(values, 'create-instance-affinity-add-open', false); const addOpen = get(values, IC_AFF_V_ADD_OPEN, false);
const editOpen = get(values, 'create-instance-affinity-edit-open', false); const editOpen = get(values, IC_AFF_V_EDIT_OPEN, false);
return { return {
addOpen, addOpen,
@ -182,53 +183,44 @@ export default compose(
shouldAsyncValidate: ({ trigger }) => { shouldAsyncValidate: ({ trigger }) => {
return trigger === 'submit'; return trigger === 'submit';
}, },
handleAsyncValidate: validateRule, handleAsyncValidate: ({ type, ...aff }) => {
return type === 'name'
? validateRule({ ...aff, key: 'default', type })
: validateRule({ ...aff, type });
},
handleEdit: () => { handleEdit: () => {
return history.push(`/~create/affinity${history.location.search}`); return history.push(`/~create/affinity${history.location.search}`);
}, },
handleCreateAffinityRules: value => { handleCreateAffinityRules: value => {
const toggleToClosed = set({
name: 'create-instance-affinity-add-open',
value: false
});
const appendAffinityRule = set({
name: 'create-instance-affinity',
value
});
return dispatch([ return dispatch([
destroy(FORM_NAME_CREATE), destroy(IC_AFF_F_ADD),
toggleToClosed, set({ name: IC_AFF_V_ADD_OPEN, value: false }),
appendAffinityRule set({ name: IC_AFF_V_AFF, value })
]); ]);
}, },
handleUpdateAffinityRule: value => { handleUpdateAffinityRule: value => {
return dispatch([ return dispatch([
destroy(FORM_NAME_EDIT), destroy(IC_AFF_F_EDIT),
set({ name: 'create-instance-affinity', value }) set({ name: IC_AFF_V_EDIT_OPEN, value: false }),
set({ name: IC_AFF_V_AFF, value })
]); ]);
}, },
handleChangeAddOpen: value => { handleChangeAddOpen: value => {
return dispatch([ return dispatch([
reset(FORM_NAME_CREATE), reset(IC_AFF_F_ADD),
set({ name: 'create-instance-affinity-add-open', value }) set({ name: IC_AFF_V_ADD_OPEN, value })
]); ]);
}, },
handleToggleExpanded: value => { handleToggleExpanded: value => {
return dispatch( return dispatch(set({ name: IC_AFF_V_EDIT_OPEN, value }));
set({ name: 'create-instance-affinity-edit-open', value })
);
}, },
handleCancelEdit: () => { handleCancelEdit: () => {
return dispatch([ return dispatch([set({ name: IC_AFF_V_EDIT_OPEN, value: false })]);
set({ name: 'create-instance-affinity-edit-open', value: false })
]);
}, },
handleRemoveAffinityRule: () => { handleRemoveAffinityRule: () => {
return dispatch([ return dispatch([
destroy(FORM_NAME_EDIT), destroy(IC_AFF_F_EDIT),
set({ name: 'create-instance-affinity', value: null }) set({ name: IC_AFF_V_AFF, value: null })
]); ]);
} }
})) }))

View File

@ -14,8 +14,10 @@ import Cns, { Footer, AddServiceForm } from '@components/cns';
import Description from '@components/description'; import Description from '@components/description';
import GetAccount from '@graphql/get-account.gql'; import GetAccount from '@graphql/get-account.gql';
import { addCnsService as validateServiceName } from '@state/validators'; import { addCnsService as validateServiceName } from '@state/validators';
import { Forms, Values } from '@root/constants';
const CNS_FORM = 'create-instance-cns'; const { IC_CNS_F, IC_NAME_F } = Forms;
const { IC_CNS_V_ENABLED, IC_CNS_V_PROCEEDED, IC_CNS_V_SERVICES } = Values;
const CNSContainer = ({ const CNSContainer = ({
submitted, submitted,
@ -66,7 +68,7 @@ const CNSContainer = ({
onRemoveService={handleRemoveService} onRemoveService={handleRemoveService}
> >
<ReduxForm <ReduxForm
form={`${CNS_FORM}-new-service`} form={IC_CNS_F}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
onSubmit={handleAddService} onSubmit={handleAddService}
@ -114,14 +116,9 @@ export default compose(
}) })
}), }),
connect(({ form, values }, { id }) => { connect(({ form, values }, { id }) => {
const proceeded = get(values, `${CNS_FORM}-proceeded`, false); const proceeded = get(values, IC_CNS_V_PROCEEDED, false);
const instanceName = get( const instanceName = get(form, `${IC_NAME_F}.values.name`, '<inst-name>');
form, const serviceNames = get(values, IC_CNS_V_SERVICES, []);
'create-instance-name.values.name',
'<instance-name>'
);
const serviceNames = get(values, `${CNS_FORM}-services`, []);
// REPLACE WITH DATA CENTER // REPLACE WITH DATA CENTER
const dataCenter = 'us-east-1'; const dataCenter = 'us-east-1';
@ -158,7 +155,7 @@ export default compose(
}); });
return { return {
cnsEnabled: get(values, `${CNS_FORM}-enabled`, true), cnsEnabled: get(values, IC_CNS_V_ENABLED, true),
instanceName, instanceName,
proceeded: proceeded || serviceNames.length, proceeded: proceeded || serviceNames.length,
hostnames, hostnames,
@ -167,32 +164,30 @@ export default compose(
}), }),
connect(null, (dispatch, { history, cnsEnabled, serviceNames = [] }) => ({ connect(null, (dispatch, { history, cnsEnabled, serviceNames = [] }) => ({
handleNext: () => { handleNext: () => {
dispatch(set({ name: `${CNS_FORM}-proceeded`, value: true })); dispatch(set({ name: IC_CNS_V_PROCEEDED, value: true }));
return history.push(`/~create/affinity${history.location.search}`); return history.push(`/~create/affinity${history.location.search}`);
}, },
handleEdit: () => { handleEdit: () => {
dispatch(set({ name: `${CNS_FORM}-proceeded`, value: true })); dispatch(set({ name: IC_CNS_V_PROCEEDED, value: true }));
history.push(`/~create/cns${history.location.search}`); history.push(`/~create/cns${history.location.search}`);
}, },
shouldAsyncValidate: ({ trigger }) => { shouldAsyncValidate: ({ trigger }) => {
return trigger === 'submit'; return trigger === 'submit';
}, },
handleAsyncValidate: validateServiceName, handleAsyncValidate: validateServiceName,
handleToggleCnsEnabled: ({ target }) => handleToggleCnsEnabled: ({ target }) => {
dispatch(set({ name: `${CNS_FORM}-enabled`, value: !cnsEnabled })), return dispatch(set({ name: IC_CNS_V_ENABLED, value: !cnsEnabled }));
},
handleAddService: ({ name }) => { handleAddService: ({ name }) => {
dispatch([ return dispatch([
destroy(`${CNS_FORM}-new-service`), destroy(IC_CNS_F),
set({ set({ name: IC_CNS_V_SERVICES, value: serviceNames.concat(name) })
name: `${CNS_FORM}-services`,
value: serviceNames.concat(name)
})
]); ]);
}, },
handleRemoveService: value => { handleRemoveService: value => {
return dispatch( return dispatch(
set({ set({
name: `${CNS_FORM}-services`, name: IC_CNS_V_SERVICES,
value: serviceNames.filter(name => name !== value) value: serviceNames.filter(name => name !== value)
}) })
); );

View File

@ -22,8 +22,10 @@ import Title from '@components/create-instance/title';
import Description from '@components/description'; import Description from '@components/description';
import Empty from '@components/empty'; import Empty from '@components/empty';
import ListFwRules from '@graphql/list-fw-rules.gql'; import ListFwRules from '@graphql/list-fw-rules.gql';
import { Forms, Values } from '@root/constants';
const FORM_NAME = 'CREATE-INSTANCE-FIREWALL'; const { IC_FW_F_ENABLED, IC_FW_F_INACTIVE } = Forms;
const { IC_FW_V_PROCEEDED, IC_TAG_V_TAGS } = Values;
const Firewall = ({ const Firewall = ({
defaultRules = [], defaultRules = [],
@ -62,7 +64,7 @@ const Firewall = ({
<Flex> <Flex>
<FlexItem> <FlexItem>
<ReduxForm <ReduxForm
form={`${FORM_NAME}-enabled`} form={IC_FW_F_ENABLED}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
> >
@ -77,7 +79,7 @@ const Firewall = ({
</FlexItem> </FlexItem>
<FlexItem> <FlexItem>
<ReduxForm <ReduxForm
form={`${FORM_NAME}-inactive`} form={IC_FW_F_INACTIVE}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
> >
@ -154,24 +156,18 @@ export default compose(
connect( connect(
({ form, values }, ownProps) => ({ ({ form, values }, ownProps) => ({
...ownProps, ...ownProps,
proceeded: get(values, 'create-instance-firewall-proceeded', false), proceeded: get(values, IC_FW_V_PROCEEDED, false),
enabled: get(form, `${FORM_NAME}-enabled.values.enabled`, false), enabled: get(form, `${IC_FW_F_ENABLED}.values.enabled`, false),
showInactive: get(form, `${FORM_NAME}-inactive.values.inactive`, false), showInactive: get(form, `${IC_FW_F_INACTIVE}.values.inactive`, false),
tags: get(values, 'create-instance-tags', []) tags: get(values, IC_TAG_V_TAGS, [])
}), }),
(dispatch, { history }) => ({ (dispatch, { history }) => ({
handleNext: () => { handleNext: () => {
dispatch( dispatch(set({ name: IC_FW_V_PROCEEDED, value: true }));
set({ name: 'create-instance-firewall-proceeded', value: true })
);
return history.push(`/~create/cns${history.location.search}`); return history.push(`/~create/cns${history.location.search}`);
}, },
handleEdit: () => { handleEdit: () => {
dispatch( dispatch(set({ name: IC_FW_V_PROCEEDED, value: true }));
set({ name: 'create-instance-firewall-proceeded', value: true })
);
return history.push(`/~create/firewall${history.location.search}`); return history.push(`/~create/firewall${history.location.search}`);
} }
}) })

View File

@ -19,6 +19,10 @@ import Title from '@components/create-instance/title';
import Description from '@components/description'; import Description from '@components/description';
import imageData from '@data/images-map.json'; import imageData from '@data/images-map.json';
import GetImages from '@graphql/get-images.gql'; import GetImages from '@graphql/get-images.gql';
import { Forms, Values } from '@root/constants';
const { IC_IMG_F } = Forms;
const { IC_IMG_V_PROCEEDED, IC_IMG_V_VMS } = Values;
const HarcodedImage = (image = {}) => ( const HarcodedImage = (image = {}) => (
<Fragment> <Fragment>
@ -27,7 +31,7 @@ const HarcodedImage = (image = {}) => (
</Title> </Title>
{image.id ? ( {image.id ? (
<ReduxForm <ReduxForm
form="create-instance-image" form={IC_IMG_F}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
initialValues={{ image: image.id }} initialValues={{ image: image.id }}
@ -85,7 +89,7 @@ const ImageContainer = ({
</Description> </Description>
) : null} ) : null}
<ReduxForm <ReduxForm
form="create-instance-image" form={IC_IMG_F}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
initialValues={{ vms: true }} initialValues={{ vms: true }}
@ -130,9 +134,9 @@ const ImageContainer = ({
export default compose( export default compose(
connect( connect(
({ form, values }, ownProps) => { ({ form, values }, ownProps) => {
const proceeded = get(values, 'create-instance-image-proceeded', false); const proceeded = get(values, IC_IMG_V_PROCEEDED, false);
const image = get(form, 'create-instance-image.values.image', null); const image = get(form, `${IC_IMG_F}.values.image`, null);
const vms = get(values, 'vms', true); const vms = get(values, IC_IMG_V_VMS, true);
return { return {
...ownProps, ...ownProps,
@ -143,19 +147,17 @@ export default compose(
}, },
(dispatch, { history }) => ({ (dispatch, { history }) => ({
handleNext: () => { handleNext: () => {
dispatch(set({ name: 'create-instance-image-proceeded', value: true })); dispatch(set({ name: IC_IMG_V_PROCEEDED, value: true }));
return history.push(`/~create/package${history.location.search}`); return history.push(`/~create/package${history.location.search}`);
}, },
handleEdit: () => { handleEdit: () => {
return history.push(`/~create/image${history.location.search}`); return history.push(`/~create/image${history.location.search}`);
}, },
handleSelectLatest: ({ versions }) => { handleSelectLatest: ({ versions }) => {
const id = versions[0].id; return dispatch(change(IC_IMG_F, 'image', versions[0].id));
return dispatch(change('create-instance-image', 'image', id));
}, },
setImageType: isVm => { setImageType: isVm => {
return dispatch(set({ name: 'vms', value: isVm })); return dispatch(set({ name: IC_IMG_V_VMS, value: isVm }));
} }
}) })
), ),

View File

@ -11,7 +11,7 @@ import intercept from 'apr-intercept';
import constantCase from 'constant-case'; import constantCase from 'constant-case';
import queryString from 'query-string'; import queryString from 'query-string';
import get from 'lodash.get'; import get from 'lodash.get';
import Values from 'lodash.values'; import lvalues from 'lodash.values';
import omit from 'lodash.omit'; import omit from 'lodash.omit';
import uniqBy from 'lodash.uniqby'; import uniqBy from 'lodash.uniqby';
@ -36,8 +36,18 @@ import CNS from '@containers/create-instance/cns';
import Affinity from '@containers/create-instance/affinity'; import Affinity from '@containers/create-instance/affinity';
import CreateInstanceMutation from '@graphql/create-instance.gql'; import CreateInstanceMutation from '@graphql/create-instance.gql';
import parseError from '@state/parse-error'; import parseError from '@state/parse-error';
import { Forms, Values } from '@root/constants';
const CREATE_FORM = 'CREATE-INSTANCE'; const { IC_F, IC_NAME_F, IC_IMG_F, IC_PKG_F_SELECT, IC_NW_F, IC_US_F } = Forms;
const {
IC_MD_V_MD,
IC_TAG_V_TAGS,
IC_AFF_V_AFF,
IC_CNS_V_ENABLED,
IC_CNS_V_SERVICES,
IC_FW_F_ENABLED
} = Values;
const CreateInstance = ({ const CreateInstance = ({
step, step,
@ -137,7 +147,7 @@ const CreateInstance = ({
</Message> </Message>
</Margin> </Margin>
) : null} ) : null}
<ReduxForm form={CREATE_FORM} onSubmit={handleSubmit}> <ReduxForm form={IC_F} onSubmit={handleSubmit}>
{({ handleSubmit, submitting }) => ( {({ handleSubmit, submitting }) => (
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<Button disabled={disabled} loading={submitting}> <Button disabled={disabled} loading={submitting}>
@ -154,20 +164,19 @@ export default compose(
graphql(CreateInstanceMutation, { name: 'createInstance' }), graphql(CreateInstanceMutation, { name: 'createInstance' }),
connect(({ form, values }, { match, location }) => { connect(({ form, values }, { match, location }) => {
const query = queryString.parse(location.search); const query = queryString.parse(location.search);
const FORM_NAME = 'create-instance-name';
const step = get(match, 'params.step', 'name'); const step = get(match, 'params.step', 'name');
const error = get(form, `${CREATE_FORM}.error`, null); const error = get(form, `${IC_F}.error`, null);
const name = get(form, `${FORM_NAME}.values.name`, ''); const name = get(form, `${IC_NAME_F}.values.name`, '');
const image = get(form, 'create-instance-image.values.image', ''); const image = get(form, `${IC_IMG_F}.values.image`, '');
const pkg = get(form, 'create-instance-package.values.package', ''); const pkg = get(form, `${IC_PKG_F_SELECT}.values.package`, '');
const networks = get(form, 'CREATE-INSTANCE-NETWORKS.values', {}); const networks = get(form, `${IC_NW_F}.values`, {});
const enabled = const enabled =
name.length && name.length &&
image.length && image.length &&
pkg.length && pkg.length &&
Values(networks).filter(Boolean).length; lvalues(networks).filter(Boolean).length;
if (!enabled) { if (!enabled) {
return { return {
@ -178,17 +187,16 @@ export default compose(
}; };
} }
const metadata = get(values, 'create-instance-metadata', []); const metadata = get(values, IC_MD_V_MD, []);
const receivedTags = get(values, 'create-instance-tags', []); const tags = get(values, IC_TAG_V_TAGS, []).map(tag => tag); // clone
const affinity = get(values, 'create-instance-affinity', []); const affinity = get(values, IC_AFF_V_AFF, null);
const cns = get(values, 'create-instance-cns-enabled', true); const cns = get(values, IC_CNS_V_ENABLED, true);
const cnsServices = get(values, 'create-instance-cns-services', null); const cnsServices = get(values, IC_CNS_V_SERVICES, null);
const userScript = get(values, 'create-instance-user-script', {}); const userScript = get(form, `${IC_US_F}.values.value`, '');
const tags = receivedTags.map(a => omit(a, 'expanded'));
const firewall_enabled = get( const firewall_enabled = get(
form, form,
'CREATE-INSTANCE-FIREWALL.values.enabled', `${IC_FW_F_ENABLED}.values.enabled`,
false false
); );
@ -236,14 +244,14 @@ export default compose(
history history
} = ownProps; } = ownProps;
return { const parseAffRule = ({
handleSubmit: async () => { conditional,
const _affinity = affinity placement,
.map(aff => ({ identity,
...aff, key,
value: aff.type === 'name' ? aff.name : aff.value pattern,
})) value
.map(({ conditional, placement, identity, key, pattern, value }) => { }) => {
const type = constantCase( const type = constantCase(
`${conditional}_${placement === 'same' ? 'equal' : 'not_equal'}` `${conditional}_${placement === 'same' ? 'equal' : 'not_equal'}`
); );
@ -257,18 +265,25 @@ export default compose(
}; };
const _key = identity === 'name' ? 'instance' : key; const _key = identity === 'name' ? 'instance' : key;
const _value = patterns[pattern](value); const _value = patterns[pattern](type === 'name' ? name : value);
return { return {
type, type,
key: _key, key: _key,
value: _value value: _value
}; };
}); };
return {
handleSubmit: async () => {
const _affinity = affinity ? parseAffRule(affinity) : null;
const _name = name.toLowerCase(); const _name = name.toLowerCase();
const _metadata = metadata.map(a => omit(a, 'open')); const _metadata = metadata.map(a => omit(a, 'open'));
const _tags = uniqBy(tags, 'name').map(a => omit(a, 'expanded'));
const _tags = uniqBy(tags.map(a => omit(a, 'expanded')), 'name').map(
a => omit(a, 'expanded')
);
const _networks = Object.keys(networks).filter( const _networks = Object.keys(networks).filter(
network => networks[network] network => networks[network]
); );
@ -283,7 +298,7 @@ export default compose(
name: _name, name: _name,
package: pkg, package: pkg,
image, image,
affinity: _affinity.length ? _affinity : undefined, affinity: _affinity,
metadata: _metadata, metadata: _metadata,
tags: _tags, tags: _tags,
firewall_enabled, firewall_enabled,
@ -299,7 +314,6 @@ export default compose(
} }
dispatch([destroyAll(), forms.map(name => destroy(name))]); dispatch([destroyAll(), forms.map(name => destroy(name))]);
history.push(`/${res.data.createMachine.name}`); history.push(`/${res.data.createMachine.name}`);
} }
}; };

View File

@ -14,9 +14,10 @@ import Editor from 'joyent-ui-toolkit/dist/es/editor';
import Title from '@components/create-instance/title'; import Title from '@components/create-instance/title';
import Description from '@components/description'; import Description from '@components/description';
import { addMetadata as validateMetadata } from '@state/validators'; import { addMetadata as validateMetadata } from '@state/validators';
import { Forms, Values } from '@root/constants';
const FORM_NAME_CREATE = 'CREATE-INSTANCE-METADATA-ADD'; const { IC_MD_F_ADD, IC_MD_F_EDIT } = Forms;
const FORM_NAME_EDIT = i => `CREATE-INSTANCE-METADATA-EDIT-${i}`; const { IC_MD_V_PROCEEDED, IC_MD_V_ADD_OPEN, IC_MD_V_MD } = Values;
export const Metadata = ({ export const Metadata = ({
id, id,
@ -68,7 +69,7 @@ export const Metadata = ({
) : null} ) : null}
{metadata.map(({ name, value, open }, index) => ( {metadata.map(({ name, value, open }, index) => (
<ReduxForm <ReduxForm
form={FORM_NAME_EDIT(index)} form={IC_MD_F_EDIT(index)}
key={index} key={index}
initialValues={{ name, value }} initialValues={{ name, value }}
destroyOnUnmount={false} destroyOnUnmount={false}
@ -103,7 +104,7 @@ export const Metadata = ({
</ReduxForm> </ReduxForm>
))} ))}
<ReduxForm <ReduxForm
form={FORM_NAME_CREATE} form={IC_MD_F_ADD}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
onSubmit={handleAddMetadata} onSubmit={handleAddMetadata}
@ -152,9 +153,9 @@ export const Metadata = ({
export default compose( export default compose(
connect(({ values }, ownProps) => { connect(({ values }, ownProps) => {
const proceeded = get(values, 'create-instance-metadata-proceeded', false); const proceeded = get(values, IC_MD_V_PROCEEDED, false);
const addOpen = get(values, 'create-instance-metadata-add-open', false); const addOpen = get(values, IC_MD_V_ADD_OPEN, false);
const metadata = get(values, 'create-instance-metadata', []); const metadata = get(values, IC_MD_V_MD, []);
return { return {
proceeded: proceeded || metadata.length, proceeded: proceeded || metadata.length,
@ -164,17 +165,11 @@ export default compose(
}), }),
connect(null, (dispatch, { metadata = [], history }) => ({ connect(null, (dispatch, { metadata = [], history }) => ({
handleNext: () => { handleNext: () => {
dispatch( dispatch(set({ name: IC_MD_V_PROCEEDED, value: true }));
set({ name: 'create-instance-metadata-proceeded', value: true })
);
return history.push(`/~create/user-script${history.location.search}`); return history.push(`/~create/user-script${history.location.search}`);
}, },
handleEdit: () => { handleEdit: () => {
dispatch( dispatch(set({ name: IC_MD_V_PROCEEDED, value: true }));
set({ name: 'create-instance-metadata-proceeded', value: true })
);
return history.push(`/~create/metadata${history.location.search}`); return history.push(`/~create/metadata${history.location.search}`);
}, },
shouldAsyncValidate: ({ trigger }) => { shouldAsyncValidate: ({ trigger }) => {
@ -182,21 +177,14 @@ export default compose(
}, },
handleAsyncValidate: validateMetadata, handleAsyncValidate: validateMetadata,
handleAddMetadata: value => { handleAddMetadata: value => {
const toggleToClosed = set({ const toggleToClosed = set({ name: IC_MD_V_ADD_OPEN, value: false });
name: `create-instance-metadata-add-open`,
value: false
});
const appendMetadata = set({ const appendMetadata = set({
name: `create-instance-metadata`, name: IC_MD_V_MD,
value: metadata.concat([{ ...value, open: false }]) value: metadata.concat([{ ...value, open: false }])
}); });
return dispatch([ return dispatch([destroy(IC_MD_F_ADD), toggleToClosed, appendMetadata]);
destroy(FORM_NAME_CREATE),
toggleToClosed,
appendMetadata
]);
}, },
handleUpdateMetadata: (index, newMetadata) => { handleUpdateMetadata: (index, newMetadata) => {
metadata[index] = { metadata[index] = {
@ -205,14 +193,14 @@ export default compose(
}; };
return dispatch([ return dispatch([
destroy(FORM_NAME_EDIT(index)), destroy(IC_MD_F_EDIT(index)),
set({ name: `create-instance-metadata`, value: metadata.slice() }) set({ name: IC_MD_V_MD, value: metadata.slice() })
]); ]);
}, },
handleChangeAddOpen: value => { handleChangeAddOpen: value => {
return dispatch([ return dispatch([
reset(FORM_NAME_CREATE), reset(IC_MD_F_ADD),
set({ name: `create-instance-metadata-add-open`, value }) set({ name: IC_MD_V_ADD_OPEN, value })
]); ]);
}, },
handleToggleExpanded: index => { handleToggleExpanded: index => {
@ -221,12 +209,7 @@ export default compose(
open: !metadata[index].open open: !metadata[index].open
}; };
return dispatch( return dispatch(set({ name: IC_MD_V_MD, value: metadata.slice() }));
set({
name: `create-instance-metadata`,
value: metadata.slice()
})
);
}, },
handleCancelEdit: index => { handleCancelEdit: index => {
metadata[index] = { metadata[index] = {
@ -235,16 +218,16 @@ export default compose(
}; };
return dispatch([ return dispatch([
reset(FORM_NAME_EDIT(index)), reset(IC_MD_F_EDIT(index)),
set({ name: `create-instance-metadata`, value: metadata.slice() }) set({ name: IC_MD_V_MD, value: metadata.slice() })
]); ]);
}, },
handleRemoveMetadata: index => { handleRemoveMetadata: index => {
metadata.splice(index, 1); metadata.splice(index, 1);
return dispatch([ return dispatch([
destroy(FORM_NAME_EDIT(index)), destroy(IC_MD_F_EDIT(index)),
set({ name: `create-instance-metadata`, value: metadata.slice() }) set({ name: IC_MD_V_MD, value: metadata.slice() })
]); ]);
} }
})) }))

View File

@ -16,8 +16,10 @@ import Description from '@components/description';
import { instanceName as validateName } from '@state/validators'; import { instanceName as validateName } from '@state/validators';
import createClient from '@state/apollo-client'; import createClient from '@state/apollo-client';
import GetRandomName from '@graphql/get-random-name.gql'; import GetRandomName from '@graphql/get-random-name.gql';
import { Forms, Values } from '@root/constants';
const FORM_NAME = 'create-instance-name'; const { IC_NAME_F } = Forms;
const { IC_NAME_V_PROCEEDED, IC_NAME_V_RANDOMIZING } = Values;
const NameContainer = ({ const NameContainer = ({
expanded, expanded,
@ -47,7 +49,7 @@ const NameContainer = ({
</Description> </Description>
) : null} ) : null}
<ReduxForm <ReduxForm
form={FORM_NAME} form={IC_NAME_F}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
onSubmit={handleNext} onSubmit={handleNext}
@ -96,14 +98,9 @@ export default compose(
}), }),
connect( connect(
({ form, values }, ownProps) => { ({ form, values }, ownProps) => {
const name = get(form, `${FORM_NAME}.values.name`, ''); const name = get(form, `${IC_NAME_F}.values.name`, '');
const proceeded = get(values, 'create-instance-name-proceeded', false); const randomizing = get(values, IC_NAME_V_RANDOMIZING, false);
const proceeded = get(values, IC_NAME_V_PROCEEDED, false);
const randomizing = get(
values,
'create-instance-name-randomizing',
false
);
return { return {
...ownProps, ...ownProps,
@ -114,7 +111,7 @@ export default compose(
}, },
(dispatch, { history, query }) => ({ (dispatch, { history, query }) => ({
handleNext: () => { handleNext: () => {
dispatch(set({ name: 'create-instance-name-proceeded', value: true })); dispatch(set({ name: IC_NAME_V_PROCEEDED, value: true }));
return history.push( return history.push(
`/~create/${query.image ? 'package' : 'image'}${ `/~create/${query.image ? 'package' : 'image'}${
history.location.search history.location.search
@ -129,9 +126,7 @@ export default compose(
}, },
handleAsyncValidate: validateName, handleAsyncValidate: validateName,
handleRandomize: async () => { handleRandomize: async () => {
dispatch( dispatch(set({ name: IC_NAME_V_RANDOMIZING, value: true }));
set({ name: 'create-instance-name-randomizing', value: true })
);
const [err, res] = await intercept( const [err, res] = await intercept(
createClient().query({ createClient().query({
@ -140,9 +135,7 @@ export default compose(
}) })
); );
dispatch( dispatch(set({ name: IC_NAME_V_RANDOMIZING, value: false }));
set({ name: 'create-instance-name-randomizing', value: false })
);
if (err) { if (err) {
console.error(err); console.error(err);
@ -152,7 +145,7 @@ export default compose(
const { data } = res; const { data } = res;
const { rndName } = data; const { rndName } = data;
return dispatch(change(FORM_NAME, 'name', rndName)); return dispatch(change(IC_NAME_F, 'name', rndName));
} }
}) })
) )

View File

@ -15,8 +15,14 @@ import Title from '@components/create-instance/title';
import Network from '@components/create-instance/network'; import Network from '@components/create-instance/network';
import Description from '@components/description'; import Description from '@components/description';
import ListNetworks from '@graphql/list-networks.gql'; import ListNetworks from '@graphql/list-networks.gql';
import { Forms, Values } from '@root/constants';
const FORM_NAME = 'CREATE-INSTANCE-NETWORKS'; const { IC_NW_F } = Forms;
const {
IC_NW_V_PROCEEDED,
IC_NW_V_INFO_EXPANDED,
IC_NW_V_MACHINES_EXPANDED
} = Values;
export const Networks = ({ export const Networks = ({
networks = [], networks = [],
@ -62,7 +68,7 @@ export const Networks = ({
) : null} ) : null}
{loading && expanded ? <StatusLoader /> : null} {loading && expanded ? <StatusLoader /> : null}
<ReduxForm <ReduxForm
form={FORM_NAME} form={IC_NW_F}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
initialValues={initialValues} initialValues={initialValues}
@ -128,16 +134,11 @@ export default compose(
}), }),
connect( connect(
({ values, form }, { networks }) => { ({ values, form }, { networks }) => {
const selected = get(form, `${FORM_NAME}.values`, {}); const proceeded = get(values, IC_NW_V_PROCEEDED, false);
const selected = get(form, `${IC_NW_F}.values`, {});
const empty = id => !includes(Object.keys(selected), id); const empty = id => !includes(Object.keys(selected), id);
const _public = find(networks, ['name', 'Joyent-SDC-Public']); const _public = find(networks, ['name', 'Joyent-SDC-Public']);
const proceeded = get(
values,
'create-instance-networks-proceeded',
false
);
const initialValues = _public const initialValues = _public
? { ? {
[_public.id]: true [_public.id]: true
@ -151,22 +152,14 @@ export default compose(
return { return {
...network, ...network,
id,
name, name,
selected: selected:
empty(id) && name === 'Joyent-SDC-Public' empty(id) && name === 'Joyent-SDC-Public'
? true ? true
: Boolean(selected[id]), : Boolean(selected[id]),
infoExpanded: get( machinesExpanded: get(values, IC_NW_V_MACHINES_EXPANDED(id), false),
values, infoExpanded: get(values, IC_NW_V_INFO_EXPANDED(id), false)
`create-instance-networks-${id}-info-expanded`,
false
),
machinesExpanded: get(
values,
`create-instance-networks-${id}-machines-expanded`,
false
),
id
}; };
}); });
@ -179,33 +172,21 @@ export default compose(
}, },
(dispatch, { history }) => ({ (dispatch, { history }) => ({
handleNext: () => { handleNext: () => {
dispatch( dispatch(set({ name: IC_NW_V_PROCEEDED, value: true }));
set({ name: 'create-instance-networks-proceeded', value: true })
);
return history.push(`/~create/firewall${history.location.search}`); return history.push(`/~create/firewall${history.location.search}`);
}, },
handleEdit: () => { handleEdit: () => {
dispatch( dispatch(set({ name: IC_NW_V_PROCEEDED, value: true }));
set({ name: 'create-instance-networks-proceeded', value: true })
);
return history.push(`/~create/networks${history.location.search}`); return history.push(`/~create/networks${history.location.search}`);
}, },
setInfoExpanded: (id, expanded) => { setInfoExpanded: (id, expanded) => {
return dispatch( return dispatch(
set({ set({ name: IC_NW_V_INFO_EXPANDED(id), value: expanded })
name: `create-instance-networks-${id}-info-expanded`,
value: expanded
})
); );
}, },
setMachinesExpanded: (id, expanded) => { setMachinesExpanded: (id, expanded) => {
return dispatch( return dispatch(
set({ set({ name: IC_NW_V_MACHINES_EXPANDED(id), value: expanded })
name: `create-instance-networks-${id}-machines-expanded`,
value: expanded
})
); );
} }
}) })

View File

@ -26,9 +26,16 @@ import Title from '@components/create-instance/title';
import Description from '@components/description'; import Description from '@components/description';
import getPackages from '@graphql/get-packages.gql'; import getPackages from '@graphql/get-packages.gql';
import priceData from '@data/prices.json'; import priceData from '@data/prices.json';
import { Forms, Values } from '@root/constants';
const FORM_NAME = 'create-instance-package'; const { IC_PKG_F_SELECT, IC_PKG_F_FILTER } = Forms;
const FILTERS = 'create-instance-package-filters';
const {
IC_PKG_V_PROCEEDED,
IC_PKG_V_SORT_BY,
IC_PKG_V_SORT_ORDER,
IC_IMG_V_VMS
} = Values;
const PackageContainer = ({ const PackageContainer = ({
expanded, expanded,
@ -69,7 +76,7 @@ const PackageContainer = ({
</Description> </Description>
) : null} ) : null}
<ReduxForm <ReduxForm
form={`${FORM_NAME}-filters`} form={IC_PKG_F_FILTER}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
> >
@ -80,7 +87,7 @@ const PackageContainer = ({
} }
</ReduxForm> </ReduxForm>
<ReduxForm <ReduxForm
form={FORM_NAME} form={IC_PKG_F_SELECT}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
onSubmit={handleNext} onSubmit={handleNext}
@ -162,37 +169,37 @@ export default compose(
}), }),
connect( connect(
({ form, values }, { packages, ...ownProps }) => { ({ form, values }, { packages, ...ownProps }) => {
const proceeded = get(values, 'create-instance-package-proceeded', false); const proceeded = get(values, IC_PKG_V_PROCEEDED, false);
const _sortBy = get(values, 'packages-list-sort-by', 'price'); const _sortBy = get(values, IC_PKG_V_SORT_BY, 'price');
const _sortOrder = get(values, 'packages-list-sort-order', 'asc'); const _sortOrder = get(values, IC_PKG_V_SORT_ORDER, 'asc');
const ssdOnly = get(form, `${FILTERS}.values.ssd`, false); const ssdOnly = get(form, `${IC_PKG_F_FILTER}.values.ssd`, false);
const computeOptimized = get( const computeOptimized = get(
form, form,
`${FILTERS}.values.compute-optimized`, `${IC_PKG_F_FILTER}.values.compute-optimized`,
false false
); );
const generalPurpose = get( const generalPurpose = get(
form, form,
`${FILTERS}.values.general-purpose`, `${IC_PKG_F_FILTER}.values.general-purpose`,
false false
); );
const storageOptimized = get( const storageOptimized = get(
form, form,
`${FILTERS}.values.storage-optimized`, `${IC_PKG_F_FILTER}.values.storage-optimized`,
false false
); );
const memoryOptimized = get( const memoryOptimized = get(
form, form,
`${FILTERS}.values.memory-optimized`, `${IC_PKG_F_FILTER}.values.memory-optimized`,
false false
); );
const vmSelected = get(form, 'create-instance-vms.values.vms', false); const vmSelected = get(values, IC_IMG_V_VMS, true);
const pkgSelected = get(form, `${FORM_NAME}.values.package`, null); const pkgSelected = get(form, `${IC_PKG_F_SELECT}.values.package`, null);
const selected = find(packages, ['id', pkgSelected]); const selected = find(packages, ['id', pkgSelected]);
const sorted = sortBy(packages, [_sortBy]); const sorted = sortBy(packages, [_sortBy]);
@ -228,31 +235,25 @@ export default compose(
}, },
(dispatch, { history }) => ({ (dispatch, { history }) => ({
handleNext: () => { handleNext: () => {
dispatch( dispatch(set({ name: IC_PKG_V_PROCEEDED, value: true }));
set({ name: 'create-instance-package-proceeded', value: true })
);
return history.push(`/~create/tags${history.location.search}`); return history.push(`/~create/tags${history.location.search}`);
}, },
handleEdit: () => { handleEdit: () => {
return history.push(`/~create/package${history.location.search}`); return history.push(`/~create/package${history.location.search}`);
}, },
handleResetFilters: () => { handleResetFilters: () => {
dispatch(destroy(`${FORM_NAME}-filters`)); dispatch(destroy(IC_PKG_F_FILTER));
}, },
handleRowClick: id => { handleRowClick: id => {
dispatch(change(FORM_NAME, 'package', id)); dispatch(change(IC_PKG_F_SELECT, 'package', id));
}, },
handleSortBy: (newSortBy, sortOrder) => { handleSortBy: (newSortBy, sortOrder) => {
dispatch([ dispatch([
set({ set({
name: `packages-list-sort-order`, name: IC_PKG_V_SORT_BY,
value: sortOrder === 'desc' ? 'asc' : 'desc' value: sortOrder === 'desc' ? 'asc' : 'desc'
}), }),
set({ set({ name: IC_PKG_V_SORT_ORDER, value: newSortBy })
name: `packages-list-sort-by`,
value: newSortBy
})
]); ]);
} }
}) })

View File

@ -21,9 +21,10 @@ import Title from '@components/create-instance/title';
import Description from '@components/description'; import Description from '@components/description';
import Tag from '@components/tags'; import Tag from '@components/tags';
import { addTag as validateTag } from '@state/validators'; import { addTag as validateTag } from '@state/validators';
import { Forms, Values } from '@root/constants';
const FORM_NAME_CREATE = 'CREATE-INSTANCE-TAGS-ADD'; const { IC_TAG_F_ADD, IC_TAG_F_EDIT } = Forms;
const FORM_NAME_EDIT = i => `CREATE-INSTANCE-TAGS-EDIT-${i}`; const { IC_TAG_V_PROCEEDED, IC_TAG_V_ADD_OPEN, IC_TAG_V_TAGS } = Values;
export const Tags = ({ export const Tags = ({
step, step,
@ -84,7 +85,7 @@ export const Tags = ({
</Fragment> </Fragment>
) : null} ) : null}
<ReduxForm <ReduxForm
form={FORM_NAME_CREATE} form={IC_TAG_F_ADD}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
shouldAsyncValidate={shouldAsyncValidate} shouldAsyncValidate={shouldAsyncValidate}
@ -132,9 +133,9 @@ export const Tags = ({
export default compose( export default compose(
connect(({ values }, ownProps) => { connect(({ values }, ownProps) => {
const proceeded = get(values, 'create-instance-tags-proceeded', false); const proceeded = get(values, IC_TAG_V_PROCEEDED, false);
const addOpen = get(values, 'create-instance-tags-add-open', false); const addOpen = get(values, IC_TAG_V_ADD_OPEN, false);
const tags = get(values, 'create-instance-tags', []); const tags = get(values, IC_TAG_V_TAGS, []);
return { return {
proceeded: proceeded || tags.length, proceeded: proceeded || tags.length,
@ -144,11 +145,11 @@ export default compose(
}), }),
connect(null, (dispatch, { tags = [], history }) => ({ connect(null, (dispatch, { tags = [], history }) => ({
handleNext: () => { handleNext: () => {
dispatch(set({ name: 'create-instance-tags-proceeded', value: true })); dispatch(set({ name: IC_TAG_V_PROCEEDED, value: true }));
return history.push(`/~create/metadata${history.location.search}`); return history.push(`/~create/metadata${history.location.search}`);
}, },
handleEdit: () => { handleEdit: () => {
dispatch(set({ name: 'create-instance-tags-proceeded', value: true })); dispatch(set({ name: IC_TAG_V_PROCEEDED, value: true }));
return history.push(`/~create/tags${history.location.search}`); return history.push(`/~create/tags${history.location.search}`);
}, },
shouldAsyncValidate: ({ trigger }) => { shouldAsyncValidate: ({ trigger }) => {
@ -156,17 +157,14 @@ export default compose(
}, },
handleAsyncValidate: validateTag, handleAsyncValidate: validateTag,
handleAddTag: value => { handleAddTag: value => {
const toggleToClosed = set({ const toggleToClosed = set({ name: IC_TAG_V_ADD_OPEN, value: false });
name: `create-instance-tags-add-open`,
value: false
});
const appendTag = set({ const appendTag = set({
name: `create-instance-tags`, name: IC_TAG_V_TAGS,
value: tags.concat([{ ...value, expanded: false }]) value: tags.concat([{ ...value, expanded: false }])
}); });
return dispatch([destroy(FORM_NAME_CREATE), toggleToClosed, appendTag]); return dispatch([destroy(IC_TAG_F_ADD), toggleToClosed, appendTag]);
}, },
handleUpdateTag: (index, newTag) => { handleUpdateTag: (index, newTag) => {
tags[index] = { tags[index] = {
@ -175,14 +173,14 @@ export default compose(
}; };
return dispatch([ return dispatch([
destroy(FORM_NAME_EDIT(index)), destroy(IC_TAG_F_EDIT(index)),
set({ name: `create-instance-tags`, value: tags.slice() }) set({ name: IC_TAG_V_TAGS, value: tags.slice() })
]); ]);
}, },
handleChangeAddOpen: value => { handleChangeAddOpen: value => {
return dispatch([ return dispatch([
reset(FORM_NAME_CREATE), reset(IC_TAG_F_ADD),
set({ name: `create-instance-tags-add-open`, value }) set({ name: IC_TAG_V_ADD_OPEN, value })
]); ]);
}, },
handleToggleExpanded: index => { handleToggleExpanded: index => {
@ -191,12 +189,7 @@ export default compose(
expanded: !tags[index].expanded expanded: !tags[index].expanded
}; };
return dispatch( return dispatch(set({ name: IC_TAG_V_TAGS, value: tags.slice() }));
set({
name: `create-instance-tags`,
value: tags.slice()
})
);
}, },
handleCancelEdit: index => { handleCancelEdit: index => {
tags[index] = { tags[index] = {
@ -205,16 +198,16 @@ export default compose(
}; };
return dispatch([ return dispatch([
reset(FORM_NAME_EDIT(index)), reset(IC_TAG_F_EDIT(index)),
set({ name: `create-instance-tags`, value: tags.slice() }) set({ name: IC_TAG_V_TAGS, value: tags.slice() })
]); ]);
}, },
handleRemoveTag: index => { handleRemoveTag: index => {
tags.splice(index, 1); tags.splice(index, 1);
return dispatch([ return dispatch([
destroy(FORM_NAME_EDIT(index)), destroy(IC_TAG_F_EDIT(index)),
set({ name: `create-instance-tags`, value: tags.slice() }) set({ name: IC_TAG_V_TAGS, value: tags.slice() })
]); ]);
} }
})) }))

View File

@ -11,9 +11,13 @@ import { ScriptIcon, Button } from 'joyent-ui-toolkit';
import Title from '@components/create-instance/title'; import Title from '@components/create-instance/title';
import Description from '@components/description'; import Description from '@components/description';
import UserScriptForm, { Overview } from '@components/create-instance/user-script'; import UserScriptForm, {
Overview
} from '@components/create-instance/user-script';
import { Forms, Values } from '@root/constants';
const FORM_NAME = 'create-instance-user-script'; const { IC_US_F } = Forms;
const { IC_US_V_PROCEEDED, IC_US_V_OPEN } = Values;
export const UserScript = ({ export const UserScript = ({
expanded, expanded,
@ -44,7 +48,7 @@ export const UserScript = ({
</Description> </Description>
{formOpen ? ( {formOpen ? (
<ReduxForm <ReduxForm
form={FORM_NAME} form={IC_US_F}
destroyOnUnmount={false} destroyOnUnmount={false}
forceUnregisterOnUnmount={true} forceUnregisterOnUnmount={true}
onSubmit={handleSubmit} onSubmit={handleSubmit}
@ -87,15 +91,11 @@ export const UserScript = ({
export default compose( export default compose(
connect( connect(
({ values, form }, ownProps) => { ({ values, form }, ownProps) => {
const formOpen = get(values, 'create-instance-user-script-open', false); const formOpen = get(values, IC_US_V_OPEN, false);
const script = get(form, `${FORM_NAME}.values.value`, ''); const script = get(form, `${IC_US_F}.values.value`, '');
const lines = script.split('\n').length; const lines = script.split('\n').length;
const proceeded = get( const proceeded = get(values, IC_US_V_PROCEEDED, false);
values,
'create-instance-user-script-proceeded',
false
);
return { return {
script, script,
@ -109,21 +109,19 @@ export default compose(
(dispatch, { history }) => ({ (dispatch, { history }) => ({
handleEdit: () => { handleEdit: () => {
dispatch([ dispatch([
set({ name: 'create-instance-user-script-proceeded', value: true }), set({ name: IC_US_V_PROCEEDED, value: true }),
set({ name: `create-instance-user-script-open`, value: true }) set({ name: IC_US_V_OPEN, value: true })
]); ]);
return history.push(`/~create/user-script${history.location.search}`); return history.push(`/~create/user-script${history.location.search}`);
}, },
handleChangeOpenForm: value => { handleChangeOpenForm: value => {
return dispatch([ return dispatch([set({ name: IC_US_V_OPEN, value })]);
set({ name: `create-instance-user-script-open`, value })
]);
}, },
handleSubmit: value => { handleSubmit: value => {
dispatch([ dispatch([
set({ name: `create-instance-user-script-open`, value: false }), set({ name: IC_US_V_OPEN, value: false }),
set({ name: 'create-instance-user-script-proceeded', value: true }) set({ name: IC_US_V_PROCEEDED, value: true })
]); ]);
return history.push(`/~create/networks${history.location.search}`); return history.push(`/~create/networks${history.location.search}`);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -101,7 +101,7 @@ export const Tags = ({
form={editing.form} form={editing.form}
initialValues={{ name: editing.name, value: editing.value }} initialValues={{ name: editing.name, value: editing.value }}
shouldAsyncValidate={shouldAsyncValidate} shouldAsyncValidate={shouldAsyncValidate}
handleAsyncValidate={handleAsyncValidate} asyncValidate={handleAsyncValidate}
onSubmit={handleEdit} onSubmit={handleEdit}
> >
{props => ( {props => (

View File

@ -14,14 +14,16 @@ const validateField = async (field, value) => {
const validateSchema = async (schema, value) => { const validateSchema = async (schema, value) => {
const errors = await reduce( const errors = await reduce(
keys(schema), keys(schema),
async (errors, name) => async (errors, name) => {
assign(errors, { const msg = await validateField(schema[name], value[name]);
[name]: await validateField(schema[name], value[name]) return !msg ? errors : assign(errors, { [name]: msg });
}), },
{} {}
); );
if (keys(errors).length) {
throw errors; throw errors;
}
}; };
/*****************************************************************************/ /*****************************************************************************/