feat(my-joy-instances): simpler user scripts editor (#1289)
fixes #1187
@ -130,9 +130,7 @@ export default compose(
|
||||
i => ImageType[i] === 'Infrastructure Container'
|
||||
);
|
||||
|
||||
const filtered = filter
|
||||
? index.search(filter)
|
||||
: images;
|
||||
const filtered = filter ? index.search(filter) : images;
|
||||
|
||||
return {
|
||||
images: filtered
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@ -3378,6 +3378,7 @@ exports[`renders <KeyValue input="textarea" /> without throwing 1`] = `
|
||||
className="c18 c19"
|
||||
disabled={false}
|
||||
id="p"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
|
@ -0,0 +1,40 @@
|
||||
import React, { PureComponent, Fragment } from 'react';
|
||||
import { Field } from 'redux-form';
|
||||
import { Margin } from 'styled-components-spacing';
|
||||
|
||||
import { FormGroup, Button, H3, P } from 'joyent-ui-toolkit';
|
||||
import Editor from 'joyent-ui-toolkit/dist/es/editor';
|
||||
|
||||
class EditorField extends PureComponent {
|
||||
render() {
|
||||
return <Editor {...this.props} onBlur={null} mode="sh" />;
|
||||
}
|
||||
}
|
||||
|
||||
export default ({ onSubmit }) => (
|
||||
<form onSubmit={onSubmit}>
|
||||
<FormGroup name="value" field={Field} fluid>
|
||||
<Field name="value" component={EditorField} />
|
||||
<Margin bottom={4} top={4}>
|
||||
<Button type="submit">Next</Button>
|
||||
</Margin>
|
||||
</FormGroup>
|
||||
</form>
|
||||
);
|
||||
|
||||
export const Overview = ({ script, lines }) => (
|
||||
<Margin top={3}>
|
||||
{script ? (
|
||||
<Fragment>
|
||||
<H3 noMargin>User script added</H3>
|
||||
<Margin top={2}>
|
||||
<P>
|
||||
{lines} line{lines === 1 ? '' : 's'} of code
|
||||
</P>
|
||||
</Margin>
|
||||
</Fragment>
|
||||
) : (
|
||||
<H3>No user script added</H3>
|
||||
)}
|
||||
</Margin>
|
||||
);
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
@ -1011,6 +1011,7 @@ exports[`renders <AddForm /> without throwing 1`] = `
|
||||
className="c18 c19"
|
||||
disabled={false}
|
||||
id="l"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
@ -2141,6 +2142,7 @@ exports[`renders <EditForm /> without throwing 1`] = `
|
||||
className="c18 c19"
|
||||
disabled={false}
|
||||
id="n"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 16 KiB |
@ -1428,6 +1428,7 @@ Array [
|
||||
className="c18 c19"
|
||||
disabled={false}
|
||||
id="t"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
@ -3440,6 +3441,7 @@ Array [
|
||||
className="c18 c19"
|
||||
disabled={false}
|
||||
id="l"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
@ -4585,6 +4587,7 @@ Array [
|
||||
className="c18 c19"
|
||||
disabled={false}
|
||||
id="n"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
@ -6020,6 +6023,7 @@ Array [
|
||||
className="c18 c19"
|
||||
disabled={false}
|
||||
id="p"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
@ -7184,6 +7188,7 @@ Array [
|
||||
className="c18 c19"
|
||||
disabled={false}
|
||||
id="r"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
|
@ -2,16 +2,16 @@ import React, { Fragment } from 'react';
|
||||
import { compose } from 'react-apollo';
|
||||
import { set } from 'react-redux-values';
|
||||
import ReduxForm from 'declarative-redux-form';
|
||||
import { destroy } from 'redux-form';
|
||||
import { Margin } from 'styled-components-spacing';
|
||||
import { connect } from 'react-redux';
|
||||
import get from 'lodash.get';
|
||||
import Flex from 'styled-flex-component';
|
||||
|
||||
import { ScriptIcon, Button, KeyValue } from 'joyent-ui-toolkit';
|
||||
import Editor from 'joyent-ui-toolkit/dist/es/editor';
|
||||
import { ScriptIcon, Button } from 'joyent-ui-toolkit';
|
||||
|
||||
import Title from '@components/create-instance/title';
|
||||
import Description from '@components/description';
|
||||
import UserScriptForm, { Overview } from '@components/create-instance/user-script';
|
||||
|
||||
const FORM_NAME = 'create-instance-user-script';
|
||||
|
||||
@ -22,10 +22,9 @@ export const UserScript = ({
|
||||
edit,
|
||||
formOpen,
|
||||
script = {},
|
||||
lines,
|
||||
handleChangeOpenForm,
|
||||
handleSubmit,
|
||||
handleRemove,
|
||||
handleNext,
|
||||
handleEdit,
|
||||
step
|
||||
}) => (
|
||||
@ -39,67 +38,58 @@ export const UserScript = ({
|
||||
User Script
|
||||
</Title>
|
||||
{expanded ? (
|
||||
<Description>
|
||||
User script can be used to inject a custom boot script.
|
||||
</Description>
|
||||
<Fragment>
|
||||
<Description>
|
||||
User script can be used to inject a custom boot script.
|
||||
</Description>
|
||||
{formOpen ? (
|
||||
<ReduxForm
|
||||
form={FORM_NAME}
|
||||
destroyOnUnmount={false}
|
||||
forceUnregisterOnUnmount={true}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{props => <UserScriptForm {...props} />}
|
||||
</ReduxForm>
|
||||
) : null}
|
||||
</Fragment>
|
||||
) : null}
|
||||
<ReduxForm
|
||||
form={FORM_NAME}
|
||||
destroyOnUnmount={false}
|
||||
forceUnregisterOnUnmount={true}
|
||||
initialValues={script}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{props =>
|
||||
!formOpen && create ? null : (
|
||||
<KeyValue
|
||||
{...props}
|
||||
expanded={formOpen}
|
||||
method={edit ? 'edit' : 'add'}
|
||||
input="textarea"
|
||||
type="user script"
|
||||
onToggleExpanded={() => handleChangeOpenForm(!formOpen)}
|
||||
onCancel={() => handleChangeOpenForm(false)}
|
||||
onRemove={handleRemove}
|
||||
editor={Editor}
|
||||
onlyValue
|
||||
/>
|
||||
)
|
||||
}
|
||||
</ReduxForm>
|
||||
{expanded ? (
|
||||
<Margin top={formOpen || script.value ? 4 : 2} bottom={7}>
|
||||
{script.value || formOpen ? null : (
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleChangeOpenForm(true)}
|
||||
secondary
|
||||
>
|
||||
Add User Script
|
||||
</Button>
|
||||
<Flex alignCenter>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => handleChangeOpenForm(true)}
|
||||
secondary
|
||||
>
|
||||
Add User Script
|
||||
</Button>
|
||||
<Button type="submit" onClick={handleSubmit}>
|
||||
Next
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
<Button type="submit" onClick={handleNext}>
|
||||
Next
|
||||
</Button>
|
||||
</Margin>
|
||||
) : proceeded ? (
|
||||
<Margin top={4} bottom={7}>
|
||||
<Button type="button" onClick={handleEdit} secondary>
|
||||
Edit
|
||||
</Button>
|
||||
</Margin>
|
||||
<Fragment>
|
||||
<Overview script={script} lines={lines} />
|
||||
<Margin top={4} bottom={7}>
|
||||
<Button type="button" onClick={handleEdit} secondary>
|
||||
Edit
|
||||
</Button>
|
||||
</Margin>
|
||||
</Fragment>
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
export default compose(
|
||||
connect(
|
||||
({ values }, ownProps) => {
|
||||
({ values, form }, ownProps) => {
|
||||
const formOpen = get(values, 'create-instance-user-script-open', false);
|
||||
|
||||
const script = get(values, 'create-instance-user-script', {
|
||||
name: 'user-script'
|
||||
});
|
||||
const script = get(form, `${FORM_NAME}.values.value`, '');
|
||||
const lines = script.split('\n').length;
|
||||
|
||||
const proceeded = get(
|
||||
values,
|
||||
@ -109,6 +99,7 @@ export default compose(
|
||||
|
||||
return {
|
||||
script,
|
||||
lines,
|
||||
proceeded: proceeded || script.value,
|
||||
create: !script.value,
|
||||
edit: script.value,
|
||||
@ -116,17 +107,11 @@ export default compose(
|
||||
};
|
||||
},
|
||||
(dispatch, { history }) => ({
|
||||
handleNext: () => {
|
||||
dispatch(
|
||||
set({ name: 'create-instance-user-script-proceeded', value: true })
|
||||
);
|
||||
|
||||
return history.push(`/~create/networks${history.location.search}`);
|
||||
},
|
||||
handleEdit: () => {
|
||||
dispatch(
|
||||
set({ name: 'create-instance-user-script-proceeded', value: true })
|
||||
);
|
||||
dispatch([
|
||||
set({ name: 'create-instance-user-script-proceeded', value: true }),
|
||||
set({ name: `create-instance-user-script-open`, value: true })
|
||||
]);
|
||||
|
||||
return history.push(`/~create/user-script${history.location.search}`);
|
||||
},
|
||||
@ -136,20 +121,12 @@ export default compose(
|
||||
]);
|
||||
},
|
||||
handleSubmit: value => {
|
||||
return dispatch([
|
||||
set({ name: `create-instance-user-script`, value: { ...value } }),
|
||||
set({ name: `create-instance-user-script-open`, value: false })
|
||||
]);
|
||||
},
|
||||
handleRemove: () => {
|
||||
return dispatch([
|
||||
destroy(FORM_NAME),
|
||||
set({
|
||||
name: `create-instance-user-script`,
|
||||
value: { name: 'user-script' }
|
||||
}),
|
||||
set({ name: `create-instance-user-script-open`, value: false })
|
||||
dispatch([
|
||||
set({ name: `create-instance-user-script-open`, value: false }),
|
||||
set({ name: 'create-instance-user-script-proceeded', value: true })
|
||||
]);
|
||||
|
||||
return history.push(`/~create/networks${history.location.search}`);
|
||||
}
|
||||
})
|
||||
)
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@ -1776,6 +1776,7 @@ exports[`renders <Metadata addOpen /> without throwing 1`] = `
|
||||
className="c30 c31"
|
||||
disabled={false}
|
||||
id="x"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
@ -4516,6 +4517,7 @@ exports[`renders <Metadata metadata /> without throwing 1`] = `
|
||||
className="c33 c34"
|
||||
disabled={false}
|
||||
id="C"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
@ -4735,6 +4737,7 @@ exports[`renders <Metadata metadata /> without throwing 1`] = `
|
||||
className="c33 c34"
|
||||
disabled={false}
|
||||
id="E"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
@ -4954,6 +4957,7 @@ exports[`renders <Metadata metadata /> without throwing 1`] = `
|
||||
className="c33 c34"
|
||||
disabled={false}
|
||||
id="G"
|
||||
name="name"
|
||||
onBlur={undefined}
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { PureComponent, Fragment } from 'react';
|
||||
import React, { Fragment } from 'react';
|
||||
import { Margin, Padding } from 'styled-components-spacing';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTheme } from 'styled-components';
|
||||
@ -51,26 +51,6 @@ const Bold = styled.span`
|
||||
font-weight: ${props => props.theme.font.weight.semibold};
|
||||
`;
|
||||
|
||||
class ValueTextareaField extends PureComponent {
|
||||
render() {
|
||||
const { input = {}, submitting, editor } = this.props;
|
||||
|
||||
return input.value === 'user-script' ? (
|
||||
<Field
|
||||
name="value"
|
||||
component={props =>
|
||||
React.createElement(editor, {
|
||||
...props,
|
||||
mode: 'sh'
|
||||
})
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Textarea monospace resize="vertical" disabled={submitting} fluid />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const TextareaKeyValue = ({
|
||||
type,
|
||||
submitting,
|
||||
@ -103,11 +83,12 @@ const TextareaKeyValue = ({
|
||||
<FormGroup name="value" field={Field} fluid>
|
||||
<FormLabel>{titleCase(type)} value</FormLabel>
|
||||
<Margin top={0.5}>
|
||||
<Field
|
||||
<Textarea
|
||||
monospace
|
||||
name="name"
|
||||
resize="vertical"
|
||||
disabled={submitting}
|
||||
fluid
|
||||
component={ValueTextareaField}
|
||||
props={{ submitting, editor }}
|
||||
/>
|
||||
</Margin>
|
||||
<Row>
|
||||
@ -182,7 +163,6 @@ export const KeyValue = ({
|
||||
pristine = true,
|
||||
invalid = false,
|
||||
removing = false,
|
||||
handleSubmit,
|
||||
onToggleExpanded = () => null,
|
||||
onCancel = () => null,
|
||||
onRemove = () => null,
|
||||
|
46
yarn.lock
@ -246,10 +246,10 @@ accept@3.x.x:
|
||||
hoek "5.x.x"
|
||||
|
||||
accepts@~1.3.4:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f"
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2"
|
||||
dependencies:
|
||||
mime-types "~2.1.16"
|
||||
mime-types "~2.1.18"
|
||||
negotiator "0.6.1"
|
||||
|
||||
acorn-dynamic-import@^2.0.0:
|
||||
@ -1945,12 +1945,18 @@ boom@6.x.x:
|
||||
dependencies:
|
||||
hoek "5.x.x"
|
||||
|
||||
boom@7.1.x, boom@7.x.x:
|
||||
boom@7.1.x:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/boom/-/boom-7.1.1.tgz#50392a4e3417e971f1ad28622c20e832275260bb"
|
||||
dependencies:
|
||||
hoek "5.x.x"
|
||||
|
||||
boom@7.x.x:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/boom/-/boom-7.2.0.tgz#2bff24a55565767fde869ec808317eb10c48e966"
|
||||
dependencies:
|
||||
hoek "5.x.x"
|
||||
|
||||
bounce@1.2.x, bounce@1.x.x:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/bounce/-/bounce-1.2.0.tgz#e3bac68c73fd256e38096551efc09f504873c8c8"
|
||||
@ -2407,7 +2413,7 @@ checksum@^0.1.1:
|
||||
dependencies:
|
||||
optimist "~0.3.5"
|
||||
|
||||
chokidar@^1.6.0, chokidar@^1.6.1, chokidar@^1.7.0:
|
||||
chokidar@^1.6.0, chokidar@^1.6.1:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
|
||||
dependencies:
|
||||
@ -2422,7 +2428,7 @@ chokidar@^1.6.0, chokidar@^1.6.1, chokidar@^1.7.0:
|
||||
optionalDependencies:
|
||||
fsevents "^1.0.0"
|
||||
|
||||
chokidar@^2.0.0:
|
||||
chokidar@^2.0.0, chokidar@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.2.tgz#4dc65139eeb2714977735b6a35d06e97b494dfd7"
|
||||
dependencies:
|
||||
@ -2807,8 +2813,8 @@ content-type@1.0.4, content-type@~1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||
|
||||
content@4.x.x:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/content/-/content-4.0.3.tgz#2224e0449e4258617bc5f7fb4dc2f17f321d21fc"
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/content/-/content-4.0.4.tgz#2941609c89593ed2e1504d72c9a28e9516f163e0"
|
||||
dependencies:
|
||||
boom "7.x.x"
|
||||
|
||||
@ -5200,8 +5206,8 @@ hapi-triton-auth@^2.0.0:
|
||||
wreck "14.0.x"
|
||||
|
||||
hapi@^17.2.0:
|
||||
version "17.2.0"
|
||||
resolved "https://registry.yarnpkg.com/hapi/-/hapi-17.2.0.tgz#e5d74b65235b443225e05d7b7510cdb80d4887e7"
|
||||
version "17.2.1"
|
||||
resolved "https://registry.yarnpkg.com/hapi/-/hapi-17.2.1.tgz#177ca6b8d38b91509aea6ea63295cc726890f006"
|
||||
dependencies:
|
||||
accept "3.x.x"
|
||||
ammo "3.x.x"
|
||||
@ -7383,7 +7389,7 @@ mime-db@1.x.x, "mime-db@>= 1.33.0 < 2", mime-db@~1.33.0:
|
||||
version "1.33.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
|
||||
|
||||
mime-types@^2.1.12, mime-types@~2.1.16, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.7:
|
||||
mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.7:
|
||||
version "2.1.18"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
|
||||
dependencies:
|
||||
@ -7582,6 +7588,10 @@ negotiator@0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
|
||||
|
||||
neo-async@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.0.tgz#76b1c823130cca26acfbaccc8fbaf0a2fa33b18f"
|
||||
|
||||
nigel@3.x.x:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nigel/-/nigel-3.0.0.tgz#a6e3378a8a34281e75ba1641e886a415d4be93ad"
|
||||
@ -8687,10 +8697,14 @@ preserve@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||
|
||||
prettier@1.11.0, prettier@^1.11.0, prettier@^1.7.4:
|
||||
prettier@1.11.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.0.tgz#c024f70cab158c993f50fc0c25ffe738cb8b0f85"
|
||||
|
||||
prettier@^1.11.0, prettier@^1.7.4:
|
||||
version "1.11.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75"
|
||||
|
||||
pretty-bytes@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
|
||||
@ -11740,12 +11754,12 @@ watch@~0.10.0:
|
||||
resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
|
||||
|
||||
watchpack@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac"
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.5.0.tgz#231e783af830a22f8966f65c4c4bacc814072eed"
|
||||
dependencies:
|
||||
async "^2.1.2"
|
||||
chokidar "^1.7.0"
|
||||
chokidar "^2.0.2"
|
||||
graceful-fs "^4.1.2"
|
||||
neo-async "^2.5.0"
|
||||
|
||||
wbuf@^1.1.0, wbuf@^1.7.2:
|
||||
version "1.7.2"
|
||||
|