feat(my-joy-instances): simpler user scripts editor (#1289)

fixes #1187
This commit is contained in:
Sara Vieira 2018-03-01 13:47:30 +00:00 committed by Sérgio Ramos
parent abe7a58e3f
commit 9d10a3fa92
30 changed files with 763 additions and 6556 deletions

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -3378,6 +3378,7 @@ exports[`renders <KeyValue input="textarea" /> without throwing 1`] = `
className="c18 c19"
disabled={false}
id="p"
name="name"
onBlur={undefined}
/>
</div>

View File

@ -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>
);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -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>

View File

@ -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}`);
}
})
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -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>

View File

@ -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,

View File

@ -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"