feat: improved validation of attrs
@ -13,7 +13,7 @@
|
|||||||
"build:lib": "NODE_ENV=production redrun -p build:es build:umd",
|
"build:lib": "NODE_ENV=production redrun -p build:es build:umd",
|
||||||
"build:bundle": "echo 0",
|
"build:bundle": "echo 0",
|
||||||
"prepublish": "NODE_ENV=production redrun build:lib",
|
"prepublish": "NODE_ENV=production redrun build:lib",
|
||||||
"lint": "redrun lint:ci -- -- --fix",
|
"lint": "redrun lint:ci -- --fix",
|
||||||
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
||||||
"test": "NODE_ENV=test joyent-react-scripts test --env=jsdom",
|
"test": "NODE_ENV=test joyent-react-scripts test --env=jsdom",
|
||||||
"test:ci": "redrun test",
|
"test:ci": "redrun test",
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
"build:lib": "NODE_ENV=production redrun -p build:es build:umd",
|
"build:lib": "NODE_ENV=production redrun -p build:es build:umd",
|
||||||
"build:bundle": "echo 0",
|
"build:bundle": "echo 0",
|
||||||
"prepublish": "NODE_ENV=production redrun build:lib",
|
"prepublish": "NODE_ENV=production redrun build:lib",
|
||||||
"lint": "redrun lint:ci -- -- --fix",
|
"lint": "redrun lint:ci -- --fix",
|
||||||
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
||||||
"test": "echo 0",
|
"test": "echo 0",
|
||||||
"test:ci": "redrun test",
|
"test:ci": "redrun test",
|
||||||
|
@ -11,9 +11,9 @@
|
|||||||
"build:lib": "echo 0",
|
"build:lib": "echo 0",
|
||||||
"build:bundle": "NODE_ENV=production redrun -p build:frontend build:ssr",
|
"build:bundle": "NODE_ENV=production redrun -p build:frontend build:ssr",
|
||||||
"prepublish": "NODE_ENV=production redrun build:bundle",
|
"prepublish": "NODE_ENV=production redrun build:bundle",
|
||||||
"lint": "redrun lint:ci -- -- --fix",
|
"lint": "redrun lint:ci -- --fix",
|
||||||
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
||||||
"test": "redrun test:ci",
|
"test": "echo 0",
|
||||||
"test:ci": "echo 0",
|
"test:ci": "echo 0",
|
||||||
"build:frontend": "joyent-react-scripts build",
|
"build:frontend": "joyent-react-scripts build",
|
||||||
"build:ssr": "SSR=1 UMD=1 babel src --out-dir lib/app --copy-files"
|
"build:ssr": "SSR=1 UMD=1 babel src --out-dir lib/app --copy-files"
|
||||||
@ -42,7 +42,6 @@
|
|||||||
"lodash.uniqby": "^4.7.0",
|
"lodash.uniqby": "^4.7.0",
|
||||||
"lunr": "^2.1.6",
|
"lunr": "^2.1.6",
|
||||||
"param-case": "^2.1.1",
|
"param-case": "^2.1.1",
|
||||||
"punycode": "^2.1.0",
|
|
||||||
"react": "^16.2.0",
|
"react": "^16.2.0",
|
||||||
"react-apollo": "^2.0.4",
|
"react-apollo": "^2.0.4",
|
||||||
"react-dom": "^16.2.0",
|
"react-dom": "^16.2.0",
|
||||||
|
@ -2,13 +2,12 @@ import React, { Fragment } from 'react';
|
|||||||
import { compose, graphql } from 'react-apollo';
|
import { compose, graphql } from 'react-apollo';
|
||||||
import { set } from 'react-redux-values';
|
import { set } from 'react-redux-values';
|
||||||
import ReduxForm from 'declarative-redux-form';
|
import ReduxForm from 'declarative-redux-form';
|
||||||
|
import { Row, Col } from 'joyent-react-styled-flexboxgrid';
|
||||||
import { Margin } from 'styled-components-spacing';
|
import { Margin } from 'styled-components-spacing';
|
||||||
import { change } from 'redux-form';
|
import { change } from 'redux-form';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import intercept from 'apr-intercept';
|
import intercept from 'apr-intercept';
|
||||||
import get from 'lodash.get';
|
import get from 'lodash.get';
|
||||||
import punycode from 'punycode';
|
|
||||||
import { Row, Col } from 'joyent-react-styled-flexboxgrid';
|
|
||||||
|
|
||||||
import { NameIcon, H3, Button, H4, P } from 'joyent-ui-toolkit';
|
import { NameIcon, H3, Button, H4, P } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
@ -16,7 +15,8 @@ import Title from '@components/create-image/title';
|
|||||||
import Details from '@components/create-image/details';
|
import Details from '@components/create-image/details';
|
||||||
import Description from '@components/description';
|
import Description from '@components/description';
|
||||||
import GetRandomName from '@graphql/get-random-name.gql';
|
import GetRandomName from '@graphql/get-random-name.gql';
|
||||||
import createStore from '@state/apollo-client';
|
import createClient from '@state/apollo-client';
|
||||||
|
import { instanceName as validateName } from '@state/validators';
|
||||||
import { Forms } from '@root/constants';
|
import { Forms } from '@root/constants';
|
||||||
|
|
||||||
const NameContainer = ({
|
const NameContainer = ({
|
||||||
@ -27,7 +27,7 @@ const NameContainer = ({
|
|||||||
description,
|
description,
|
||||||
placeholderName,
|
placeholderName,
|
||||||
randomizing,
|
randomizing,
|
||||||
handleAsyncValidation,
|
handleAsyncValidate,
|
||||||
shouldAsyncValidate,
|
shouldAsyncValidate,
|
||||||
handleNext,
|
handleNext,
|
||||||
handleRandomize,
|
handleRandomize,
|
||||||
@ -54,9 +54,9 @@ const NameContainer = ({
|
|||||||
form={Forms.FORM_DETAILS}
|
form={Forms.FORM_DETAILS}
|
||||||
destroyOnUnmount={false}
|
destroyOnUnmount={false}
|
||||||
forceUnregisterOnUnmount={true}
|
forceUnregisterOnUnmount={true}
|
||||||
onSubmit={handleNext}
|
asyncValidate={handleAsyncValidate}
|
||||||
asyncValidate={handleAsyncValidation}
|
|
||||||
shouldAsyncValidate={shouldAsyncValidate}
|
shouldAsyncValidate={shouldAsyncValidate}
|
||||||
|
onSubmit={handleNext}
|
||||||
>
|
>
|
||||||
{props =>
|
{props =>
|
||||||
expanded ? (
|
expanded ? (
|
||||||
@ -121,6 +121,7 @@ export default compose(
|
|||||||
({ form, values }, ownProps) => {
|
({ form, values }, ownProps) => {
|
||||||
const name = get(form, `${Forms.FORM_DETAILS}.values.name`, '');
|
const name = get(form, `${Forms.FORM_DETAILS}.values.name`, '');
|
||||||
const version = get(form, `${Forms.FORM_DETAILS}.values.version`, '');
|
const version = get(form, `${Forms.FORM_DETAILS}.values.version`, '');
|
||||||
|
|
||||||
const description = get(
|
const description = get(
|
||||||
form,
|
form,
|
||||||
`${Forms.FORM_DETAILS}.values.description`,
|
`${Forms.FORM_DETAILS}.values.description`,
|
||||||
@ -128,7 +129,6 @@ export default compose(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const proceeded = get(values, `${Forms.FORM_DETAILS}-proceeded`, false);
|
const proceeded = get(values, `${Forms.FORM_DETAILS}-proceeded`, false);
|
||||||
|
|
||||||
const randomizing = get(values, 'create-image-name-randomizing', false);
|
const randomizing = get(values, 'create-image-name-randomizing', false);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -141,35 +141,23 @@ export default compose(
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
(dispatch, { history, match }) => ({
|
(dispatch, { history, match }) => ({
|
||||||
shouldAsyncValidate: ({ trigger }) => trigger === 'submit',
|
|
||||||
handleAsyncValidation: async ({ name }) => {
|
|
||||||
const sanitized = punycode.encode(name).replace(/-$/, '');
|
|
||||||
|
|
||||||
if (sanitized !== name) {
|
|
||||||
// eslint-disable-next-line no-throw-literal
|
|
||||||
throw {
|
|
||||||
name: 'Special characters are not accepted'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!/^[a-zA-Z0-9][a-zA-Z0-9\\_\\.\\-]*$/.test(name)) {
|
|
||||||
// eslint-disable-next-line no-throw-literal
|
|
||||||
throw {
|
|
||||||
name: 'Invalid name'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleNext: () => {
|
handleNext: () => {
|
||||||
dispatch(set({ name: `${Forms.FORM_DETAILS}-proceeded`, value: true }));
|
dispatch(set({ name: `${Forms.FORM_DETAILS}-proceeded`, value: true }));
|
||||||
|
|
||||||
return history.push(`/~create/${match.params.instance}/tag`);
|
return history.push(`/~create/${match.params.instance}/tag`);
|
||||||
},
|
},
|
||||||
handleEdit: () => history.push(`/~create/${match.params.instance}/name`),
|
handleEdit: () => {
|
||||||
|
dispatch(set({ name: `${Forms.FORM_DETAILS}-proceeded`, value: true }));
|
||||||
|
return history.push(`/~create/${match.params.instance}/name`);
|
||||||
|
},
|
||||||
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
|
return trigger === 'change';
|
||||||
|
},
|
||||||
|
handleAsyncValidate: validateName,
|
||||||
handleRandomize: async () => {
|
handleRandomize: async () => {
|
||||||
dispatch(set({ name: 'create-image-name-randomizing', value: true }));
|
dispatch(set({ name: 'create-image-name-randomizing', value: true }));
|
||||||
|
|
||||||
const [err, res] = await intercept(
|
const [err, res] = await intercept(
|
||||||
createStore().query({
|
createClient().query({
|
||||||
fetchPolicy: 'network-only',
|
fetchPolicy: 'network-only',
|
||||||
query: GetRandomName
|
query: GetRandomName
|
||||||
})
|
})
|
||||||
|
@ -21,6 +21,7 @@ import {
|
|||||||
import Title from '@components/create-image/title';
|
import Title from '@components/create-image/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 { Forms } from '@root/constants';
|
import { Forms } from '@root/constants';
|
||||||
|
|
||||||
export const Tags = ({
|
export const Tags = ({
|
||||||
@ -34,6 +35,8 @@ export const Tags = ({
|
|||||||
handleToggleExpanded,
|
handleToggleExpanded,
|
||||||
handleCancelEdit,
|
handleCancelEdit,
|
||||||
handleChangeAddOpen,
|
handleChangeAddOpen,
|
||||||
|
handleAsyncValidate,
|
||||||
|
shouldAsyncValidate,
|
||||||
handleNext,
|
handleNext,
|
||||||
step,
|
step,
|
||||||
handleEdit,
|
handleEdit,
|
||||||
@ -84,6 +87,8 @@ export const Tags = ({
|
|||||||
form={Forms.FORM_TAGS_CREATE}
|
form={Forms.FORM_TAGS_CREATE}
|
||||||
destroyOnUnmount={false}
|
destroyOnUnmount={false}
|
||||||
forceUnregisterOnUnmount={true}
|
forceUnregisterOnUnmount={true}
|
||||||
|
asyncValidate={handleAsyncValidate}
|
||||||
|
shouldAsyncValidate={shouldAsyncValidate}
|
||||||
onSubmit={handleAddTag}
|
onSubmit={handleAddTag}
|
||||||
>
|
>
|
||||||
{props =>
|
{props =>
|
||||||
@ -141,6 +146,10 @@ export default compose(
|
|||||||
handleEdit: () => {
|
handleEdit: () => {
|
||||||
return history.push(`/~create/${match.params.instance}/tag`);
|
return history.push(`/~create/${match.params.instance}/tag`);
|
||||||
},
|
},
|
||||||
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
|
return trigger === 'submit';
|
||||||
|
},
|
||||||
|
handleAsyncValidate: validateTag,
|
||||||
handleAddTag: value => {
|
handleAddTag: value => {
|
||||||
const toggleToClosed = set({
|
const toggleToClosed = set({
|
||||||
name: `${Forms.CREATE_TAGS}-add-open`,
|
name: `${Forms.CREATE_TAGS}-add-open`,
|
||||||
|
@ -27,6 +27,7 @@ import Tag, { AddForm } from '@components/tags';
|
|||||||
import ToolbarForm from '@components/toolbar';
|
import ToolbarForm from '@components/toolbar';
|
||||||
import UpdateImageTags from '@graphql/update-image-tags.gql';
|
import UpdateImageTags from '@graphql/update-image-tags.gql';
|
||||||
import GetTags from '@graphql/get-tags.gql';
|
import GetTags from '@graphql/get-tags.gql';
|
||||||
|
import { addTag as validateTag } from '@state/validators';
|
||||||
import parseError from '@state/parse-error';
|
import parseError from '@state/parse-error';
|
||||||
|
|
||||||
const { TAGS_TOOLBAR_FORM, TAGS_ADD_FORM } = Forms;
|
const { TAGS_TOOLBAR_FORM, TAGS_ADD_FORM } = Forms;
|
||||||
@ -38,6 +39,8 @@ export const Tags = ({
|
|||||||
error = null,
|
error = null,
|
||||||
mutationError = null,
|
mutationError = null,
|
||||||
mutating = false,
|
mutating = false,
|
||||||
|
handleAsyncValidate,
|
||||||
|
shouldAsyncValidate,
|
||||||
handleToggleAddOpen,
|
handleToggleAddOpen,
|
||||||
handleRemoveTag,
|
handleRemoveTag,
|
||||||
handleAddTag
|
handleAddTag
|
||||||
@ -76,7 +79,12 @@ export const Tags = ({
|
|||||||
</Message>
|
</Message>
|
||||||
</Margin>
|
</Margin>
|
||||||
) : null}
|
) : null}
|
||||||
<ReduxForm form={TAGS_ADD_FORM} onSubmit={handleAddTag}>
|
<ReduxForm
|
||||||
|
form={TAGS_ADD_FORM}
|
||||||
|
asyncValidate={handleAsyncValidate}
|
||||||
|
shouldAsyncValidate={shouldAsyncValidate}
|
||||||
|
onSubmit={handleAddTag}
|
||||||
|
>
|
||||||
{props =>
|
{props =>
|
||||||
addOpen ? (
|
addOpen ? (
|
||||||
<Margin bottom={4}>
|
<Margin bottom={4}>
|
||||||
@ -162,6 +170,10 @@ export default compose(
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
(dispatch, { image, tags = [], updateTags, refetch }) => ({
|
(dispatch, { image, tags = [], updateTags, refetch }) => ({
|
||||||
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
|
return trigger === 'submit';
|
||||||
|
},
|
||||||
|
handleAsyncValidate: validateTag,
|
||||||
handleToggleAddOpen: addOpen => {
|
handleToggleAddOpen: addOpen => {
|
||||||
dispatch(set({ name: `${image.id}-add-open`, value: addOpen }));
|
dispatch(set({ name: `${image.id}-add-open`, value: addOpen }));
|
||||||
},
|
},
|
||||||
|
67
packages/my-joy-images/src/state/validators.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import intercept from 'apr-intercept';
|
||||||
|
import keys from 'lodash.keys';
|
||||||
|
import reduce from 'apr-reduce';
|
||||||
|
import assign from 'lodash.assign';
|
||||||
|
import yup from 'yup';
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
const validateField = async (field, value) => {
|
||||||
|
const [err] = await intercept(field.validate(value));
|
||||||
|
return err ? err.errors.shift() : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateSchema = async (schema, value) => {
|
||||||
|
const errors = await reduce(
|
||||||
|
keys(schema),
|
||||||
|
async (errors, name) =>
|
||||||
|
assign(errors, {
|
||||||
|
[name]: await validateField(schema[name], value[name])
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
throw errors;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
const matches = {
|
||||||
|
nameStart: /^[a-zA-Z]|\d/,
|
||||||
|
nameBody: /^([a-zA-Z]|\d|\.|_|-)+$/
|
||||||
|
};
|
||||||
|
|
||||||
|
const msgs = {
|
||||||
|
required: prefix => `${prefix} must be defined.`,
|
||||||
|
nameStart: prefix => `${prefix} can only start with letters and numbers.`,
|
||||||
|
nameBody: prefix =>
|
||||||
|
`${prefix} cannot contain spaces and can only contain letters, numbers, periods (.), underscores (_), and hyphens (-).`
|
||||||
|
};
|
||||||
|
|
||||||
|
const Schemas = {
|
||||||
|
tag: {
|
||||||
|
name: yup
|
||||||
|
.string()
|
||||||
|
.required(msgs.required('Key'))
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Key'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Key')),
|
||||||
|
value: yup
|
||||||
|
.string()
|
||||||
|
.required(msgs.required('Value'))
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Value'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Value'))
|
||||||
|
},
|
||||||
|
instanceName: {
|
||||||
|
name: yup
|
||||||
|
.string()
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Instance name'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Instance Name'))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
export const addTag = tag => validateSchema(Schemas.tag, tag);
|
||||||
|
|
||||||
|
export const instanceName = ({ name }) =>
|
||||||
|
!name ? null : validateSchema(Schemas.instanceName, { name });
|
@ -11,7 +11,7 @@
|
|||||||
"build:lib": "echo 0",
|
"build:lib": "echo 0",
|
||||||
"build:bundle": "NODE_ENV=production redrun -p build:frontend build:ssr",
|
"build:bundle": "NODE_ENV=production redrun -p build:frontend build:ssr",
|
||||||
"prepublish": "NODE_ENV=production redrun build:bundle",
|
"prepublish": "NODE_ENV=production redrun build:bundle",
|
||||||
"lint": "redrun lint:ci -- -- --fix",
|
"lint": "redrun lint:ci -- --fix",
|
||||||
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
||||||
"test": "DEFAULT_TIMEOUT_INTERVAL=100000 NODE_ENV=test joyent-react-scripts test --env=jsdom",
|
"test": "DEFAULT_TIMEOUT_INTERVAL=100000 NODE_ENV=test joyent-react-scripts test --env=jsdom",
|
||||||
"test:ci": "NODE_ENV=test joyent-react-scripts test --env=jsdom --testPathIgnorePatterns='.ui.js'",
|
"test:ci": "NODE_ENV=test joyent-react-scripts test --env=jsdom --testPathIgnorePatterns='.ui.js'",
|
||||||
@ -22,6 +22,7 @@
|
|||||||
"@manaflair/redux-batch": "^0.1.0",
|
"@manaflair/redux-batch": "^0.1.0",
|
||||||
"apollo": "^0.2.2",
|
"apollo": "^0.2.2",
|
||||||
"apr-intercept": "^3.0.3",
|
"apr-intercept": "^3.0.3",
|
||||||
|
"apr-reduce": "^3.0.3",
|
||||||
"bytes": "^3.0.0",
|
"bytes": "^3.0.0",
|
||||||
"clipboard-copy": "^1.4.2",
|
"clipboard-copy": "^1.4.2",
|
||||||
"constant-case": "^2.0.0",
|
"constant-case": "^2.0.0",
|
||||||
@ -47,13 +48,13 @@
|
|||||||
"lodash.isfunction": "^3.0.9",
|
"lodash.isfunction": "^3.0.9",
|
||||||
"lodash.isinteger": "^4.0.4",
|
"lodash.isinteger": "^4.0.4",
|
||||||
"lodash.omit": "^4.5.0",
|
"lodash.omit": "^4.5.0",
|
||||||
|
"lodash.reduce": "^4.6.0",
|
||||||
"lodash.reverse": "^4.0.1",
|
"lodash.reverse": "^4.0.1",
|
||||||
"lodash.some": "^4.6.0",
|
"lodash.some": "^4.6.0",
|
||||||
"lodash.sortby": "^4.7.0",
|
"lodash.sortby": "^4.7.0",
|
||||||
"lodash.uniqby": "^4.7.0",
|
"lodash.uniqby": "^4.7.0",
|
||||||
"lodash.values": "^4.3.0",
|
"lodash.values": "^4.3.0",
|
||||||
"param-case": "^2.1.1",
|
"param-case": "^2.1.1",
|
||||||
"punycode": "^2.1.0",
|
|
||||||
"query-string": "^5.1.0",
|
"query-string": "^5.1.0",
|
||||||
"react": "^16.2.0",
|
"react": "^16.2.0",
|
||||||
"react-apollo": "^2.0.4",
|
"react-apollo": "^2.0.4",
|
||||||
@ -68,7 +69,8 @@
|
|||||||
"styled-components": "^3.1.6",
|
"styled-components": "^3.1.6",
|
||||||
"styled-components-spacing": "^2.1.3",
|
"styled-components-spacing": "^2.1.3",
|
||||||
"styled-flex-component": "^2.2.1",
|
"styled-flex-component": "^2.2.1",
|
||||||
"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",
|
||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@ -466,11 +466,6 @@ exports[`renders <AddServiceForm pristine /> without throwing 1`] = `
|
|||||||
background-color: rgb(59,70,204);
|
background-color: rgb(59,70,204);
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
border: solid 0.0625rem rgb(45,56,132);
|
border: solid 0.0625rem rgb(45,56,132);
|
||||||
cursor: not-allowed;
|
|
||||||
pointer-events: none;
|
|
||||||
color: rgb(216,216,216);
|
|
||||||
background-color: rgb(250,250,250);
|
|
||||||
border-color: rgb(216,216,216);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.c7:focus {
|
.c7:focus {
|
||||||
@ -500,23 +495,6 @@ exports[`renders <AddServiceForm pristine /> without throwing 1`] = `
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c7:focus {
|
|
||||||
background-color: rgb(250,250,250);
|
|
||||||
border-color: rgb(216,216,216);
|
|
||||||
}
|
|
||||||
|
|
||||||
.c7:hover {
|
|
||||||
background-color: rgb(250,250,250);
|
|
||||||
border-color: rgb(250,250,250);
|
|
||||||
}
|
|
||||||
|
|
||||||
.c7:active,
|
|
||||||
.c7:active:hover,
|
|
||||||
.c7:active:focus {
|
|
||||||
background-color: rgb(250,250,250);
|
|
||||||
border-color: rgb(250,250,250);
|
|
||||||
}
|
|
||||||
|
|
||||||
.c3 {
|
.c3 {
|
||||||
font-size: 0.9375rem;
|
font-size: 0.9375rem;
|
||||||
line-height: 1.125rem;
|
line-height: 1.125rem;
|
||||||
@ -678,7 +656,7 @@ exports[`renders <AddServiceForm pristine /> without throwing 1`] = `
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="c7 c8 c9"
|
className="c7 c8 c9"
|
||||||
disabled={true}
|
disabled={undefined}
|
||||||
href=""
|
href=""
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
|
@ -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={pristine || invalid}
|
disabled={submitting || invalid}
|
||||||
loading={submitting}
|
loading={submitting}
|
||||||
inline
|
inline
|
||||||
>
|
>
|
||||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@ -13,13 +13,11 @@ Array [
|
|||||||
:
|
:
|
||||||
</span>,
|
</span>,
|
||||||
" be on a ",
|
" be on a ",
|
||||||
" ",
|
|
||||||
" node as the instance(s) identified by the instance ",
|
" node as the instance(s) identified by the instance ",
|
||||||
" ",
|
" ",
|
||||||
"key “",
|
"key “",
|
||||||
"\\" and the instance tag value",
|
"\\" and the instance tag value",
|
||||||
" ",
|
" ",
|
||||||
" ",
|
|
||||||
" \\"",
|
" \\"",
|
||||||
"”",
|
"”",
|
||||||
]
|
]
|
||||||
@ -38,13 +36,11 @@ Array [
|
|||||||
:
|
:
|
||||||
</span>,
|
</span>,
|
||||||
" be on a ",
|
" be on a ",
|
||||||
" ",
|
|
||||||
" node as the instance(s) identified by the instance ",
|
" node as the instance(s) identified by the instance ",
|
||||||
" ",
|
" ",
|
||||||
"key “",
|
"key “",
|
||||||
"\\" and the instance tag value",
|
"\\" and the instance tag value",
|
||||||
" ",
|
" ",
|
||||||
" ",
|
|
||||||
" \\"",
|
" \\"",
|
||||||
"”",
|
"”",
|
||||||
]
|
]
|
||||||
@ -52,7 +48,7 @@ Array [
|
|||||||
|
|
||||||
exports[`renders <Rule/> without throwing 1`] = `
|
exports[`renders <Rule/> without throwing 1`] = `
|
||||||
.c0 {
|
.c0 {
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c12 {
|
.c12 {
|
||||||
@ -667,8 +663,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
className="c2"
|
className="c2"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -676,7 +672,7 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="baseline-jVaZNU kXgQxt c3"
|
className="baseline-jVaZNU kXgQxt c3"
|
||||||
name="rule-instance-conditional"
|
name="conditional"
|
||||||
role="group"
|
role="group"
|
||||||
style={undefined}
|
style={undefined}
|
||||||
>
|
>
|
||||||
@ -685,8 +681,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
disabled={false}
|
disabled={false}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="4.125rem"
|
width="4.125rem"
|
||||||
@ -698,8 +694,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
onBlur={undefined}
|
onBlur={undefined}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="4.125rem"
|
width="4.125rem"
|
||||||
@ -721,8 +717,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
className="c2"
|
className="c2"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -730,7 +726,7 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="baseline-jVaZNU kXgQxt c3"
|
className="baseline-jVaZNU kXgQxt c3"
|
||||||
name="rule-instance-placement"
|
name="placement"
|
||||||
role="group"
|
role="group"
|
||||||
style={undefined}
|
style={undefined}
|
||||||
>
|
>
|
||||||
@ -739,8 +735,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
disabled={false}
|
disabled={false}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="6.25rem"
|
width="6.25rem"
|
||||||
@ -752,8 +748,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
onBlur={undefined}
|
onBlur={undefined}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="6.25rem"
|
width="6.25rem"
|
||||||
@ -775,8 +771,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
className="c2"
|
className="c2"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -784,7 +780,7 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="baseline-jVaZNU kXgQxt c3"
|
className="baseline-jVaZNU kXgQxt c3"
|
||||||
name="rule-type"
|
name="type"
|
||||||
role="group"
|
role="group"
|
||||||
style={undefined}
|
style={undefined}
|
||||||
>
|
>
|
||||||
@ -793,8 +789,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
disabled={false}
|
disabled={false}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="8.4375rem"
|
width="8.4375rem"
|
||||||
@ -806,8 +802,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
onBlur={undefined}
|
onBlur={undefined}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="8.4375rem"
|
width="8.4375rem"
|
||||||
@ -827,7 +823,7 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="baseline-jVaZNU kXgQxt c3"
|
className="baseline-jVaZNU kXgQxt c3"
|
||||||
name="rule-instance-name-pattern"
|
name="pattern"
|
||||||
role="group"
|
role="group"
|
||||||
style={undefined}
|
style={undefined}
|
||||||
>
|
>
|
||||||
@ -839,8 +835,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
disabled={false}
|
disabled={false}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="8.125rem"
|
width="8.125rem"
|
||||||
@ -852,8 +848,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
onBlur={undefined}
|
onBlur={undefined}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="8.125rem"
|
width="8.125rem"
|
||||||
@ -889,7 +885,7 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="baseline-jVaZNU kXgQxt c3"
|
className="baseline-jVaZNU kXgQxt c3"
|
||||||
name="rule-instance-name"
|
name="value"
|
||||||
role="group"
|
role="group"
|
||||||
style={undefined}
|
style={undefined}
|
||||||
>
|
>
|
||||||
@ -902,8 +898,8 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
required={true}
|
required={true}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -914,7 +910,7 @@ exports[`renders <Rule/> without throwing 1`] = `
|
|||||||
|
|
||||||
exports[`renders <Rule/> without throwing 2`] = `
|
exports[`renders <Rule/> without throwing 2`] = `
|
||||||
.c0 {
|
.c0 {
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c12 {
|
.c12 {
|
||||||
@ -1529,8 +1525,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
className="c2"
|
className="c2"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -1538,7 +1534,7 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="baseline-jVaZNU kXgQxt c3"
|
className="baseline-jVaZNU kXgQxt c3"
|
||||||
name="rule-instance-conditional"
|
name="conditional"
|
||||||
role="group"
|
role="group"
|
||||||
style={undefined}
|
style={undefined}
|
||||||
>
|
>
|
||||||
@ -1547,8 +1543,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
disabled={false}
|
disabled={false}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="4.125rem"
|
width="4.125rem"
|
||||||
@ -1560,8 +1556,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
onBlur={undefined}
|
onBlur={undefined}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="4.125rem"
|
width="4.125rem"
|
||||||
@ -1583,8 +1579,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
className="c2"
|
className="c2"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -1592,7 +1588,7 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="baseline-jVaZNU kXgQxt c3"
|
className="baseline-jVaZNU kXgQxt c3"
|
||||||
name="rule-instance-placement"
|
name="placement"
|
||||||
role="group"
|
role="group"
|
||||||
style={undefined}
|
style={undefined}
|
||||||
>
|
>
|
||||||
@ -1601,8 +1597,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
disabled={false}
|
disabled={false}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="6.25rem"
|
width="6.25rem"
|
||||||
@ -1614,8 +1610,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
onBlur={undefined}
|
onBlur={undefined}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="6.25rem"
|
width="6.25rem"
|
||||||
@ -1637,8 +1633,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
className="c2"
|
className="c2"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -1646,7 +1642,7 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="baseline-jVaZNU kXgQxt c3"
|
className="baseline-jVaZNU kXgQxt c3"
|
||||||
name="rule-type"
|
name="type"
|
||||||
role="group"
|
role="group"
|
||||||
style={undefined}
|
style={undefined}
|
||||||
>
|
>
|
||||||
@ -1655,8 +1651,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
disabled={false}
|
disabled={false}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="8.4375rem"
|
width="8.4375rem"
|
||||||
@ -1668,8 +1664,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
onBlur={undefined}
|
onBlur={undefined}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="8.4375rem"
|
width="8.4375rem"
|
||||||
@ -1689,7 +1685,7 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="baseline-jVaZNU kXgQxt c3"
|
className="baseline-jVaZNU kXgQxt c3"
|
||||||
name="rule-instance-name-pattern"
|
name="pattern"
|
||||||
role="group"
|
role="group"
|
||||||
style={undefined}
|
style={undefined}
|
||||||
>
|
>
|
||||||
@ -1701,8 +1697,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
disabled={false}
|
disabled={false}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="8.125rem"
|
width="8.125rem"
|
||||||
@ -1714,8 +1710,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
onBlur={undefined}
|
onBlur={undefined}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
width="8.125rem"
|
width="8.125rem"
|
||||||
@ -1751,7 +1747,7 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="baseline-jVaZNU kXgQxt c3"
|
className="baseline-jVaZNU kXgQxt c3"
|
||||||
name="rule-instance-name"
|
name="value"
|
||||||
role="group"
|
role="group"
|
||||||
style={undefined}
|
style={undefined}
|
||||||
>
|
>
|
||||||
@ -1764,8 +1760,8 @@ exports[`renders <Rule/> without throwing 2`] = `
|
|||||||
required={true}
|
required={true}
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"fontSize": "18px",
|
"fontSize": "1.125rem",
|
||||||
"lineHeight": "48px",
|
"lineHeight": "3rem",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -24,14 +24,12 @@ it('renders <Rule/> without throwing', () => {
|
|||||||
<Theme>
|
<Theme>
|
||||||
<Rule
|
<Rule
|
||||||
rule={{
|
rule={{
|
||||||
'rule-instance-name': 'test',
|
conditional: 'must',
|
||||||
'rule-instance-conditional': 'must',
|
placement: 'same',
|
||||||
'rule-instance-placement': 'same',
|
pattern: 'equalling',
|
||||||
'rule-instance-tag-value-pattern': 'equalling',
|
value: 'test',
|
||||||
'rule-instance-name-pattern': 'equalling',
|
key: '',
|
||||||
'rule-instance-tag-value': '',
|
type: 'name'
|
||||||
'rule-instance-tag-key': '',
|
|
||||||
'rule-type': 'name'
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Theme>
|
</Theme>
|
||||||
@ -47,14 +45,12 @@ it('renders <Header /> without throwing', () => {
|
|||||||
<Theme>
|
<Theme>
|
||||||
<Header
|
<Header
|
||||||
rule={{
|
rule={{
|
||||||
'rule-instance-name': 'test',
|
conditional: 'must',
|
||||||
'rule-instance-conditional': 'must',
|
placement: 'same',
|
||||||
'rule-instance-placement': 'same',
|
pattern: 'equalling',
|
||||||
'rule-instance-tag-value-pattern': 'equalling',
|
value: 'test',
|
||||||
'rule-instance-name-pattern': 'equalling',
|
key: '',
|
||||||
'rule-instance-tag-value': '',
|
type: 'name'
|
||||||
'rule-instance-tag-key': '',
|
|
||||||
'rule-type': 'name'
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Theme>
|
</Theme>
|
||||||
@ -70,14 +66,12 @@ it('renders <Header tag/> without throwing', () => {
|
|||||||
<Theme>
|
<Theme>
|
||||||
<Header
|
<Header
|
||||||
rule={{
|
rule={{
|
||||||
'rule-instance-name': 'test',
|
conditional: 'must',
|
||||||
'rule-instance-conditional': 'must',
|
placement: 'same',
|
||||||
'rule-instance-placement': 'same',
|
pattern: 'equalling',
|
||||||
'rule-instance-tag-value-pattern': 'equalling',
|
value: 'one',
|
||||||
'rule-instance-name-pattern': 'equalling',
|
key: 'two',
|
||||||
'rule-instance-tag-value': 'one',
|
type: 'tag'
|
||||||
'rule-instance-tag-key': 'two',
|
|
||||||
'rule-type': 'tag'
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Theme>
|
</Theme>
|
||||||
|
@ -25,14 +25,12 @@ it('<Rule/>', async () => {
|
|||||||
<Theme ss>
|
<Theme ss>
|
||||||
<Rule
|
<Rule
|
||||||
rule={{
|
rule={{
|
||||||
'rule-instance-name': 'test',
|
conditional: 'must',
|
||||||
'rule-instance-conditional': 'must',
|
placement: 'same',
|
||||||
'rule-instance-placement': 'same',
|
pattern: 'equalling',
|
||||||
'rule-instance-tag-value-pattern': 'equalling',
|
value: 'test',
|
||||||
'rule-instance-name-pattern': 'equalling',
|
key: '',
|
||||||
'rule-instance-tag-value': '',
|
type: 'name'
|
||||||
'rule-instance-tag-key': '',
|
|
||||||
'rule-type': 'name'
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Theme>
|
</Theme>
|
||||||
@ -46,14 +44,12 @@ it('<Header />', async () => {
|
|||||||
<Theme ss>
|
<Theme ss>
|
||||||
<Header
|
<Header
|
||||||
rule={{
|
rule={{
|
||||||
'rule-instance-name': 'test',
|
conditional: 'must',
|
||||||
'rule-instance-conditional': 'must',
|
placement: 'same',
|
||||||
'rule-instance-placement': 'same',
|
pattern: 'equalling',
|
||||||
'rule-instance-tag-value-pattern': 'equalling',
|
value: 'test',
|
||||||
'rule-instance-name-pattern': 'equalling',
|
key: '',
|
||||||
'rule-instance-tag-value': '',
|
type: 'name'
|
||||||
'rule-instance-tag-key': '',
|
|
||||||
'rule-type': 'name'
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Theme>
|
</Theme>
|
||||||
@ -67,14 +63,12 @@ it('<Header tag/>', async () => {
|
|||||||
<Theme ss>
|
<Theme ss>
|
||||||
<Header
|
<Header
|
||||||
rule={{
|
rule={{
|
||||||
'rule-instance-name': 'test',
|
conditional: 'must',
|
||||||
'rule-instance-conditional': 'must',
|
placement: 'same',
|
||||||
'rule-instance-placement': 'same',
|
pattern: 'equalling',
|
||||||
'rule-instance-tag-value-pattern': 'equalling',
|
value: 'one',
|
||||||
'rule-instance-name-pattern': 'equalling',
|
key: 'two',
|
||||||
'rule-instance-tag-value': 'one',
|
type: 'tag'
|
||||||
'rule-instance-tag-key': 'two',
|
|
||||||
'rule-type': 'tag'
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Theme>
|
</Theme>
|
||||||
|
@ -9,8 +9,8 @@ import remcalc from 'remcalc';
|
|||||||
import { H5, Select, Input, FormGroup, FormMeta } from 'joyent-ui-toolkit';
|
import { H5, Select, Input, FormGroup, FormMeta } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
lineHeight: '48px',
|
lineHeight: remcalc(48),
|
||||||
fontSize: '18px'
|
fontSize: remcalc(18)
|
||||||
};
|
};
|
||||||
|
|
||||||
const Bold = styled.span`
|
const Bold = styled.span`
|
||||||
@ -19,7 +19,7 @@ const Bold = styled.span`
|
|||||||
|
|
||||||
const Values = touched => (
|
const Values = touched => (
|
||||||
<Margin right={1}>
|
<Margin right={1}>
|
||||||
<Select style={style} touched={touched} embedded width={remcalc(130)}>
|
<Select style={style} touched={touched} width={remcalc(130)} embedded>
|
||||||
<option value="equalling">equalling</option>
|
<option value="equalling">equalling</option>
|
||||||
<option value="not-equalling">not equalling</option>
|
<option value="not-equalling">not equalling</option>
|
||||||
<option value="containing">containing</option>
|
<option value="containing">containing</option>
|
||||||
@ -29,16 +29,16 @@ const Values = touched => (
|
|||||||
</Margin>
|
</Margin>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Rule = rule => (
|
export const Rule = ({ valid, ...rule }) => (
|
||||||
<Margin bottom={4}>
|
<Margin bottom={valid ? 4 : 8}>
|
||||||
<Flex alignCenter wrap>
|
<Flex alignCenter wrap>
|
||||||
<H5 style={style} inline noMargin>
|
<H5 style={style} inline noMargin>
|
||||||
The instance
|
The instance
|
||||||
</H5>
|
</H5>
|
||||||
<FormGroup name="rule-instance-conditional" field={Field}>
|
<FormGroup name="conditional" field={Field}>
|
||||||
<Select
|
<Select
|
||||||
style={style}
|
style={style}
|
||||||
touched={rule['rule-instance-conditional']}
|
touched={rule.conditional}
|
||||||
width={remcalc(66)}
|
width={remcalc(66)}
|
||||||
embedded
|
embedded
|
||||||
>
|
>
|
||||||
@ -49,10 +49,10 @@ export const Rule = rule => (
|
|||||||
<H5 style={style} inline noMargin>
|
<H5 style={style} inline noMargin>
|
||||||
be on
|
be on
|
||||||
</H5>
|
</H5>
|
||||||
<FormGroup name="rule-instance-placement" field={Field}>
|
<FormGroup name="placement" field={Field}>
|
||||||
<Select
|
<Select
|
||||||
style={style}
|
style={style}
|
||||||
touched={rule['rule-instance-placement']}
|
touched={rule.placement}
|
||||||
width={remcalc(100)}
|
width={remcalc(100)}
|
||||||
embedded
|
embedded
|
||||||
>
|
>
|
||||||
@ -63,10 +63,10 @@ export const Rule = rule => (
|
|||||||
<H5 style={style} inline noMargin>
|
<H5 style={style} inline noMargin>
|
||||||
node as the instance(s) identified by the
|
node as the instance(s) identified by the
|
||||||
</H5>
|
</H5>
|
||||||
<FormGroup name="rule-type" field={Field}>
|
<FormGroup name="type" field={Field}>
|
||||||
<Select
|
<Select
|
||||||
style={style}
|
style={style}
|
||||||
touched={rule['rule-type']}
|
touched={rule.type}
|
||||||
width={remcalc(135)}
|
width={remcalc(135)}
|
||||||
embedded
|
embedded
|
||||||
left
|
left
|
||||||
@ -75,54 +75,53 @@ export const Rule = rule => (
|
|||||||
<option value="tag">tag</option>
|
<option value="tag">tag</option>
|
||||||
</Select>
|
</Select>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
{rule['rule-type'] === 'tag' ? (
|
{rule.type === 'tag' ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<FormGroup name="rule-instance-tag-key" field={Field}>
|
<FormGroup name="key" field={Field}>
|
||||||
<Input
|
<Input
|
||||||
style={style}
|
style={style}
|
||||||
onBlur={null}
|
onBlur={null}
|
||||||
|
type="text"
|
||||||
|
placeholder="key"
|
||||||
small
|
small
|
||||||
embedded
|
embedded
|
||||||
type="text"
|
|
||||||
required
|
required
|
||||||
placeholder="key"
|
|
||||||
/>
|
/>
|
||||||
<FormMeta small />
|
<FormMeta small absolute />
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<H5 style={style} inline noMargin>
|
<H5 style={style} inline noMargin>
|
||||||
and value{' '}
|
and value{' '}
|
||||||
</H5>
|
</H5>
|
||||||
<FormGroup name="rule-instance-tag-value-pattern" field={Field}>
|
<FormGroup name="pattern" field={Field}>
|
||||||
{Values(rule['rule-instance-tag-value-pattern'])}
|
{Values(rule.pattern)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup name="rule-instance-tag-value" field={Field}>
|
<FormGroup name="value" field={Field}>
|
||||||
<Input
|
<Input
|
||||||
style={style}
|
style={style}
|
||||||
onBlur={null}
|
onBlur={null}
|
||||||
small
|
|
||||||
embedded
|
|
||||||
type="text"
|
type="text"
|
||||||
required
|
|
||||||
placeholder="value"
|
placeholder="value"
|
||||||
|
embedded
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
<FormMeta small />
|
<FormMeta small absolute />
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
) : (
|
) : (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<FormGroup name="rule-instance-name-pattern" field={Field}>
|
<FormGroup name="pattern" field={Field}>
|
||||||
{Values(rule['rule-instance-name-pattern'])}
|
{Values(rule.pattern)}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup name="rule-instance-name" field={Field}>
|
<FormGroup name="value" field={Field}>
|
||||||
<Input
|
<Input
|
||||||
onBlur={null}
|
onBlur={null}
|
||||||
embedded
|
|
||||||
style={style}
|
style={style}
|
||||||
type="text"
|
type="text"
|
||||||
required
|
|
||||||
placeholder="Example instance name: nginx"
|
placeholder="Example instance name: nginx"
|
||||||
|
embedded
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
<FormMeta />
|
<FormMeta absolute />
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
@ -132,21 +131,18 @@ export const Rule = rule => (
|
|||||||
|
|
||||||
export const Header = rule => (
|
export const Header = rule => (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Bold>{titleCase(rule['rule-instance-conditional'])}:</Bold> be on a{' '}
|
<Bold>{titleCase(rule.conditional)}:</Bold> be on a {rule.placement} node as
|
||||||
{rule['rule-instance-placement']} node as the instance(s) identified by the
|
the instance(s) identified by the instance {rule.type}
|
||||||
instance {rule['rule-type']}
|
{rule.type === 'name' ? (
|
||||||
{rule['rule-type'] === 'name' ? (
|
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{' '}
|
{' '}
|
||||||
{rule['rule-instance-name-pattern']} “{rule['rule-instance-name']}”
|
{rule.pattern} “{rule.value}”
|
||||||
</Fragment>
|
</Fragment>
|
||||||
) : (
|
) : (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{' '}
|
{' '}
|
||||||
key “{rule['rule-instance-tag-key']}" and the instance tag value{' '}
|
key “{rule.key}" and the instance tag value{' '}
|
||||||
{rule['rule-instance-tag-value-pattern'] &&
|
{rule.pattern && rule.pattern.split('-').join(' ')} "{rule.value}”
|
||||||
rule['rule-instance-tag-value-pattern'].split('-').join(' ')}{' '}
|
|
||||||
"{rule['rule-instance-tag-value']}”
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
export const fieldError =
|
|
||||||
'Please enter only letters, numbers, periods (.), underscores (_), and hyphens (-).';
|
|
@ -8,50 +8,48 @@ import { connect } from 'react-redux';
|
|||||||
import get from 'lodash.get';
|
import get from 'lodash.get';
|
||||||
import remcalc from 'remcalc';
|
import remcalc from 'remcalc';
|
||||||
|
|
||||||
import { AffinityIcon, Button, H3, Divider, KeyValue } from 'joyent-ui-toolkit';
|
import { AffinityIcon, Button, Divider, KeyValue } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
import Title from '@components/create-instance/title';
|
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 { fieldError } from '@root/constants';
|
import { addAffinityRule as validateRule } from '@state/validators';
|
||||||
|
|
||||||
const FORM_NAME_CREATE = 'CREATE-INSTANCE-AFFINITY-ADD';
|
const FORM_NAME_CREATE = 'CREATE-INSTANCE-AFFINITY-ADD';
|
||||||
const FORM_NAME_EDIT = i => `CREATE-INSTANCE-AFFINITY-EDIT-${i}`;
|
const FORM_NAME_EDIT = 'CREATE-INSTANCE-AFFINITY-EDIT';
|
||||||
|
|
||||||
const RULE_DEFAULTS = {
|
const RULE_DEFAULTS = {
|
||||||
'rule-instance-name': '',
|
conditional: 'should',
|
||||||
'rule-instance-conditional': 'should',
|
placement: 'same',
|
||||||
'rule-instance-placement': 'same',
|
type: 'name',
|
||||||
'rule-instance-tag-key-pattern': 'equalling',
|
pattern: 'equalling',
|
||||||
'rule-instance-tag-value-pattern': 'equalling',
|
key: '',
|
||||||
'rule-instance-name-pattern': 'equalling',
|
value: ''
|
||||||
'rule-instance-tag-value': '',
|
|
||||||
'rule-instance-tag-key': '',
|
|
||||||
'rule-type': 'name'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Affinity = ({
|
export const Affinity = ({
|
||||||
affinityRules = [],
|
step,
|
||||||
expanded,
|
expanded,
|
||||||
proceeded,
|
|
||||||
addOpen,
|
addOpen,
|
||||||
handleAddAffinityRules,
|
editOpen,
|
||||||
|
editingRule,
|
||||||
|
creatingRule,
|
||||||
|
exitingRule,
|
||||||
|
shouldAsyncValidate,
|
||||||
|
handleAsyncValidate,
|
||||||
|
handleCreateAffinityRules,
|
||||||
handleRemoveAffinityRule,
|
handleRemoveAffinityRule,
|
||||||
handleUpdateAffinityRule,
|
handleUpdateAffinityRule,
|
||||||
shouldAsyncValidate,
|
|
||||||
handleAsyncValidation,
|
|
||||||
handleToggleExpanded,
|
handleToggleExpanded,
|
||||||
handleCancelEdit,
|
handleCancelEdit,
|
||||||
handleChangeAddOpen,
|
handleChangeAddOpen,
|
||||||
handleEdit,
|
handleEdit
|
||||||
rule,
|
|
||||||
step
|
|
||||||
}) => (
|
}) => (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Title
|
<Title
|
||||||
id={step}
|
id={step}
|
||||||
onClick={!expanded && !proceeded && handleEdit}
|
onClick={!expanded && !exitingRule && handleEdit}
|
||||||
collapsed={!expanded && !proceeded}
|
collapsed={!expanded && !exitingRule}
|
||||||
icon={<AffinityIcon />}
|
icon={<AffinityIcon />}
|
||||||
>
|
>
|
||||||
Affinity
|
Affinity
|
||||||
@ -70,55 +68,64 @@ export const Affinity = ({
|
|||||||
</a>
|
</a>
|
||||||
</Description>
|
</Description>
|
||||||
) : null}
|
) : null}
|
||||||
{proceeded ? (
|
|
||||||
<Margin bottom={4}>
|
|
||||||
<H3>{affinityRules.length} Affinity Rule</H3>
|
|
||||||
</Margin>
|
|
||||||
) : null}
|
|
||||||
{affinityRules.map((rule, index) => (
|
|
||||||
<ReduxForm
|
<ReduxForm
|
||||||
form={FORM_NAME_EDIT(index)}
|
form={FORM_NAME_EDIT}
|
||||||
key={index}
|
initialValues={exitingRule}
|
||||||
initialValues={rule}
|
|
||||||
destroyOnUnmount={false}
|
destroyOnUnmount={false}
|
||||||
forceUnregisterOnUnmount={true}
|
forceUnregisterOnUnmount={false}
|
||||||
shouldAsyncValidate={shouldAsyncValidate}
|
shouldAsyncValidate={shouldAsyncValidate}
|
||||||
asyncValidation={handleAsyncValidation}
|
asyncValidation={handleAsyncValidate}
|
||||||
onSubmit={newValue => handleUpdateAffinityRule(index, newValue)}
|
onSubmit={handleUpdateAffinityRule}
|
||||||
>
|
>
|
||||||
{props => (
|
{formProps =>
|
||||||
|
exitingRule ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<KeyValue
|
<KeyValue
|
||||||
{...props}
|
{...formProps}
|
||||||
expanded={rule.expanded}
|
expanded={editOpen}
|
||||||
customHeader={<Header {...rule} />}
|
customHeader={<Header {...exitingRule} />}
|
||||||
method="edit"
|
method="edit"
|
||||||
input={props => <Rule {...rule} {...props} />}
|
input={inputProps => (
|
||||||
|
<Rule
|
||||||
|
{...editingRule}
|
||||||
|
{...inputProps}
|
||||||
|
valid={formProps.valid}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
type="an affinity rule"
|
type="an affinity rule"
|
||||||
onToggleExpanded={() => handleToggleExpanded(index)}
|
onToggleExpanded={() =>
|
||||||
onCancel={() => handleCancelEdit(index)}
|
handleToggleExpanded(!exitingRule.expanded)
|
||||||
onRemove={() => handleRemoveAffinityRule(index)}
|
}
|
||||||
|
onCancel={handleCancelEdit}
|
||||||
|
onRemove={handleRemoveAffinityRule}
|
||||||
/>
|
/>
|
||||||
<Divider height={remcalc(12)} transparent />
|
<Divider height={remcalc(12)} transparent />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
) : null
|
||||||
|
}
|
||||||
</ReduxForm>
|
</ReduxForm>
|
||||||
))}
|
|
||||||
<ReduxForm
|
<ReduxForm
|
||||||
form={FORM_NAME_CREATE}
|
form={FORM_NAME_CREATE}
|
||||||
|
initialValues={RULE_DEFAULTS}
|
||||||
destroyOnUnmount={false}
|
destroyOnUnmount={false}
|
||||||
forceUnregisterOnUnmount={true}
|
forceUnregisterOnUnmount={false}
|
||||||
shouldAsyncValidate={shouldAsyncValidate}
|
shouldAsyncValidate={shouldAsyncValidate}
|
||||||
asyncValidate={handleAsyncValidation}
|
asyncValidate={handleAsyncValidate}
|
||||||
onSubmit={handleAddAffinityRules}
|
onSubmit={handleCreateAffinityRules}
|
||||||
>
|
>
|
||||||
{props =>
|
{formProps =>
|
||||||
expanded && addOpen ? (
|
expanded && addOpen ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<KeyValue
|
<KeyValue
|
||||||
{...props}
|
{...formProps}
|
||||||
method="create"
|
method="create"
|
||||||
input={props => <Rule {...rule} {...props} />}
|
input={inputProps => (
|
||||||
|
<Rule
|
||||||
|
{...creatingRule}
|
||||||
|
{...inputProps}
|
||||||
|
valid={formProps.valid}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
type="an affinity rule"
|
type="an affinity rule"
|
||||||
expanded
|
expanded
|
||||||
noRemove
|
noRemove
|
||||||
@ -131,7 +138,7 @@ export const Affinity = ({
|
|||||||
</ReduxForm>
|
</ReduxForm>
|
||||||
{expanded ? (
|
{expanded ? (
|
||||||
<Margin top={2} bottom={4}>
|
<Margin top={2} bottom={4}>
|
||||||
{!addOpen && affinityRules.length === 0 ? (
|
{!addOpen && !exitingRule ? (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleChangeAddOpen(true)}
|
onClick={() => handleChangeAddOpen(true)}
|
||||||
@ -141,7 +148,7 @@ export const Affinity = ({
|
|||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
</Margin>
|
</Margin>
|
||||||
) : proceeded ? (
|
) : exitingRule ? (
|
||||||
<Margin top={2} bottom={4}>
|
<Margin top={2} bottom={4}>
|
||||||
<Button type="button" onClick={handleEdit} secondary>
|
<Button type="button" onClick={handleEdit} secondary>
|
||||||
Edit
|
Edit
|
||||||
@ -149,61 +156,45 @@ export const Affinity = ({
|
|||||||
</Margin>
|
</Margin>
|
||||||
) : null}
|
) : null}
|
||||||
<Margin bottom={7}>
|
<Margin bottom={7}>
|
||||||
{expanded || proceeded ? <Divider height={remcalc(1)} /> : null}
|
{expanded ? <Divider height={remcalc(1)} /> : null}
|
||||||
</Margin>
|
</Margin>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
connect(({ values, form }, ownProps) => {
|
connect(({ values, form }, ownProps) => {
|
||||||
const proceeded = get(values, 'create-instance-affinity-proceeded', false);
|
const editingRule = get(form, `${FORM_NAME_EDIT}.values`, null);
|
||||||
|
const creatingRule = get(form, `${FORM_NAME_CREATE}.values`, null);
|
||||||
|
const exitingRule = get(values, 'create-instance-affinity', null);
|
||||||
|
|
||||||
const addOpen = get(values, 'create-instance-affinity-add-open', false);
|
const addOpen = get(values, 'create-instance-affinity-add-open', false);
|
||||||
const affinityRules = get(values, 'create-instance-affinity', []);
|
const editOpen = get(values, 'create-instance-affinity-edit-open', false);
|
||||||
const rule = get(form, `${FORM_NAME_CREATE}.values`, {});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
proceeded: proceeded || affinityRules.length,
|
|
||||||
addOpen,
|
addOpen,
|
||||||
affinityRules,
|
editOpen,
|
||||||
rule
|
creatingRule,
|
||||||
|
editingRule,
|
||||||
|
exitingRule
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
connect(null, (dispatch, { affinityRules = [], rule, history }) => ({
|
connect(null, (dispatch, { history }) => ({
|
||||||
shouldAsyncValidate: ({ trigger }) => trigger === 'change',
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
handleAsyncValidation: async rule => {
|
return trigger === 'submit';
|
||||||
const validName = /^[a-zA-Z_.-]{1,16}$/.test(rule['rule-instance-name']);
|
|
||||||
const validKey = /^[a-zA-Z_.-]{1,16}$/.test(
|
|
||||||
rule['rule-instance-tag-key']
|
|
||||||
);
|
|
||||||
const validValue = /^[a-zA-Z_.-]{1,16}$/.test(
|
|
||||||
rule['rule-instance-tag-value']
|
|
||||||
);
|
|
||||||
|
|
||||||
if (validName && validKey && validValue) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-throw-literal
|
|
||||||
throw {
|
|
||||||
'rule-instance-name': fieldError,
|
|
||||||
'rule-instance-tag-key': fieldError,
|
|
||||||
'rule-instance-tag-value': fieldError
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
handleAsyncValidate: validateRule,
|
||||||
handleEdit: () => {
|
handleEdit: () => {
|
||||||
return history.push(`/~create/affinity${history.location.search}`);
|
return history.push(`/~create/affinity${history.location.search}`);
|
||||||
},
|
},
|
||||||
handleAddAffinityRules: ({ ...rule }) => {
|
handleCreateAffinityRules: value => {
|
||||||
const toggleToClosed = set({
|
const toggleToClosed = set({
|
||||||
name: `create-instance-affinity-add-open`,
|
name: 'create-instance-affinity-add-open',
|
||||||
value: false
|
value: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const appendAffinityRule = set({
|
const appendAffinityRule = set({
|
||||||
name: `create-instance-affinity`,
|
name: 'create-instance-affinity',
|
||||||
value: affinityRules.concat([
|
value
|
||||||
{ ...RULE_DEFAULTS, ...rule, expanded: false }
|
|
||||||
])
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return dispatch([
|
return dispatch([
|
||||||
@ -212,53 +203,32 @@ export default compose(
|
|||||||
appendAffinityRule
|
appendAffinityRule
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
handleUpdateAffinityRule: (index, newAffinityRule) => {
|
handleUpdateAffinityRule: value => {
|
||||||
affinityRules[index] = {
|
|
||||||
...newAffinityRule,
|
|
||||||
expanded: false
|
|
||||||
};
|
|
||||||
|
|
||||||
return dispatch([
|
return dispatch([
|
||||||
destroy(FORM_NAME_EDIT(index)),
|
destroy(FORM_NAME_EDIT),
|
||||||
set({ name: `create-instance-affinity`, value: affinityRules.slice() })
|
set({ name: 'create-instance-affinity', value })
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
handleChangeAddOpen: value => {
|
handleChangeAddOpen: value => {
|
||||||
return dispatch([
|
return dispatch([
|
||||||
reset(FORM_NAME_CREATE),
|
reset(FORM_NAME_CREATE),
|
||||||
set({ name: `create-instance-affinity-add-open`, value })
|
set({ name: 'create-instance-affinity-add-open', value })
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
handleToggleExpanded: index => {
|
handleToggleExpanded: value => {
|
||||||
affinityRules[index] = {
|
|
||||||
...affinityRules[index],
|
|
||||||
expanded: !affinityRules[index].expanded
|
|
||||||
};
|
|
||||||
|
|
||||||
return dispatch(
|
return dispatch(
|
||||||
set({
|
set({ name: 'create-instance-affinity-edit-open', value })
|
||||||
name: `create-instance-affinity`,
|
|
||||||
value: affinityRules.slice()
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
handleCancelEdit: index => {
|
handleCancelEdit: () => {
|
||||||
affinityRules[index] = {
|
|
||||||
...affinityRules[index],
|
|
||||||
expanded: false
|
|
||||||
};
|
|
||||||
|
|
||||||
return dispatch([
|
return dispatch([
|
||||||
reset(FORM_NAME_EDIT(index)),
|
set({ name: 'create-instance-affinity-edit-open', value: false })
|
||||||
set({ name: `create-instance-affinity`, value: affinityRules.slice() })
|
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
handleRemoveAffinityRule: index => {
|
handleRemoveAffinityRule: () => {
|
||||||
affinityRules.splice(index, 1);
|
|
||||||
|
|
||||||
return dispatch([
|
return dispatch([
|
||||||
destroy(FORM_NAME_EDIT(index)),
|
destroy(FORM_NAME_EDIT),
|
||||||
set({ name: `create-instance-affinity`, value: affinityRules.slice() })
|
set({ name: 'create-instance-affinity', value: null })
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -6,7 +6,6 @@ import { connect } from 'react-redux';
|
|||||||
import get from 'lodash.get';
|
import get from 'lodash.get';
|
||||||
import { Margin } from 'styled-components-spacing';
|
import { Margin } from 'styled-components-spacing';
|
||||||
import { set } from 'react-redux-values';
|
import { set } from 'react-redux-values';
|
||||||
import punycode from 'punycode';
|
|
||||||
|
|
||||||
import { CnsIcon, H3, Button } from 'joyent-ui-toolkit';
|
import { CnsIcon, H3, Button } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
@ -14,7 +13,7 @@ import Title from '@components/create-instance/title';
|
|||||||
import Cns, { Footer, AddServiceForm } from '@components/cns';
|
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 { fieldError } from '@root/constants';
|
import { addCnsService as validateServiceName } from '@state/validators';
|
||||||
|
|
||||||
const CNS_FORM = 'create-instance-cns';
|
const CNS_FORM = 'create-instance-cns';
|
||||||
|
|
||||||
@ -175,32 +174,18 @@ export default compose(
|
|||||||
dispatch(set({ name: `${CNS_FORM}-proceeded`, value: true }));
|
dispatch(set({ name: `${CNS_FORM}-proceeded`, value: true }));
|
||||||
history.push(`/~create/cns${history.location.search}`);
|
history.push(`/~create/cns${history.location.search}`);
|
||||||
},
|
},
|
||||||
shouldAsyncValidate: ({ trigger }) => trigger === 'change',
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
handleAsyncValidate: async ({ name = '', value = '' }) => {
|
return trigger === 'submit';
|
||||||
const isNameValid = /^[a-zA-Z_.-]{1,16}$/.test(name);
|
|
||||||
const isValueValid = /^[a-zA-Z_.-]{1,16}$/.test(value);
|
|
||||||
|
|
||||||
if (isNameValid && isValueValid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw {
|
|
||||||
name: isNameValid ? null : fieldError,
|
|
||||||
value: isValueValid ? null : fieldError
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
handleAsyncValidate: validateServiceName,
|
||||||
handleToggleCnsEnabled: ({ target }) =>
|
handleToggleCnsEnabled: ({ target }) =>
|
||||||
dispatch(set({ name: `${CNS_FORM}-enabled`, value: !cnsEnabled })),
|
dispatch(set({ name: `${CNS_FORM}-enabled`, value: !cnsEnabled })),
|
||||||
handleAddService: ({ name }) => {
|
handleAddService: ({ name }) => {
|
||||||
const serviceName = punycode
|
|
||||||
.encode(name.toLowerCase().replace(/\s/g, '-'))
|
|
||||||
.replace(/-$/, '');
|
|
||||||
|
|
||||||
dispatch([
|
dispatch([
|
||||||
destroy(`${CNS_FORM}-new-service`),
|
destroy(`${CNS_FORM}-new-service`),
|
||||||
set({
|
set({
|
||||||
name: `${CNS_FORM}-services`,
|
name: `${CNS_FORM}-services`,
|
||||||
value: serviceNames.concat(serviceName)
|
value: serviceNames.concat(name)
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
@ -240,15 +240,8 @@ export default compose(
|
|||||||
handleSubmit: async () => {
|
handleSubmit: async () => {
|
||||||
const _affinity = affinity
|
const _affinity = affinity
|
||||||
.map(aff => ({
|
.map(aff => ({
|
||||||
conditional: aff['rule-instance-conditional'],
|
...aff,
|
||||||
placement: aff['rule-instance-placement'],
|
value: aff.type === 'name' ? aff.name : aff.value
|
||||||
identity: aff['rule-type'],
|
|
||||||
key: aff['rule-instance-tag-key'],
|
|
||||||
pattern: aff['rule-instance-tag-value-pattern'],
|
|
||||||
value:
|
|
||||||
aff['rule-type'] === 'name'
|
|
||||||
? aff['rule-instance-name']
|
|
||||||
: aff['rule-instance-tag-value']
|
|
||||||
}))
|
}))
|
||||||
.map(({ conditional, placement, identity, key, pattern, value }) => {
|
.map(({ conditional, placement, identity, key, pattern, value }) => {
|
||||||
const type = constantCase(
|
const type = constantCase(
|
||||||
|
@ -13,6 +13,7 @@ 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';
|
||||||
|
|
||||||
const FORM_NAME_CREATE = 'CREATE-INSTANCE-METADATA-ADD';
|
const FORM_NAME_CREATE = 'CREATE-INSTANCE-METADATA-ADD';
|
||||||
const FORM_NAME_EDIT = i => `CREATE-INSTANCE-METADATA-EDIT-${i}`;
|
const FORM_NAME_EDIT = i => `CREATE-INSTANCE-METADATA-EDIT-${i}`;
|
||||||
@ -179,19 +180,7 @@ export default compose(
|
|||||||
shouldAsyncValidate: ({ trigger }) => {
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
return trigger === 'submit';
|
return trigger === 'submit';
|
||||||
},
|
},
|
||||||
asyncValidate: async ({ name = '', value = '' }) => {
|
handleAsyncValidate: validateMetadata,
|
||||||
const isNameInvalid = name.length === 0;
|
|
||||||
const isValueInvalid = value.length === 0;
|
|
||||||
|
|
||||||
if (!isNameInvalid && !isValueInvalid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw {
|
|
||||||
name: isNameInvalid,
|
|
||||||
value: isValueInvalid
|
|
||||||
};
|
|
||||||
},
|
|
||||||
handleAddMetadata: value => {
|
handleAddMetadata: value => {
|
||||||
const toggleToClosed = set({
|
const toggleToClosed = set({
|
||||||
name: `create-instance-metadata-add-open`,
|
name: `create-instance-metadata-add-open`,
|
||||||
|
@ -7,18 +7,15 @@ import { change } from 'redux-form';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import intercept from 'apr-intercept';
|
import intercept from 'apr-intercept';
|
||||||
import get from 'lodash.get';
|
import get from 'lodash.get';
|
||||||
import punycode from 'punycode';
|
|
||||||
|
|
||||||
import { NameIcon, H3, Button } from 'joyent-ui-toolkit';
|
import { NameIcon, H3, Button } from 'joyent-ui-toolkit';
|
||||||
|
|
||||||
import Title from '@components/create-instance/title';
|
import Title from '@components/create-instance/title';
|
||||||
import Name from '@components/create-instance/name';
|
import Name from '@components/create-instance/name';
|
||||||
import Description from '@components/description';
|
import Description from '@components/description';
|
||||||
import GetInstance from '@graphql/get-instance-small.gql';
|
import { instanceName as validateName } from '@state/validators';
|
||||||
import GetRandomName from '@graphql/get-random-name.gql';
|
|
||||||
import createClient from '@state/apollo-client';
|
import createClient from '@state/apollo-client';
|
||||||
import parseError from '@state/parse-error';
|
import GetRandomName from '@graphql/get-random-name.gql';
|
||||||
import { fieldError } from '@root/constants';
|
|
||||||
|
|
||||||
const FORM_NAME = 'create-instance-name';
|
const FORM_NAME = 'create-instance-name';
|
||||||
|
|
||||||
@ -28,7 +25,7 @@ const NameContainer = ({
|
|||||||
name,
|
name,
|
||||||
placeholderName,
|
placeholderName,
|
||||||
randomizing,
|
randomizing,
|
||||||
handleAsyncValidation,
|
handleAsyncValidate,
|
||||||
shouldAsyncValidate,
|
shouldAsyncValidate,
|
||||||
handleNext,
|
handleNext,
|
||||||
handleRandomize,
|
handleRandomize,
|
||||||
@ -54,7 +51,7 @@ const NameContainer = ({
|
|||||||
destroyOnUnmount={false}
|
destroyOnUnmount={false}
|
||||||
forceUnregisterOnUnmount={true}
|
forceUnregisterOnUnmount={true}
|
||||||
onSubmit={handleNext}
|
onSubmit={handleNext}
|
||||||
asyncValidate={handleAsyncValidation}
|
asyncValidate={handleAsyncValidate}
|
||||||
shouldAsyncValidate={shouldAsyncValidate}
|
shouldAsyncValidate={shouldAsyncValidate}
|
||||||
>
|
>
|
||||||
{props =>
|
{props =>
|
||||||
@ -127,49 +124,10 @@ export default compose(
|
|||||||
handleEdit: () => {
|
handleEdit: () => {
|
||||||
history.push(`/~create/name${history.location.search}`);
|
history.push(`/~create/name${history.location.search}`);
|
||||||
},
|
},
|
||||||
shouldAsyncValidate: ({ trigger }) => trigger === 'change',
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
handleAsyncValidation: async ({ name }) => {
|
return trigger === 'change';
|
||||||
const sanitized = punycode.encode(name).replace(/-$/, '');
|
|
||||||
|
|
||||||
if (sanitized !== name) {
|
|
||||||
// eslint-disable-next-line no-throw-literal
|
|
||||||
throw {
|
|
||||||
name: fieldError
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!/^[a-zA-Z0-9][a-zA-Z0-9\\_\\.\\-]*$/.test(name)) {
|
|
||||||
// eslint-disable-next-line no-throw-literal
|
|
||||||
throw {
|
|
||||||
name: fieldError
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const [err, res] = await intercept(
|
|
||||||
createClient().query({
|
|
||||||
fetchPolicy: 'network-only',
|
|
||||||
query: GetInstance,
|
|
||||||
variables: { name }
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
// eslint-disable-next-line no-throw-literal
|
|
||||||
throw {
|
|
||||||
name: parseError(err)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data } = res;
|
|
||||||
const { machines = [] } = data;
|
|
||||||
|
|
||||||
if (machines.length) {
|
|
||||||
// eslint-disable-next-line no-throw-literal
|
|
||||||
throw {
|
|
||||||
name: `${name} already exists`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
handleAsyncValidate: validateName,
|
||||||
handleRandomize: async () => {
|
handleRandomize: async () => {
|
||||||
dispatch(
|
dispatch(
|
||||||
set({ name: 'create-instance-name-randomizing', value: true })
|
set({ name: 'create-instance-name-randomizing', value: true })
|
||||||
|
@ -20,7 +20,7 @@ import {
|
|||||||
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 Tag from '@components/tags';
|
import Tag from '@components/tags';
|
||||||
import { fieldError } from '@root/constants';
|
import { addTag as validateTag } from '@state/validators';
|
||||||
|
|
||||||
const FORM_NAME_CREATE = 'CREATE-INSTANCE-TAGS-ADD';
|
const FORM_NAME_CREATE = 'CREATE-INSTANCE-TAGS-ADD';
|
||||||
const FORM_NAME_EDIT = i => `CREATE-INSTANCE-TAGS-EDIT-${i}`;
|
const FORM_NAME_EDIT = i => `CREATE-INSTANCE-TAGS-EDIT-${i}`;
|
||||||
@ -87,9 +87,9 @@ export const Tags = ({
|
|||||||
form={FORM_NAME_CREATE}
|
form={FORM_NAME_CREATE}
|
||||||
destroyOnUnmount={false}
|
destroyOnUnmount={false}
|
||||||
forceUnregisterOnUnmount={true}
|
forceUnregisterOnUnmount={true}
|
||||||
onSubmit={handleAddTag}
|
|
||||||
shouldAsyncValidate={shouldAsyncValidate}
|
shouldAsyncValidate={shouldAsyncValidate}
|
||||||
asyncValidate={handleAsyncValidate}
|
asyncValidate={handleAsyncValidate}
|
||||||
|
onSubmit={handleAddTag}
|
||||||
>
|
>
|
||||||
{props =>
|
{props =>
|
||||||
expanded && addOpen ? (
|
expanded && addOpen ? (
|
||||||
@ -151,20 +151,10 @@ export default compose(
|
|||||||
dispatch(set({ name: 'create-instance-tags-proceeded', value: true }));
|
dispatch(set({ name: 'create-instance-tags-proceeded', value: true }));
|
||||||
return history.push(`/~create/tags${history.location.search}`);
|
return history.push(`/~create/tags${history.location.search}`);
|
||||||
},
|
},
|
||||||
shouldAsyncValidate: ({ trigger }) => trigger === 'submit',
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
handleAsyncValidate: async ({ name = '', value = '' }) => {
|
return trigger === 'submit';
|
||||||
const isNameValid = /^[a-zA-Z_.-]{1,16}$/.test(name);
|
|
||||||
const isValueValid = /^[a-zA-Z_.-]{1,16}$/.test(value);
|
|
||||||
|
|
||||||
if (isNameValid && isValueValid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw {
|
|
||||||
name: isNameValid ? null : fieldError,
|
|
||||||
value: isValueValid ? null : fieldError
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
handleAsyncValidate: validateTag,
|
||||||
handleAddTag: value => {
|
handleAddTag: value => {
|
||||||
const toggleToClosed = set({
|
const toggleToClosed = set({
|
||||||
name: `create-instance-tags-add-open`,
|
name: `create-instance-tags-add-open`,
|
||||||
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
@ -26,7 +26,7 @@ import DeleteTag from '@graphql/delete-tag.gql';
|
|||||||
import UpdateTags from '@graphql/update-tags.gql';
|
import UpdateTags from '@graphql/update-tags.gql';
|
||||||
import GetTags from '@graphql/list-tags.gql';
|
import GetTags from '@graphql/list-tags.gql';
|
||||||
import parseError from '@state/parse-error';
|
import parseError from '@state/parse-error';
|
||||||
import { fieldError } from '@root/constants';
|
import { addCnsService as validateServiceName } from '@state/validators';
|
||||||
|
|
||||||
const FORM_NAME = 'cns-new-service';
|
const FORM_NAME = 'cns-new-service';
|
||||||
|
|
||||||
@ -258,18 +258,10 @@ export default compose(
|
|||||||
|
|
||||||
return refetch();
|
return refetch();
|
||||||
},
|
},
|
||||||
shouldAsyncValidate: ({ trigger }) => trigger === 'change',
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
handleAsyncValidate: async ({ name }) => {
|
return trigger === 'change';
|
||||||
const isNameValid = /^[a-zA-Z_.-]{1,16}$/.test(name);
|
|
||||||
|
|
||||||
if (isNameValid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw {
|
|
||||||
name: fieldError
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
handleAsyncValidate: validateServiceName,
|
||||||
handleRemoveService: async (name, services) => {
|
handleRemoveService: async (name, services) => {
|
||||||
const value = services.filter(svc => name !== svc);
|
const value = services.filter(svc => name !== svc);
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import DeleteMetadata from '@graphql/delete-metadata.gql';
|
|||||||
import parseError from '@state/parse-error';
|
import parseError from '@state/parse-error';
|
||||||
import ToolbarForm from '@components/instances/toolbar';
|
import ToolbarForm from '@components/instances/toolbar';
|
||||||
import Confirm from '@state/confirm';
|
import Confirm from '@state/confirm';
|
||||||
|
import { addMetadata as validateMetadata } from '@state/validators';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AddForm as MetadataAddForm,
|
AddForm as MetadataAddForm,
|
||||||
@ -43,14 +44,14 @@ export const Metadata = ({
|
|||||||
addOpen,
|
addOpen,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
|
shouldAsyncValidate,
|
||||||
|
handleAsyncValidate,
|
||||||
handleToggleAddOpen,
|
handleToggleAddOpen,
|
||||||
handleUpdateExpanded,
|
handleUpdateExpanded,
|
||||||
handleCancel,
|
handleCancel,
|
||||||
handleCreate,
|
handleCreate,
|
||||||
handleUpdate,
|
handleUpdate,
|
||||||
handleRemove,
|
handleRemove
|
||||||
shouldAsyncValidate,
|
|
||||||
asyncValidate
|
|
||||||
}) => {
|
}) => {
|
||||||
const _loading = !(loading && !metadata.length) ? null : <StatusLoader />;
|
const _loading = !(loading && !metadata.length) ? null : <StatusLoader />;
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ export const Metadata = ({
|
|||||||
form={ADD_FORM_NAME}
|
form={ADD_FORM_NAME}
|
||||||
onSubmit={handleCreate}
|
onSubmit={handleCreate}
|
||||||
shouldAsyncValidate={shouldAsyncValidate}
|
shouldAsyncValidate={shouldAsyncValidate}
|
||||||
asyncValidate={asyncValidate}
|
asyncValidate={handleAsyncValidate}
|
||||||
>
|
>
|
||||||
{props => (
|
{props => (
|
||||||
<MetadataAddForm
|
<MetadataAddForm
|
||||||
@ -94,9 +95,9 @@ export const Metadata = ({
|
|||||||
key={form}
|
key={form}
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
destroyOnUnmount={false}
|
destroyOnUnmount={false}
|
||||||
onSubmit={handleUpdate}
|
|
||||||
shouldAsyncValidate={shouldAsyncValidate}
|
shouldAsyncValidate={shouldAsyncValidate}
|
||||||
asyncValidate={asyncValidate}
|
asyncValidate={handleAsyncValidate}
|
||||||
|
onSubmit={handleUpdate}
|
||||||
>
|
>
|
||||||
{props => (
|
{props => (
|
||||||
<MetadataEditForm
|
<MetadataEditForm
|
||||||
@ -239,19 +240,7 @@ export default compose(
|
|||||||
shouldAsyncValidate: ({ trigger }) => {
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
return trigger === 'submit';
|
return trigger === 'submit';
|
||||||
},
|
},
|
||||||
asyncValidate: async ({ name = '', value = '' }) => {
|
handleAsyncValidate: validateMetadata,
|
||||||
const isNameInvalid = name.length === 0;
|
|
||||||
const isValueInvalid = value.length === 0;
|
|
||||||
|
|
||||||
if (!isNameInvalid && !isValueInvalid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw {
|
|
||||||
name: isNameInvalid,
|
|
||||||
value: isValueInvalid
|
|
||||||
};
|
|
||||||
},
|
|
||||||
handleCreate: async ({ name, value }) => {
|
handleCreate: async ({ name, value }) => {
|
||||||
// call mutation
|
// call mutation
|
||||||
const [err] = await intercept(
|
const [err] = await intercept(
|
||||||
|
@ -32,9 +32,9 @@ import RemoveSnapshot from '@graphql/remove-snapshot.gql';
|
|||||||
import CreateSnapshotMutation from '@graphql/create-snapshot.gql';
|
import CreateSnapshotMutation from '@graphql/create-snapshot.gql';
|
||||||
import ToolbarForm from '@components/instances/toolbar';
|
import ToolbarForm from '@components/instances/toolbar';
|
||||||
import SnapshotsListActions from '@components/instances/footer';
|
import SnapshotsListActions from '@components/instances/footer';
|
||||||
|
import { addSnapshot as validateSnapshot } from '@state/validators';
|
||||||
import parseError from '@state/parse-error';
|
import parseError from '@state/parse-error';
|
||||||
import Confirm from '@state/confirm';
|
import Confirm from '@state/confirm';
|
||||||
import { fieldError } from '@root/constants';
|
|
||||||
|
|
||||||
const MENU_FORM_NAME = 'snapshot-list-menu';
|
const MENU_FORM_NAME = 'snapshot-list-menu';
|
||||||
const TABLE_FORM_NAME = 'snapshot-list-table';
|
const TABLE_FORM_NAME = 'snapshot-list-table';
|
||||||
@ -89,14 +89,12 @@ const Snapshots = ({
|
|||||||
asyncValidate={handleAsyncValidate}
|
asyncValidate={handleAsyncValidate}
|
||||||
onSubmit={handleCreateSnapshot}
|
onSubmit={handleCreateSnapshot}
|
||||||
>
|
>
|
||||||
{props => {
|
{props => (
|
||||||
return (
|
|
||||||
<SnapshotAddForm
|
<SnapshotAddForm
|
||||||
{...props}
|
{...props}
|
||||||
onCancel={() => toggleCreateSnapshotOpen(false)}
|
onCancel={() => toggleCreateSnapshotOpen(false)}
|
||||||
/>
|
/>
|
||||||
);
|
)}
|
||||||
}}
|
|
||||||
</ReduxForm>
|
</ReduxForm>
|
||||||
</Margin>
|
</Margin>
|
||||||
) : null;
|
) : null;
|
||||||
@ -252,11 +250,29 @@ export default compose(
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
(dispatch, ownProps) => {
|
(dispatch, ownProps) => {
|
||||||
const { instance, createSnapshot, refetch } = ownProps;
|
const { instance, snapshots, createSnapshot, refetch } = ownProps;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
|
return trigger === 'submit';
|
||||||
|
},
|
||||||
|
handleAsyncValidate: async ({ name }) => {
|
||||||
|
const [err] = await intercept(validateSnapshot({ name }));
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
const snapshot = find(snapshots, ['name', name]);
|
||||||
|
if (snapshot) {
|
||||||
|
// eslint-disable-next-line no-throw-literal
|
||||||
|
throw {
|
||||||
|
name: `${name} already exists`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
handleSortBy: (newSortBy, sortOrder) => {
|
handleSortBy: (newSortBy, sortOrder) => {
|
||||||
dispatch([
|
return dispatch([
|
||||||
set({
|
set({
|
||||||
name: `snapshots-list-sort-order`,
|
name: `snapshots-list-sort-order`,
|
||||||
value: sortOrder === 'desc' ? 'asc' : 'desc'
|
value: sortOrder === 'desc' ? 'asc' : 'desc'
|
||||||
@ -267,25 +283,14 @@ export default compose(
|
|||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
shouldAsyncValidate: ({ trigger }) => trigger === 'change',
|
toggleCreateSnapshotOpen: value => {
|
||||||
handleAsyncValidate: async ({ name }) => {
|
return dispatch(
|
||||||
const isNameValid = /^[a-zA-Z_.-]{1,16}$/.test(name);
|
|
||||||
|
|
||||||
if (isNameValid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw {
|
|
||||||
name: fieldError
|
|
||||||
};
|
|
||||||
},
|
|
||||||
toggleCreateSnapshotOpen: value =>
|
|
||||||
dispatch(
|
|
||||||
set({
|
set({
|
||||||
name: `snapshots-create-open`,
|
name: `snapshots-create-open`,
|
||||||
value
|
value
|
||||||
})
|
})
|
||||||
),
|
);
|
||||||
|
},
|
||||||
toggleSelectAll: ({ selected = [], snapshots = [] }) => () => {
|
toggleSelectAll: ({ selected = [], snapshots = [] }) => () => {
|
||||||
const same = selected.length === snapshots.length;
|
const same = selected.length === snapshots.length;
|
||||||
const hasSelected = selected.length > 0;
|
const hasSelected = selected.length > 0;
|
||||||
@ -311,7 +316,6 @@ export default compose(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleCreateSnapshot: async ({ name }) => {
|
handleCreateSnapshot: async ({ name }) => {
|
||||||
const [err] = await intercept(
|
const [err] = await intercept(
|
||||||
createSnapshot({
|
createSnapshot({
|
||||||
@ -342,7 +346,6 @@ export default compose(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleAction: async ({ name, selected = [] }) => {
|
handleAction: async ({ name, selected = [] }) => {
|
||||||
// eslint-disable-next-line no-alert
|
// eslint-disable-next-line no-alert
|
||||||
if (
|
if (
|
||||||
|
@ -31,8 +31,8 @@ import GetTags from '@graphql/list-tags.gql';
|
|||||||
import UpdateTags from '@graphql/update-tags.gql';
|
import UpdateTags from '@graphql/update-tags.gql';
|
||||||
import DeleteTag from '@graphql/delete-tag.gql';
|
import DeleteTag from '@graphql/delete-tag.gql';
|
||||||
import parseError from '@state/parse-error';
|
import parseError from '@state/parse-error';
|
||||||
|
import { addTag as validateTag } from '@state/validators';
|
||||||
import Confirm from '@state/confirm';
|
import Confirm from '@state/confirm';
|
||||||
import { fieldError } from '@root/constants';
|
|
||||||
|
|
||||||
const MENU_FORM_NAME = 'instance-tags-list-menu';
|
const MENU_FORM_NAME = 'instance-tags-list-menu';
|
||||||
const ADD_FORM_NAME = 'instance-tags-add-new';
|
const ADD_FORM_NAME = 'instance-tags-add-new';
|
||||||
@ -58,10 +58,10 @@ export const Tags = ({
|
|||||||
const _add = addOpen ? (
|
const _add = addOpen ? (
|
||||||
<ReduxForm
|
<ReduxForm
|
||||||
form={ADD_FORM_NAME}
|
form={ADD_FORM_NAME}
|
||||||
onSubmit={handleCreate}
|
|
||||||
onCancel={() => handleToggleAddOpen(false)}
|
|
||||||
shouldAsyncValidate={shouldAsyncValidate}
|
shouldAsyncValidate={shouldAsyncValidate}
|
||||||
asyncValidate={handleAsyncValidate}
|
asyncValidate={handleAsyncValidate}
|
||||||
|
onSubmit={handleCreate}
|
||||||
|
onCancel={() => handleToggleAddOpen(false)}
|
||||||
>
|
>
|
||||||
{TagsAddForm}
|
{TagsAddForm}
|
||||||
</ReduxForm>
|
</ReduxForm>
|
||||||
@ -208,26 +208,16 @@ export default compose(
|
|||||||
},
|
},
|
||||||
(dispatch, ownProps) => {
|
(dispatch, ownProps) => {
|
||||||
return {
|
return {
|
||||||
|
shouldAsyncValidate: ({ trigger }) => {
|
||||||
|
return trigger === 'submit';
|
||||||
|
},
|
||||||
|
handleAsyncValidate: validateTag,
|
||||||
handleToggleAddOpen: value => {
|
handleToggleAddOpen: value => {
|
||||||
return dispatch(set({ name: `add-tags-open`, value }));
|
return dispatch(set({ name: `add-tags-open`, value }));
|
||||||
},
|
},
|
||||||
handleToggleEditing: value => {
|
handleToggleEditing: value => {
|
||||||
return dispatch(set({ name: `editing-tag`, value }));
|
return dispatch(set({ name: `editing-tag`, value }));
|
||||||
},
|
},
|
||||||
shouldAsyncValidate: ({ trigger }) => trigger === 'submit',
|
|
||||||
handleAsyncValidate: async ({ name = '', value = '' }) => {
|
|
||||||
const isNameValid = /^[a-zA-Z_.-]{1,16}$/.test(name);
|
|
||||||
const isValueValid = /^[a-zA-Z_.-]{1,16}$/.test(value);
|
|
||||||
|
|
||||||
if (isNameValid && isValueValid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw {
|
|
||||||
name: isNameValid ? null : fieldError,
|
|
||||||
value: isValueValid ? null : fieldError
|
|
||||||
};
|
|
||||||
},
|
|
||||||
handleEdit: async ({ name, value }, _, { form, initialValues }) => {
|
handleEdit: async ({ name, value }, _, { form, initialValues }) => {
|
||||||
const { instance, deleteTag, updateTags, refetch } = ownProps;
|
const { instance, deleteTag, updateTags, refetch } = ownProps;
|
||||||
|
|
||||||
|
6
packages/my-joy-instances/src/graphql/get-snapshot.gql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
query snapshot($machine: ID!, $name: String!) {
|
||||||
|
snapshot(machine: $machine, name: $name) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
112
packages/my-joy-instances/src/state/validators.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import intercept from 'apr-intercept';
|
||||||
|
import keys from 'lodash.keys';
|
||||||
|
import reduce from 'apr-reduce';
|
||||||
|
import assign from 'lodash.assign';
|
||||||
|
import yup from 'yup';
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
const validateField = async (field, value) => {
|
||||||
|
const [err] = await intercept(field.validate(value));
|
||||||
|
return err ? err.errors.shift() : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateSchema = async (schema, value) => {
|
||||||
|
const errors = await reduce(
|
||||||
|
keys(schema),
|
||||||
|
async (errors, name) =>
|
||||||
|
assign(errors, {
|
||||||
|
[name]: await validateField(schema[name], value[name])
|
||||||
|
}),
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
throw errors;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
const matches = {
|
||||||
|
nameStart: /^[a-zA-Z]|\d/,
|
||||||
|
nameBody: /^([a-zA-Z]|\d|\.|_|-)+$/
|
||||||
|
};
|
||||||
|
|
||||||
|
const msgs = {
|
||||||
|
required: prefix => `${prefix} must be defined.`,
|
||||||
|
nameStart: prefix => `${prefix} can only start with letters and numbers.`,
|
||||||
|
nameBody: prefix =>
|
||||||
|
`${prefix} cannot contain spaces and can only contain letters, numbers, periods (.), underscores (_), and hyphens (-).`
|
||||||
|
};
|
||||||
|
|
||||||
|
const Schemas = {
|
||||||
|
tag: {
|
||||||
|
name: yup
|
||||||
|
.string()
|
||||||
|
.required(msgs.required('Key'))
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Key'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Key')),
|
||||||
|
value: yup
|
||||||
|
.string()
|
||||||
|
.required(msgs.required('Value'))
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Value'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Value'))
|
||||||
|
},
|
||||||
|
cns: {
|
||||||
|
name: yup
|
||||||
|
.string()
|
||||||
|
.required(msgs.required('Service name'))
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Service name'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Service name'))
|
||||||
|
},
|
||||||
|
affinityRule: {
|
||||||
|
key: yup
|
||||||
|
.string()
|
||||||
|
.required(msgs.required('Key'))
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Key'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Key')),
|
||||||
|
value: yup
|
||||||
|
.string()
|
||||||
|
.required(msgs.required('Value'))
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Value'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Value'))
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
name: yup
|
||||||
|
.string()
|
||||||
|
.required(msgs.required('Key'))
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Key'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Key')),
|
||||||
|
value: yup.string().required(msgs.required('Value'))
|
||||||
|
},
|
||||||
|
instanceName: {
|
||||||
|
name: yup
|
||||||
|
.string()
|
||||||
|
.notRequired()
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Instance name'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Instance Name'))
|
||||||
|
},
|
||||||
|
snapshot: {
|
||||||
|
name: yup
|
||||||
|
.string()
|
||||||
|
.required()
|
||||||
|
.matches(matches.nameStart, msgs.nameStart('Snapshot name'))
|
||||||
|
.matches(matches.nameBody, msgs.nameBody('Snapshot Name'))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
export const addTag = tag => validateSchema(Schemas.tag, tag);
|
||||||
|
export const addCnsService = service => validateSchema(Schemas.cns, service);
|
||||||
|
export const addAffinityRule = aff => validateSchema(Schemas.affinityRule, aff);
|
||||||
|
|
||||||
|
export const addSnapshot = snapshot =>
|
||||||
|
validateSchema(Schemas.snapshot, snapshot);
|
||||||
|
|
||||||
|
export const addMetadata = metadata =>
|
||||||
|
validateSchema(Schemas.metadata, metadata);
|
||||||
|
|
||||||
|
export const instanceName = ({ name }) =>
|
||||||
|
!name ? null : validateSchema(Schemas.instanceName, { name });
|
||||||
|
|
||||||
|
export const editMetadata = addMetadata;
|
@ -9,7 +9,7 @@
|
|||||||
"build:lib": "echo 0",
|
"build:lib": "echo 0",
|
||||||
"build:bundle": "NODE_ENV=production redrun build",
|
"build:bundle": "NODE_ENV=production redrun build",
|
||||||
"prepublish": "NODE_ENV=production redrun build",
|
"prepublish": "NODE_ENV=production redrun build",
|
||||||
"lint": "redrun lint:ci -- -- --fix",
|
"lint": "redrun lint:ci -- --fix",
|
||||||
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
||||||
"test": "echo 0",
|
"test": "echo 0",
|
||||||
"test:ci": "redrun test",
|
"test:ci": "redrun test",
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
"build:lib": "NODE_ENV=production redrun -p build:es build:umd",
|
"build:lib": "NODE_ENV=production redrun -p build:es build:umd",
|
||||||
"build:bundle": "echo 0",
|
"build:bundle": "echo 0",
|
||||||
"prepublish": "NODE_ENV=production redrun build:lib",
|
"prepublish": "NODE_ENV=production redrun build:lib",
|
||||||
"lint": "redrun lint:ci -- -- --fix",
|
"lint": "redrun lint:ci -- --fix",
|
||||||
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
"lint:ci": "NODE_ENV=test eslint . --ext .js --ext .md",
|
||||||
"test": "NODE_ENV=test joyent-react-scripts test --env=jsdom",
|
"test": "NODE_ENV=test joyent-react-scripts test --env=jsdom",
|
||||||
"test:ci": "redrun test",
|
"test:ci": "redrun test",
|
||||||
|
@ -40,6 +40,10 @@ const StyledLabel = Label.extend`
|
|||||||
${is('small')`
|
${is('small')`
|
||||||
width: ${remcalc(120)};
|
width: ${remcalc(120)};
|
||||||
`};
|
`};
|
||||||
|
|
||||||
|
${is('absolute')`
|
||||||
|
position: absolute;
|
||||||
|
`};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Meta = props => {
|
const Meta = props => {
|
||||||
|
44
yarn.lock
@ -2319,6 +2319,10 @@ case-sensitive-paths-webpack-plugin@2.1.1:
|
|||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.1.1.tgz#3d29ced8c1f124bf6f53846fb3f5894731fdc909"
|
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.1.1.tgz#3d29ced8c1f124bf6f53846fb3f5894731fdc909"
|
||||||
|
|
||||||
|
case@^1.2.1:
|
||||||
|
version "1.5.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/case/-/case-1.5.4.tgz#b201642aae9e374feb5750d1181a76850153830c"
|
||||||
|
|
||||||
caseless@~0.12.0:
|
caseless@~0.12.0:
|
||||||
version "0.12.0"
|
version "0.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||||
@ -4690,6 +4694,10 @@ flush-write-stream@^1.0.0:
|
|||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
readable-stream "^2.0.4"
|
readable-stream "^2.0.4"
|
||||||
|
|
||||||
|
fn-name@~1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-1.0.1.tgz#de8d8a15388b33cbf2145782171f73770c6030f0"
|
||||||
|
|
||||||
follow-redirects@^1.2.3:
|
follow-redirects@^1.2.3:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.4.1.tgz#d8120f4518190f55aac65bb6fc7b85fcd666d6aa"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.4.1.tgz#d8120f4518190f55aac65bb6fc7b85fcd666d6aa"
|
||||||
@ -7065,6 +7073,10 @@ lodash.pick@^4.4.0:
|
|||||||
version "4.4.0"
|
version "4.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
|
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
|
||||||
|
|
||||||
|
lodash.reduce@^4.6.0:
|
||||||
|
version "4.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b"
|
||||||
|
|
||||||
lodash.reverse@^4.0.1:
|
lodash.reverse@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.reverse/-/lodash.reverse-4.0.1.tgz#1f2afedace2e16e660f3aa7c59d3300a6f25d13c"
|
resolved "https://registry.yarnpkg.com/lodash.reverse/-/lodash.reverse-4.0.1.tgz#1f2afedace2e16e660f3aa7c59d3300a6f25d13c"
|
||||||
@ -7102,7 +7114,7 @@ lodash.values@^4.3.0:
|
|||||||
version "4.3.0"
|
version "4.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347"
|
resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347"
|
||||||
|
|
||||||
"lodash@>=3.5 <5", lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1:
|
"lodash@>=3.5 <5", lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1:
|
||||||
version "4.17.5"
|
version "4.17.5"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
|
||||||
|
|
||||||
@ -8773,6 +8785,10 @@ prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6,
|
|||||||
loose-envify "^1.3.1"
|
loose-envify "^1.3.1"
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
|
property-expr@^1.2.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.4.0.tgz#e28cfe4e7a5a231fb14c8ad687a93a5342e05a8c"
|
||||||
|
|
||||||
proxy-addr@~2.0.2:
|
proxy-addr@~2.0.2:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341"
|
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341"
|
||||||
@ -8828,7 +8844,7 @@ punycode@1.3.2:
|
|||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
||||||
|
|
||||||
punycode@2.x.x, punycode@^2.1.0:
|
punycode@2.x.x:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d"
|
||||||
|
|
||||||
@ -10943,6 +10959,10 @@ symbol@^0.2.1:
|
|||||||
version "0.2.3"
|
version "0.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/symbol/-/symbol-0.2.3.tgz#3b9873b8a901e47c6efe21526a3ac372ef28bbc7"
|
resolved "https://registry.yarnpkg.com/symbol/-/symbol-0.2.3.tgz#3b9873b8a901e47c6efe21526a3ac372ef28bbc7"
|
||||||
|
|
||||||
|
synchronous-promise@^1.0.18:
|
||||||
|
version "1.0.18"
|
||||||
|
resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-1.0.18.tgz#936e8763e6554088cdcf78dc64f7473b972fcefc"
|
||||||
|
|
||||||
table@^4.0.1:
|
table@^4.0.1:
|
||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc"
|
resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc"
|
||||||
@ -11197,6 +11217,10 @@ topo@3.x.x:
|
|||||||
dependencies:
|
dependencies:
|
||||||
hoek "5.x.x"
|
hoek "5.x.x"
|
||||||
|
|
||||||
|
toposort@^0.2.10:
|
||||||
|
version "0.2.12"
|
||||||
|
resolved "https://registry.yarnpkg.com/toposort/-/toposort-0.2.12.tgz#c7d2984f3d48c217315cc32d770888b779491e81"
|
||||||
|
|
||||||
toposort@^1.0.0:
|
toposort@^1.0.0:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec"
|
resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.6.tgz#c31748e55d210effc00fdcdc7d6e68d7d7bb9cec"
|
||||||
@ -11292,6 +11316,10 @@ type-is@~1.6.15:
|
|||||||
media-typer "0.3.0"
|
media-typer "0.3.0"
|
||||||
mime-types "~2.1.18"
|
mime-types "~2.1.18"
|
||||||
|
|
||||||
|
type-name@^2.0.1:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/type-name/-/type-name-2.0.2.tgz#efe7d4123d8ac52afff7f40c7e4dec5266008fb4"
|
||||||
|
|
||||||
typedarray@^0.0.6:
|
typedarray@^0.0.6:
|
||||||
version "0.0.6"
|
version "0.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
@ -12282,6 +12310,18 @@ yauzl@2.4.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fd-slicer "~1.0.1"
|
fd-slicer "~1.0.1"
|
||||||
|
|
||||||
|
yup@^0.24.1:
|
||||||
|
version "0.24.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/yup/-/yup-0.24.1.tgz#2c8a81b5f929ef29aaf77a8b7c9acfa52ab6a7d1"
|
||||||
|
dependencies:
|
||||||
|
case "^1.2.1"
|
||||||
|
fn-name "~1.0.1"
|
||||||
|
lodash "^4.17.0"
|
||||||
|
property-expr "^1.2.0"
|
||||||
|
synchronous-promise "^1.0.18"
|
||||||
|
toposort "^0.2.10"
|
||||||
|
type-name "^2.0.1"
|
||||||
|
|
||||||
zen-observable-ts@^0.8.6:
|
zen-observable-ts@^0.8.6:
|
||||||
version "0.8.8"
|
version "0.8.8"
|
||||||
resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.8.tgz#1a586dc204fa5632a88057f879500e0d2ba06869"
|
resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.8.tgz#1a586dc204fa5632a88057f879500e0d2ba06869"
|
||||||
|