Browse code

Form (first version)

Cinan Rakosnik authored on 21/03/2018 at 11:52:03
Showing 7 changed files
... ...
@@ -24,6 +24,7 @@
24 24
     "eslint-plugin-react": "7.4.0",
25 25
     "extract-text-webpack-plugin": "3.0.2",
26 26
     "file-loader": "1.1.5",
27
+    "formik": "^0.11.11",
27 28
     "fs-extra": "3.0.1",
28 29
     "html-webpack-plugin": "2.29.0",
29 30
     "jest": "20.0.4",
... ...
@@ -32,6 +33,7 @@
32 32
     "postcss-flexbugs-fixes": "3.2.0",
33 33
     "postcss-loader": "2.0.8",
34 34
     "promise": "8.0.1",
35
+    "proptypes": "^1.1.0",
35 36
     "raf": "3.4.0",
36 37
     "rambda": "^1.0.12",
37 38
     "rambdax": "^0.8.10",
... ...
@@ -40,10 +42,13 @@
40 40
     "react-dev-utils": "^5.0.0",
41 41
     "react-dom": "^16.2.0",
42 42
     "react-measure": "^2.0.0",
43
+    "react-select": "^1.2.1",
44
+    "react-sortable-hoc": "^0.6.8",
43 45
     "recharts": "^1.0.0-beta.10",
44 46
     "style-loader": "0.19.0",
45 47
     "sw-precache-webpack-plugin": "0.11.4",
46 48
     "url-loader": "0.6.2",
49
+    "uuid": "^3.2.1",
47 50
     "webpack": "3.8.1",
48 51
     "webpack-dev-server": "2.9.4",
49 52
     "webpack-manifest-plugin": "1.3.2",
... ...
@@ -1,4 +1,5 @@
1 1
 import React, { PureComponent } from 'react';
2
+import Form from './components/Form';
2 3
 import Gantt from './components/Gantt';
3 4
 import { normalizeData } from './ganttUtils';
4 5
 
... ...
@@ -34,6 +35,7 @@ class App extends PureComponent {
34 34
   render() {
35 35
     return (
36 36
       <div style={{ padding: 20 }}>
37
+        <Form />
37 38
         <Gantt data={data} />
38 39
       </div>
39 40
     );
40 41
new file mode 100644
... ...
@@ -0,0 +1,203 @@
0
+import React from 'react';
1
+import { reject } from 'rambda';
2
+
3
+const computeBoxStyle = (
4
+  {
5
+    // Maybe rhythm props.
6
+    margin,
7
+    marginVertical = margin,
8
+    marginHorizontal = margin,
9
+    marginTop = marginVertical,
10
+    marginBottom = marginVertical,
11
+    marginLeft = marginHorizontal,
12
+    marginRight = marginHorizontal,
13
+    padding,
14
+    paddingVertical = padding,
15
+    paddingHorizontal = padding,
16
+    paddingTop = paddingVertical,
17
+    paddingBottom = paddingVertical,
18
+    paddingLeft = paddingHorizontal,
19
+    paddingRight = paddingHorizontal,
20
+    height,
21
+    maxHeight,
22
+    maxWidth,
23
+    minHeight,
24
+    minWidth,
25
+    width,
26
+    bottom,
27
+    left,
28
+    right,
29
+    top,
30
+
31
+    flex,
32
+    backgroundColor,
33
+
34
+    // Border props.
35
+    borderColor = 'gray',
36
+    // We can't use borderColor as default because some component in React Native,
37
+    // for example Image, doesn't support that.
38
+    borderBottomColor,
39
+    borderLeftColor,
40
+    borderRightColor,
41
+    borderTopColor,
42
+    borderRadius,
43
+    borderBottomLeftRadius = borderRadius,
44
+    borderBottomRightRadius = borderRadius,
45
+    borderTopLeftRadius = borderRadius,
46
+    borderTopRightRadius = borderRadius,
47
+    borderWidth = 0, // Enfore React Native behaviour. It also makes more sense.
48
+    borderBottomWidth = borderWidth,
49
+    borderLeftWidth = borderWidth,
50
+    borderRightWidth = borderWidth,
51
+    borderTopWidth = borderWidth,
52
+    borderStyle,
53
+    boxShadow,
54
+
55
+    // Just value props.
56
+    alignContent,
57
+    alignItems,
58
+    alignSelf,
59
+    flexBasis,
60
+    flexDirection,
61
+    flexGrow,
62
+    flexShrink,
63
+    flexWrap,
64
+    justifyContent,
65
+    opacity,
66
+    overflow,
67
+    overflowX,
68
+    overflowY,
69
+    pointerEvents,
70
+    position,
71
+    textOverflow,
72
+    whiteSpace,
73
+    zIndex,
74
+
75
+    ...props
76
+  },
77
+) => {
78
+  let style = {
79
+    position: 'relative',
80
+    flexDirection: 'column',
81
+    display: 'flex',
82
+  };
83
+
84
+  if (typeof flex === 'number') {
85
+    style.flexBasis = 'auto';
86
+    style.flexGrow = flex;
87
+    style.flexShrink = 1;
88
+  }
89
+
90
+  const justValueProps = {
91
+    margin,
92
+    marginVertical,
93
+    marginHorizontal,
94
+    marginTop,
95
+    marginBottom,
96
+    marginLeft,
97
+    marginRight,
98
+    padding,
99
+    paddingVertical,
100
+    paddingHorizontal,
101
+    paddingTop,
102
+    paddingBottom,
103
+    paddingLeft,
104
+    paddingRight,
105
+    height,
106
+    maxHeight,
107
+    maxWidth,
108
+    minHeight,
109
+    minWidth,
110
+    width,
111
+    bottom,
112
+    left,
113
+    right,
114
+    top,
115
+
116
+    flex,
117
+    backgroundColor,
118
+
119
+    // Border props.
120
+    borderColor,
121
+    // We can't use borderColor as default because some component in React Native,
122
+    // for example Image, doesn't support that.
123
+    borderBottomColor,
124
+    borderLeftColor,
125
+    borderRightColor,
126
+    borderTopColor,
127
+    borderRadius,
128
+    borderBottomLeftRadius,
129
+    borderBottomRightRadius,
130
+    borderTopLeftRadius,
131
+    borderTopRightRadius,
132
+    borderWidth,
133
+    borderBottomWidth,
134
+    borderLeftWidth,
135
+    borderRightWidth,
136
+    borderTopWidth,
137
+    borderStyle,
138
+    boxShadow,
139
+
140
+    // Just value props.
141
+    alignContent,
142
+    alignItems,
143
+    alignSelf,
144
+    flexBasis,
145
+    flexDirection,
146
+    flexGrow,
147
+    flexShrink,
148
+    flexWrap,
149
+    justifyContent,
150
+    opacity,
151
+    overflow,
152
+    overflowX,
153
+    overflowY,
154
+    pointerEvents,
155
+    position,
156
+    textOverflow,
157
+    whiteSpace,
158
+    zIndex,
159
+  };
160
+
161
+  Object.keys(justValueProps)
162
+    .filter(prop => {
163
+      const value = justValueProps[prop];
164
+      const isDefined = typeof value === 'number' || value;
165
+      return isDefined;
166
+    })
167
+    .forEach(prop => {
168
+      const value = justValueProps[prop];
169
+      style[prop] = value;
170
+    });
171
+
172
+  return [style, props];
173
+};
174
+
175
+class Box extends React.PureComponent {
176
+  render() {
177
+    const {
178
+      as = 'div',
179
+      className,
180
+      style,
181
+      ...props
182
+    } = this.props;
183
+
184
+    const [boxStyle, restProps] = computeBoxStyle(props);
185
+
186
+    let combinedStyles = {
187
+      ...boxStyle,
188
+      ...style,
189
+    };
190
+
191
+    combinedStyles = reject(val => Number.isNaN(val), combinedStyles);
192
+
193
+    const styles = {
194
+      style: combinedStyles,
195
+      className
196
+    };
197
+
198
+    return React.createElement(as, { ...restProps, ...styles });
199
+  }
200
+}
201
+
202
+export default Box;
0 203
new file mode 100644
... ...
@@ -0,0 +1,6 @@
0
+import React from 'react';
1
+import { SortableHandle } from 'react-sortable-hoc';
2
+
3
+const DragHandle = SortableHandle(() => <span style={{ cursor: 'pointer' }}>⬍︎</span>);
4
+
5
+export default DragHandle;
0 6
\ No newline at end of file
1 7
new file mode 100644
... ...
@@ -0,0 +1,306 @@
0
+import React from 'react';
1
+import Box from './Box';
2
+import uuid from 'uuid/v4';
3
+import {
4
+  SortableContainer,
5
+  SortableElement,
6
+  arrayMove,
7
+} from 'react-sortable-hoc';
8
+import DragHandle from './DragHandle';
9
+import { FieldArray, Formik, Form as FormikForm, Field } from 'formik';
10
+import PropTypes from 'proptypes';
11
+import Select from 'react-select';
12
+import 'react-select/dist/react-select.css';
13
+import {
14
+  filter, find, flatten, identity, map, prop, propEq, reject, uniq, update
15
+} from 'rambda';
16
+import { insert } from 'ramda';
17
+
18
+const allJobs = {
19
+  frontend: 'Frontend',
20
+  backend: 'Backend',
21
+};
22
+
23
+const nextWorkerName = (rows) =>
24
+  `${rows.length + 1}. pracovník`;
25
+
26
+class Form extends React.PureComponent {
27
+  state = {
28
+    rows: [
29
+      {
30
+        id: uuid(),
31
+        name: 'pracovnik 1',
32
+        preempt: false,
33
+        linkedTo: null,
34
+        jobs: [
35
+          { id: uuid(), name: 'frontend', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0 },
36
+          { id: uuid(), name: 'backend', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0 }
37
+        ]
38
+      },
39
+      {
40
+        id: uuid(),
41
+        name: 'pracovnik 2',
42
+        preempt: false,
43
+        linkedTo: null,
44
+        jobs: [
45
+          { id: uuid(), name: 'frontend', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0 },
46
+          { id: uuid(), name: 'backend', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0 }
47
+        ]
48
+      }
49
+    ]
50
+  };
51
+
52
+  addWorker = (setFieldValue, rows) => {
53
+    const updatedRows = [...rows, { id: uuid(), name: nextWorkerName(rows), jobs: [] } ];
54
+    setFieldValue('rows', updatedRows);
55
+  };
56
+
57
+  render() {
58
+    return (
59
+      <Formik initialValues={this.state} render={({ setFieldValue, values: { rows } }) => (
60
+        <React.Fragment>
61
+          <h1>Konfigurácia projektu</h1>
62
+
63
+          <Box flexDirection="row" marginBottom={10}>
64
+            <Box flexBasis="20%" flexShrink={0}><strong>Pracovník</strong></Box>
65
+            <Box flexBasis="60%" flexShrink={0}><strong>Úlohy</strong></Box>
66
+            <Box flexBasis="10%" flexShrink={0} align="center"><strong>Prerušenie</strong></Box>
67
+          </Box>
68
+
69
+          <FieldArray name="rows" render={arrayHelpers => (
70
+            <FormikForm>
71
+              {rows.map((row, i) => <Row key={i} {...row} arrayHelpers={arrayHelpers} prefix={`rows.${i}`} index={i} />)}
72
+            </FormikForm>
73
+          )} />
74
+
75
+          <Box flexDirection="row" marginBottom={10}>
76
+            <Box flexBasis="20%" flexShrink={0} onClick={() => this.addWorker(setFieldValue, rows)} style={{ cursor: 'pointer' }}>
77
+              + Nový pracovník
78
+            </Box>
79
+          </Box>
80
+        </React.Fragment>
81
+      )}>
82
+      </Formik>
83
+    )
84
+  }
85
+}
86
+
87
+const SortableJob = SortableElement(
88
+  class extends React.PureComponent {
89
+    static contextTypes = {
90
+      formik: PropTypes.object
91
+    };
92
+
93
+    handleSelectChange = (type, selectedPairs) => {
94
+      const { prefix } = this.props;
95
+      const { formik: { setFieldValue } } = this.context;
96
+
97
+      const selected = map(prop('value'), selectedPairs);
98
+
99
+      setFieldValue(`${prefix}.${type}`, selected);
100
+    };
101
+
102
+    deleteJob = () => {
103
+      const { rowIndex, myIndex } = this.props;
104
+      const { formik: { setFieldValue, values: { rows } } } = this.context;
105
+
106
+      const jobs = filter(identity, update(myIndex, null, rows[rowIndex].jobs));
107
+
108
+      if (jobs.length) {
109
+        setFieldValue(`rows.${rowIndex}.jobs`, jobs);
110
+      } else {
111
+        const updatedRows = filter(identity, update(rowIndex, null, rows));
112
+        setFieldValue(`rows`, updatedRows);
113
+      }
114
+    };
115
+
116
+    render() {
117
+      const { myIndex, rowIndex, prefix, job, existingJobs: _existingJobs } = this.props;
118
+      const { formik: { values: { rows } } } = this.context;
119
+
120
+      const existingJobs = map(
121
+        value => {
122
+          const [idRow, idJob] = value.split(':');
123
+          const row = find(propEq('id', idRow), rows);
124
+          const jobName = find(propEq('id', idJob), row.jobs).name;
125
+
126
+          return ({ value, label: `${row.name} – ${jobName}` });
127
+        },
128
+        reject(
129
+          value => {
130
+            const [, idJob] = value.split(':');
131
+            return idJob === job.id;
132
+          },
133
+          _existingJobs
134
+        )
135
+      );
136
+
137
+      return (
138
+        <Box flexDirection="row" marginBottom={10} paddingBottom={10} backgroundColor="white" borderBottomColor="#1B1B3A" borderBottomWidth={1} borderStyle="solid">
139
+          <Box marginRight={10} style={{ fontSize: '1.5rem' }}>
140
+            <DragHandle />
141
+          </Box>
142
+
143
+          <Box flex={1}>
144
+            <Box width={200} marginBottom={10} flexDirection="row">
145
+              <Field component="select" name={`${prefix}.name`}>
146
+               {Object.keys(allJobs).map(key => (
147
+                  <option value={key} key={key}>{allJobs[key]}</option>
148
+                ))}
149
+              </Field>
150
+              <Box style={{ cursor: 'pointer' }} onClick={this.deleteJob} marginLeft={5}>✕</Box>
151
+            </Box>
152
+
153
+            <Box flexDirection="row" justifyContent="space-between" marginBottom={10}>
154
+              <Box flexBasis="30%">
155
+                <label>
156
+                  Trvanie: <br />
157
+                  <Field type="number" step={1} name={`${prefix}.t`} style={{ width: '100%' }} />
158
+                </label>
159
+              </Box>
160
+              <Box flexBasis="30%">
161
+                <label>
162
+                  Deadline: <br />
163
+                  <Field type="number" step={1} name={`${prefix}.d`} style={{ width: '100%' }} />
164
+                </label>
165
+              </Box>
166
+              <Box flexBasis="30%">
167
+                <label>
168
+                  Váha: <br />
169
+                  <Field type="number" min={0} max={1} step={0.1} name={`${prefix}.w`} style={{ width: '100%' }} />
170
+                </label>
171
+              </Box>
172
+            </Box>
173
+
174
+            <Box>
175
+              <Box as="label" flexDirection="row" marginBottom={5}>
176
+                <Field type="radio" name={`${prefix}.succOrAnc`} value={0} /> Bez nadväznosti
177
+              </Box>
178
+              <Box marginBottom={5}>
179
+                <Box as="label" flexDirection="row">
180
+                  <Field type="radio" name={`${prefix}.succOrAnc`} value={1}/> Predchodcovia
181
+                </Box>
182
+                <Box flex={1} marginLeft={10} marginTop={5}>
183
+                  <Select
184
+                    disabled={false}
185
+                    multi
186
+                    onChange={e => this.handleSelectChange('anc', e)}
187
+                    options={existingJobs}
188
+                    removeSelected
189
+                    value={job.anc}
190
+                  />
191
+                </Box>
192
+              </Box>
193
+              <Box>
194
+                <Box as="label" flexDirection="row">
195
+                  <Field type="radio" name={`${prefix}.succOrAnc`} value={2} /> Nasledovníci
196
+                </Box>
197
+                <Box flex={1} marginLeft={10} marginTop={5}>
198
+                  <Select
199
+                    disabled={false}
200
+                    multi
201
+                    onChange={e => this.handleSelectChange('succ', e)}
202
+                    options={existingJobs}
203
+                    removeSelected
204
+                    value={job.succ}
205
+                  />
206
+                </Box>
207
+              </Box>
208
+            </Box>
209
+          </Box>
210
+        </Box>
211
+      );
212
+    }
213
+  });
214
+
215
+const SortableList = SortableContainer(({ jobs, existingJobs, prefix, rowIndex }) => (
216
+  <div>
217
+    {jobs.map((job, i) => (
218
+      <SortableJob
219
+        key={job.id}
220
+        index={i}
221
+        myIndex={i}
222
+        rowIndex={rowIndex}
223
+        job={job}
224
+        prefix={`${prefix}.${i}`}
225
+        existingJobs={existingJobs}
226
+      />
227
+    ))}
228
+  </div>
229
+));
230
+
231
+class Row extends React.PureComponent {
232
+  static contextTypes = {
233
+    formik: PropTypes.object
234
+  };
235
+
236
+  onSortEnd = ({ oldIndex, newIndex }) => {
237
+    const { prefix, index } = this.props;
238
+    const { formik: { setFieldValue, values: { rows }} } = this.context;
239
+
240
+    const updatedJobs = arrayMove(rows[index].jobs, oldIndex, newIndex);
241
+
242
+    setFieldValue(`${prefix}.jobs`, updatedJobs);
243
+  };
244
+
245
+  findExistingJobs = () => {
246
+    const { formik: { values: { rows } } } = this.context;
247
+
248
+    const existingJobs = uniq(
249
+      flatten(
250
+        map(({ id: idRow, jobs }) =>
251
+          map(({ id: idJob }) => `${idRow}:${idJob}`, jobs),
252
+        rows)
253
+      )
254
+    );
255
+
256
+    return existingJobs;
257
+  };
258
+
259
+  addJob = () => {
260
+    const { index } = this.props;
261
+    const { formik: { setFieldValue, values: { rows } } } = this.context;
262
+    const newJob = {
263
+      id: uuid(), name: 'frontend', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0
264
+    };
265
+
266
+    const jobs = [...rows[index].jobs, newJob];
267
+
268
+    setFieldValue(`rows.${index}.jobs`, jobs);
269
+  };
270
+
271
+  duplicate = () => {
272
+    const { id, index, name, preempt, jobs } = this.props;
273
+    const { formik: { setFieldValue, values: { rows } } } = this.context;
274
+
275
+    const jobsCopy = map(job => ({ ...job }), jobs);
276
+    const newRow = { id: uuid(), name: `${name} - kópia`, preempt, linkedTo: id, jobs: jobsCopy };
277
+
278
+    const updatedRows = insert(index + 1, newRow, rows);
279
+
280
+    setFieldValue('rows', updatedRows);
281
+  };
282
+
283
+  render() {
284
+    const { index, prefix, name, preempt, linkedTo, jobs } = this.props;
285
+    const existingJobs = this.findExistingJobs();
286
+
287
+    return (
288
+      <Box flexDirection="row" marginBottom={30}>
289
+        <Box flexBasis="20%" flexShrink={0}>{name}</Box>
290
+        <Box flexBasis="60%" flexShrink={0}>
291
+          <FieldArray render={() => (
292
+            <SortableList jobs={jobs} onSortStart={this.onSortStart} onSortEnd={this.onSortEnd} useDragHandle={true} existingJobs={existingJobs} prefix={`${prefix}.jobs`} rowIndex={index} />
293
+          )} />
294
+          <Box onClick={this.addJob} style={{ cursor: 'pointer' }}>+ Nová úloha</Box>
295
+        </Box>
296
+        <Box flexBasis="10%" flexShrink={0} alignItems="center">
297
+          <Field type="checkbox" name={`${prefix}.preempt`} />
298
+        </Box>
299
+        <Box alignItems="flex-end"><button type="button" onClick={this.duplicate}>Duplikovať a spojiť pracovníka</button></Box>
300
+      </Box>
301
+    )
302
+  }
303
+}
304
+
305
+export default Form;
0 306
\ No newline at end of file
... ...
@@ -2,6 +2,7 @@ body {
2 2
   margin: 0;
3 3
   padding: 0;
4 4
   font-family: -apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
5
+  font-size: 14px;
5 6
 }
6 7
 
7 8
 svg * {
... ...
@@ -945,7 +945,7 @@ babel-register@^6.26.0:
945 945
     mkdirp "^0.5.1"
946 946
     source-map-support "^0.4.15"
947 947
 
948
-babel-runtime@6.26.0, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
948
+babel-runtime@6.26.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
949 949
   version "6.26.0"
950 950
   resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
951 951
   dependencies:
... ...
@@ -1436,7 +1436,7 @@ class-utils@^0.3.5:
1436 1436
     isobject "^3.0.0"
1437 1437
     static-extend "^0.1.1"
1438 1438
 
1439
-classnames@2.2.5, classnames@^2.2.5:
1439
+classnames@2.2.5, classnames@^2.2.4, classnames@^2.2.5:
1440 1440
   version "2.2.5"
1441 1441
   resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
1442 1442
 
... ...
@@ -2885,6 +2885,16 @@ form-data@~2.3.1:
2885 2885
     combined-stream "1.0.6"
2886 2886
     mime-types "^2.1.12"
2887 2887
 
2888
+formik@^0.11.11:
2889
+  version "0.11.11"
2890
+  resolved "https://registry.yarnpkg.com/formik/-/formik-0.11.11.tgz#4b02838133c0196b1ef443aa973766cd097ec4a5"
2891
+  dependencies:
2892
+    lodash.clonedeep "^4.5.0"
2893
+    lodash.isequal "4.5.0"
2894
+    lodash.topath "4.5.2"
2895
+    prop-types "^15.5.10"
2896
+    warning "^3.0.0"
2897
+
2888 2898
 forwarded@~0.1.2:
2889 2899
   version "0.1.2"
2890 2900
   resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
... ...
@@ -3476,6 +3486,12 @@ interpret@^1.0.0:
3476 3476
   version "1.1.0"
3477 3477
   resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
3478 3478
 
3479
+invariant@^2.2.1:
3480
+  version "2.2.4"
3481
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
3482
+  dependencies:
3483
+    loose-envify "^1.0.0"
3484
+
3479 3485
 invariant@^2.2.2:
3480 3486
   version "2.2.3"
3481 3487
   resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.3.tgz#1a827dfde7dcbd7c323f0ca826be8fa7c5e9d688"
... ...
@@ -4320,6 +4336,10 @@ lodash.camelcase@^4.3.0:
4320 4320
   version "4.3.0"
4321 4321
   resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
4322 4322
 
4323
+lodash.clonedeep@^4.5.0:
4324
+  version "4.5.0"
4325
+  resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
4326
+
4323 4327
 lodash.cond@^4.3.0:
4324 4328
   version "4.5.2"
4325 4329
   resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5"
... ...
@@ -4328,6 +4348,10 @@ lodash.defaults@^4.2.0:
4328 4328
   version "4.2.0"
4329 4329
   resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
4330 4330
 
4331
+lodash.isequal@4.5.0:
4332
+  version "4.5.0"
4333
+  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
4334
+
4331 4335
 lodash.memoize@^4.1.2:
4332 4336
   version "4.1.2"
4333 4337
   resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
... ...
@@ -4345,11 +4369,15 @@ lodash.templatesettings@^4.0.0:
4345 4345
   dependencies:
4346 4346
     lodash._reinterpolate "~3.0.0"
4347 4347
 
4348
+lodash.topath@4.5.2:
4349
+  version "4.5.2"
4350
+  resolved "https://registry.yarnpkg.com/lodash.topath/-/lodash.topath-4.5.2.tgz#3616351f3bba61994a0931989660bd03254fd009"
4351
+
4348 4352
 lodash.uniq@^4.5.0:
4349 4353
   version "4.5.0"
4350 4354
   resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
4351 4355
 
4352
-"lodash@>=3.5 <5", lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0, lodash@~4.17.4:
4356
+"lodash@>=3.5 <5", lodash@^4.12.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0, lodash@~4.17.4:
4353 4357
   version "4.17.5"
4354 4358
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
4355 4359
 
... ...
@@ -5468,7 +5496,7 @@ promise@^7.1.1:
5468 5468
   dependencies:
5469 5469
     asap "~2.0.3"
5470 5470
 
5471
-prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0:
5471
+prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0:
5472 5472
   version "15.6.1"
5473 5473
   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca"
5474 5474
   dependencies:
... ...
@@ -5476,6 +5504,10 @@ prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0:
5476 5476
     loose-envify "^1.3.1"
5477 5477
     object-assign "^4.1.1"
5478 5478
 
5479
+proptypes@^1.1.0:
5480
+  version "1.1.0"
5481
+  resolved "https://registry.yarnpkg.com/proptypes/-/proptypes-1.1.0.tgz#78b3828a5aa6bb1308939e0de3c6044dfd4bd239"
5482
+
5479 5483
 proxy-addr@~2.0.2:
5480 5484
   version "2.0.3"
5481 5485
   resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341"
... ...
@@ -5646,6 +5678,12 @@ react-error-overlay@^4.0.0:
5646 5646
   version "4.0.0"
5647 5647
   resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4"
5648 5648
 
5649
+react-input-autosize@^2.1.2:
5650
+  version "2.2.1"
5651
+  resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.1.tgz#ec428fa15b1592994fb5f9aa15bb1eb6baf420f8"
5652
+  dependencies:
5653
+    prop-types "^15.5.8"
5654
+
5649 5655
 react-measure@^2.0.0:
5650 5656
   version "2.0.2"
5651 5657
   resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-2.0.2.tgz#072a9a5fafc01dfbadc1fa5fb09fc351037f636c"
... ...
@@ -5660,6 +5698,14 @@ react-resize-detector@1.1.0:
5660 5660
   dependencies:
5661 5661
     prop-types "^15.5.10"
5662 5662
 
5663
+react-select@^1.2.1:
5664
+  version "1.2.1"
5665
+  resolved "https://registry.yarnpkg.com/react-select/-/react-select-1.2.1.tgz#a2fe58a569eb14dcaa6543816260b97e538120d1"
5666
+  dependencies:
5667
+    classnames "^2.2.4"
5668
+    prop-types "^15.5.8"
5669
+    react-input-autosize "^2.1.2"
5670
+
5663 5671
 react-smooth@1.0.0:
5664 5672
   version "1.0.0"
5665 5673
   resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-1.0.0.tgz#b29dbebddddb06d21b5b08962167fb9eac1897d8"
... ...
@@ -5669,6 +5715,15 @@ react-smooth@1.0.0:
5669 5669
     raf "^3.2.0"
5670 5670
     react-transition-group "^2.2.1"
5671 5671
 
5672
+react-sortable-hoc@^0.6.8:
5673
+  version "0.6.8"
5674
+  resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-0.6.8.tgz#b08562f570d7c41f6e393fca52879d2ebb9118e9"
5675
+  dependencies:
5676
+    babel-runtime "^6.11.6"
5677
+    invariant "^2.2.1"
5678
+    lodash "^4.12.0"
5679
+    prop-types "^15.5.7"
5680
+
5672 5681
 react-transition-group@^2.2.1:
5673 5682
   version "2.2.1"
5674 5683
   resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.2.1.tgz#e9fb677b79e6455fd391b03823afe84849df4a10"
... ...
@@ -6951,7 +7006,7 @@ uuid@^2.0.2:
6951 6951
   version "2.0.3"
6952 6952
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
6953 6953
 
6954
-uuid@^3.0.0, uuid@^3.1.0:
6954
+uuid@^3.0.0, uuid@^3.1.0, uuid@^3.2.1:
6955 6955
   version "3.2.1"
6956 6956
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
6957 6957