hippo-fw 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/.nvmrc +2 -0
  3. data/.travis.yml +1 -1
  4. data/client/hippo/access/login-dialog.jsx +3 -5
  5. data/client/hippo/boot.jsx +2 -2
  6. data/client/hippo/components/asset.jsx +0 -1
  7. data/client/hippo/components/data-list.jsx +16 -15
  8. data/client/hippo/components/data-list/data-list.scss +10 -0
  9. data/client/hippo/components/data-table.jsx +14 -14
  10. data/client/hippo/components/data-table/header-cell.jsx +0 -1
  11. data/client/hippo/components/data-table/table-styles.scss +7 -0
  12. data/client/hippo/components/date-time.jsx +19 -16
  13. data/client/hippo/components/date-time/calendar.jsx +5 -7
  14. data/client/hippo/components/date-time/date-time-drop.jsx +0 -2
  15. data/client/hippo/components/date-time/time.jsx +0 -1
  16. data/client/hippo/components/form.jsx +1 -1
  17. data/client/hippo/components/form/{model.js → api.js} +25 -7
  18. data/client/hippo/components/form/fields.jsx +12 -11
  19. data/client/hippo/components/form/fields/date-wrapper.jsx +1 -1
  20. data/client/hippo/components/form/fields/form-field.scss +9 -1
  21. data/client/hippo/components/form/fields/label.jsx +14 -0
  22. data/client/hippo/components/form/fields/select-wrapper.jsx +2 -3
  23. data/client/hippo/components/form/wrapper.jsx +1 -3
  24. data/client/hippo/components/icon.jsx +2 -69
  25. data/client/hippo/components/master-detail.jsx +0 -2
  26. data/client/hippo/components/network-activity-overlay.jsx +1 -4
  27. data/client/hippo/components/query-builder.jsx +15 -16
  28. data/client/hippo/components/record-finder.jsx +2 -5
  29. data/client/hippo/components/record-finder/query-layer.jsx +1 -5
  30. data/client/hippo/components/screen.jsx +7 -3
  31. data/client/hippo/components/text-editor.jsx +2 -8
  32. data/client/hippo/components/tool-tip.jsx +2 -3
  33. data/client/hippo/components/warning-notification.jsx +3 -3
  34. data/client/hippo/lib/date-range.js +28 -0
  35. data/client/hippo/lib/util.js +6 -0
  36. data/client/hippo/models/asset.js +6 -3
  37. data/client/hippo/models/config.js +1 -1
  38. data/client/hippo/models/pub_sub.js +12 -7
  39. data/client/hippo/models/pub_sub/channel.js +6 -4
  40. data/client/hippo/models/query.js +19 -4
  41. data/client/hippo/models/query/array-result.js +9 -8
  42. data/client/hippo/models/query/clause.js +21 -13
  43. data/client/hippo/models/query/field.js +7 -2
  44. data/client/hippo/models/query/info.js +7 -3
  45. data/client/hippo/models/sync.js +11 -14
  46. data/client/hippo/react/Root.jsx +1 -2
  47. data/client/hippo/react/{DefaultComponentNotFound.jsx → component-not-found.jsx} +1 -3
  48. data/client/hippo/screens/index.js +6 -2
  49. data/client/hippo/screens/system-settings.jsx +10 -6
  50. data/client/hippo/screens/system-settings/mailer-config.jsx +0 -2
  51. data/client/hippo/screens/system-settings/tenant.jsx +1 -4
  52. data/client/hippo/screens/user-management.jsx +0 -1
  53. data/client/hippo/screens/user-management/edit-form.jsx +1 -2
  54. data/client/hippo/workspace/index.jsx +21 -12
  55. data/client/hippo/workspace/menu-group.jsx +4 -7
  56. data/client/hippo/workspace/menu-option.jsx +1 -3
  57. data/client/hippo/workspace/menu.jsx +29 -11
  58. data/client/hippo/workspace/navbar.jsx +1 -2
  59. data/client/hippo/workspace/root-view.jsx +5 -2
  60. data/client/hippo/workspace/screen.jsx +2 -3
  61. data/client/hippo/workspace/styles.scss +17 -0
  62. data/command-reference-files/screen/client/appy-app/screens/ready-set-go.jsx +2 -1
  63. data/db/migrate/20170530120004_create_users.rb +1 -1
  64. data/hippo-fw.gemspec +3 -2
  65. data/lib/hippo/api/cable.rb +13 -13
  66. data/lib/hippo/api/controller_base.rb +1 -0
  67. data/lib/hippo/api/handlers/tenant.rb +1 -1
  68. data/lib/hippo/api/handlers/user_session.rb +2 -1
  69. data/lib/hippo/api/helper_methods.rb +4 -1
  70. data/lib/hippo/api/pub_sub.rb +7 -6
  71. data/lib/hippo/api/to_json.rb +1 -1
  72. data/lib/hippo/api/updates.rb +2 -0
  73. data/lib/hippo/command/console.rb +11 -3
  74. data/lib/hippo/command/jest.rb +2 -0
  75. data/lib/hippo/configuration.rb +4 -7
  76. data/lib/hippo/rake_tasks.rb +1 -1
  77. data/lib/hippo/screen.rb +31 -93
  78. data/lib/hippo/screen/definition.rb +76 -0
  79. data/lib/hippo/screen/group.rb +26 -0
  80. data/lib/hippo/spec_helper.rb +3 -0
  81. data/lib/hippo/system_settings.rb +6 -0
  82. data/lib/hippo/user.rb +11 -3
  83. data/lib/hippo/version.rb +1 -1
  84. data/package-lock.json +419 -533
  85. data/package.json +32 -30
  86. data/spec/client/access/login-dialog.spec.jsx +4 -5
  87. data/spec/client/components/__snapshots__/query-builder.spec.jsx.snap +1 -1
  88. data/spec/client/components/__snapshots__/record-finder.spec.jsx.snap +72 -0
  89. data/spec/client/components/asset.spec.jsx +2 -6
  90. data/spec/client/components/data-list.spec.jsx +2 -6
  91. data/spec/client/components/data-table.spec.jsx +3 -5
  92. data/spec/client/components/date-time.spec.jsx +1 -1
  93. data/spec/client/components/form.spec.jsx +2 -2
  94. data/spec/client/components/master-detail.spec.jsx +1 -2
  95. data/spec/client/components/network-activity-overlay.spec.jsx +2 -3
  96. data/spec/client/components/query-builder.spec.jsx +3 -6
  97. data/spec/client/components/record-finder.spec.jsx +4 -4
  98. data/spec/client/models/pub_sub.spec.js +3 -1
  99. data/spec/client/models/query.spec.js +4 -9
  100. data/spec/client/screens/system-settings-tenants.spec.jsx +1 -1
  101. data/spec/client/screens/system-settings.spec.jsx +1 -4
  102. data/spec/client/workspace/__snapshots__/menu.spec.jsx.snap +15 -20
  103. data/spec/client/workspace/menu.spec.jsx +1 -2
  104. data/spec/server/api/user_sessions_spec.rb +15 -0
  105. data/templates/client/screens/screen.jsx +2 -1
  106. data/views/hippo_root_view.erb +1 -0
  107. metadata +30 -52
  108. data/client/hippo/components/calendar/Calendar.jsx +0 -25
  109. data/client/hippo/components/calendar/index.js +0 -3
  110. data/client/hippo/components/calendar/styles.scss +0 -3
  111. data/client/hippo/components/shared/AssetsListing.jsx +0 -23
  112. data/client/hippo/components/shared/Checkbox.jsx +0 -49
  113. data/client/hippo/components/shared/CountBadge.jsx +0 -13
  114. data/client/hippo/components/shared/DateTime.jsx +0 -58
  115. data/client/hippo/components/shared/DisplayValue.jsx +0 -15
  116. data/client/hippo/components/shared/ErrorDisplay.jsx +0 -37
  117. data/client/hippo/components/shared/FieldMixin.jsx +0 -254
  118. data/client/hippo/components/shared/FieldSet.jsx +0 -52
  119. data/client/hippo/components/shared/FieldWrapper.jsx +0 -94
  120. data/client/hippo/components/shared/FormGroup.jsx +0 -41
  121. data/client/hippo/components/shared/GenericField.jsx +0 -7
  122. data/client/hippo/components/shared/IconButton.jsx +0 -13
  123. data/client/hippo/components/shared/ImageAsset.jsx +0 -78
  124. data/client/hippo/components/shared/IndeterminateCheckbox.jsx +0 -31
  125. data/client/hippo/components/shared/Input.jsx +0 -16
  126. data/client/hippo/components/shared/InputFieldMixin.jsx +0 -78
  127. data/client/hippo/components/shared/JobProgress.jsx +0 -46
  128. data/client/hippo/components/shared/NumberInput.jsx +0 -37
  129. data/client/hippo/components/shared/PanelHeader.jsx +0 -15
  130. data/client/hippo/components/shared/RadioField.jsx +0 -33
  131. data/client/hippo/components/shared/ResizeSensor.jsx +0 -18
  132. data/client/hippo/components/shared/ScreenWrapper.jsx +0 -17
  133. data/client/hippo/components/shared/TextArea.jsx +0 -19
  134. data/client/hippo/components/shared/Throbber.jsx +0 -8
  135. data/client/hippo/components/shared/ToggleField.jsx +0 -2
  136. data/client/hippo/components/shared/Tooltip.jsx +0 -23
  137. data/client/hippo/components/shared/fields.scss +0 -58
  138. data/client/hippo/components/shared/fieldset.scss +0 -27
  139. data/client/hippo/components/shared/image-asset.scss +0 -53
  140. data/client/hippo/components/shared/index.js +0 -5
  141. data/client/hippo/components/shared/overlay.scss +0 -83
  142. data/client/hippo/components/shared/resize-sensor.scss +0 -30
  143. data/client/hippo/components/shared/styles.scss +0 -64
  144. data/client/hippo/components/shared/throbber.scss +0 -53
  145. data/client/hippo/fonts/fontawesome-webfont.woff +0 -0
  146. data/client/hippo/fonts/fontawesome-webfont.woff2 +0 -0
  147. data/client/hippo/workspace/content.jsx +0 -22
  148. data/client/hippo/workspace/tabs.jsx +0 -60
  149. data/client/hippo/workspace/viewport.jsx +0 -82
  150. data/spec/client/screens/__snapshots__/tabs.spec.jsx.snap +0 -127
  151. data/spec/client/screens/tabs.spec.jsx +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8a86a77e5eb0041425dcc05d9b6d8efb2c304a99
4
- data.tar.gz: df658e7e5eb832884c88606575617b4247aa4e89
3
+ metadata.gz: ea4e1fab04ebb80ec4cadd61c6eb529e71cb9da7
4
+ data.tar.gz: 2f8567b02e13defacc31d703b526739b6f964551
5
5
  SHA512:
6
- metadata.gz: 3df81f86cd6613d3ad71237534c7c997bac329470697ab6a83af8182e155059d1ee99d0e54298d45352a81ebfc137793560116af7271537c87cc2b62dba3e388
7
- data.tar.gz: 566662660f26bf8cbb0dd4c31a4afdab9d1da1b53ca380bdeff349a9e7e7f16dab0cc18455f07f85a24c9e7c190c5b773a8a1f8b2f956d3bce701a174d9060ba
6
+ metadata.gz: 8007c42f669e7e8dde8b2696fa9a5e2d10a2690c4d7cff9a32e69e214429375c750b6ebbbccdeab401c10bf4f7d1f52f636df2ae5938ec6ee93880e699ef60b8
7
+ data.tar.gz: 7e9cc5649badcc65a8ec65ceae4a5e6f960ca35690c8f4656b911f9e41a8267558ff42744150307284a310631306b3e04aee8a4584c30a12330dc5cb130754d8
data/.nvmrc ADDED
@@ -0,0 +1,2 @@
1
+ v8
2
+
data/.travis.yml CHANGED
@@ -17,7 +17,7 @@ env:
17
17
  global:
18
18
  - DATABASE_URL=postgres://travis@127.0.0.1:5432/travis
19
19
  - REDIS_URL=redis://localhost:6379
20
- - TRAVIS_NODE_VERSION="7"
20
+ - TRAVIS_NODE_VERSION="8"
21
21
  before_install:
22
22
  - nvm install $TRAVIS_NODE_VERSION
23
23
  - npm install
@@ -9,16 +9,15 @@ import User from '../user';
9
9
 
10
10
  @observer
11
11
  export default class LoginDialog extends React.Component {
12
-
13
12
  constructor() {
14
13
  super();
15
14
  bindAll(this, 'attemptLogin');
16
15
  }
17
16
 
18
17
  attemptLogin({ username, password }) {
19
- User.attemptLogin(username, password)/* .then((session)=> {
18
+ User.attemptLogin(username, password);/* .then((session)=> {
20
19
  if session.isValid
21
- });*/
20
+ }); */
22
21
  }
23
22
 
24
23
  render() {
@@ -32,7 +31,6 @@ export default class LoginDialog extends React.Component {
32
31
  secondaryText={User.lastServerMessage}
33
32
  />
34
33
  </Layer>
35
- )
34
+ );
36
35
  }
37
-
38
36
  }
@@ -6,6 +6,8 @@ import { AppContainer } from 'react-hot-loader';
6
6
  import { onBoot } from './models/pub_sub';
7
7
  import './extensions/hippo';
8
8
 
9
+ // react-tap-event-plugin is required for material-ui which is used by ory-editor-ui
10
+ require('react-tap-event-plugin')();
9
11
  const Workspace = require('hippo/workspace').default;
10
12
 
11
13
  let Root;
@@ -33,8 +35,6 @@ whenDomReady().then(() => {
33
35
  delay(() => {
34
36
  onBoot();
35
37
  loading.parentNode.removeChild(loading);
36
-
37
38
  }, 400);
38
-
39
39
  }
40
40
  });
@@ -15,7 +15,6 @@ import './asset.scss';
15
15
 
16
16
  @observer
17
17
  export default class Asset extends React.PureComponent {
18
-
19
18
  static defaultProps = {
20
19
  label: '',
21
20
  className: '',
@@ -1,9 +1,10 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { bindAll } from 'lodash';
4
- import { observable } from 'mobx';
3
+ import { partial } from 'lodash';
4
+ import { observable, action } from 'mobx';
5
5
  import { observer } from 'mobx-react';
6
-
6
+ import { autobind } from 'core-decorators';
7
+ import cn from 'classnames';
7
8
  import Box from 'grommet/components/Box';
8
9
 
9
10
  import {
@@ -12,10 +13,10 @@ import {
12
13
  import 'react-virtualized/styles.css';
13
14
 
14
15
  import Query from '../models/query';
16
+ import './data-list/data-list.scss';
15
17
 
16
18
  @observer
17
19
  export default class DataList extends React.Component {
18
-
19
20
  static defaultProps = {
20
21
  rowHeight: 40,
21
22
  }
@@ -33,32 +34,29 @@ export default class DataList extends React.Component {
33
34
  constructor(props) {
34
35
  super(props);
35
36
  this.query = props.query;
36
- bindAll(this,
37
- 'rowRenderer',
38
- 'isRowLoaded',
39
- 'loadMoreRows',
40
- );
41
37
  }
42
38
 
43
39
  componentWillMount() { this.query.open(); }
44
40
  componentWillUnmount() { this.query.close(); }
45
41
 
42
+ @autobind
46
43
  rowRenderer(props) {
47
- const { rowComponent: Row } = this.props;
44
+ const { rowComponent: Row, onRowClick } = this.props;
48
45
  const row = this.query.results.rows[props.index];
49
46
  return (
50
- <Row {...props} row={row} />
47
+ <Row {...props} row={row} onClick={partial(onRowClick, props.index, row)} />
51
48
  );
52
49
  }
53
50
 
51
+ @autobind
54
52
  isRowLoaded({ index }) {
55
53
  return (
56
- this.query.results.rows.length > index
57
- && !this.query.results.isRowLoading(index)
58
- && this.query.results.rows[index]
54
+ (this.query.results.rows.length > index) &&
55
+ (this.query.results.isRowLoading(index) || this.query.results.rows[index])
59
56
  );
60
57
  }
61
58
 
59
+ @action.bound
62
60
  loadMoreRows({ startIndex: start, stopIndex }) {
63
61
  const limit = (stopIndex + 1) - start;
64
62
  return this.query.results.fetch({ start, limit });
@@ -72,7 +70,10 @@ export default class DataList extends React.Component {
72
70
  const { query } = this;
73
71
  const { rowHeight, rowRenderer, ...listProps } = this.props;
74
72
  return (
75
- <Box className="data-list" align='stretch' direction='row' flex>
73
+ <Box
74
+ className={cn('data-list', { selectable: this.props.onRowClick })}
75
+ align='stretch' direction='row' flex
76
+ >
76
77
  <InfiniteLoader
77
78
  keyChange={query.results.updateKey}
78
79
  minimumBatchSize={query.pageSize}
@@ -0,0 +1,10 @@
1
+ @import "~grommet/scss/grommet-core/settings";
2
+ #hippo-root {
3
+ .data-list {
4
+ &.selectable {
5
+ .ReactVirtualized__Grid__innerScrollContainer {
6
+ cursor: pointer;
7
+ }
8
+ }
9
+ }
10
+ }
@@ -15,7 +15,7 @@ import './data-table/table-styles.scss';
15
15
  import Query from '../models/query';
16
16
  import HeaderCell from './data-table/header-cell';
17
17
 
18
- function renderEditTriangle({ rowIndex, columnData: { onEdit }}) {
18
+ function renderEditTriangle({ rowIndex, columnData: { onEdit } }) {
19
19
  return (
20
20
  <Button
21
21
  plain icon={<NextIcon />}
@@ -26,7 +26,6 @@ function renderEditTriangle({ rowIndex, columnData: { onEdit }}) {
26
26
 
27
27
  @observer
28
28
  export default class DataTable extends React.Component {
29
-
30
29
  static defaultProps = {
31
30
  canCreate: false,
32
31
  editRowIndex: null,
@@ -49,12 +48,12 @@ export default class DataTable extends React.Component {
49
48
  super(props);
50
49
  this.query = props.query;
51
50
  bindAll(this,
52
- 'rowRenderer',
53
- 'rowAtIndex',
54
- 'calculateRowHeight',
55
- 'isRowLoaded',
56
- 'loadMoreRows',
57
- 'headerRenderer',
51
+ 'rowRenderer',
52
+ 'rowAtIndex',
53
+ 'calculateRowHeight',
54
+ 'isRowLoaded',
55
+ 'loadMoreRows',
56
+ 'headerRenderer',
58
57
  );
59
58
  this.editIndex = props.editRowIndex;
60
59
  autorun(() => {
@@ -111,7 +110,7 @@ export default class DataTable extends React.Component {
111
110
  if (index < 0) {
112
111
  return 'header';
113
112
  }
114
- return index % 2 === 0 ? 'e' : 'o';
113
+ return 0 === index % 2 ? 'e' : 'o';
115
114
  }
116
115
 
117
116
  @action.bound
@@ -130,7 +129,7 @@ export default class DataTable extends React.Component {
130
129
  columnData: f,
131
130
  dataKey: f.dataIndex || f.id,
132
131
  headerRenderer: this.headerRenderer,
133
- }, pick(f, 'width', 'label', 'flexGrow', 'flexShrink')),
132
+ }, pick(f, 'width', 'label', 'flexGrow', 'flexShrink', 'cellRenderer')),
134
133
  );
135
134
  if (this.props.editor) {
136
135
  definitions.unshift({
@@ -189,9 +188,8 @@ export default class DataTable extends React.Component {
189
188
 
190
189
  isRowLoaded({ index }) {
191
190
  return (
192
- this.query.results.rows.length > index
193
- && !this.query.results.isRowLoading(index)
194
- && this.query.results.rows[index]
191
+ (this.query.results.rows.length > index) &&
192
+ (this.query.results.isRowLoading(index) || this.query.results.rows[index])
195
193
  );
196
194
  }
197
195
 
@@ -222,7 +220,9 @@ export default class DataTable extends React.Component {
222
220
  <Table
223
221
  height={height}
224
222
  width={width}
225
- ref={(table) => { registerChild(table); this.tableRef = table; }}
223
+ ref={(table) => {
224
+ registerChild(table); this.tableRef = table;
225
+ }}
226
226
  rowHeight={this.calculateRowHeight}
227
227
  rowGetter={this.rowAtIndex}
228
228
  estimatedRowSize={40}
@@ -90,5 +90,4 @@ export default class SortingHeaderCell extends React.Component {
90
90
  }
91
91
  return label;
92
92
  }
93
-
94
93
  }
@@ -29,6 +29,13 @@
29
29
  &.o {
30
30
  background-color: lighten($border-color, 75%);
31
31
  }
32
+
33
+ }
34
+ &.selectable {
35
+ .ReactVirtualized__Table__row {
36
+ cursor: pointer;
37
+ }
32
38
  }
39
+
33
40
  }
34
41
  }
@@ -20,7 +20,6 @@ const CLASS_ROOT = CSSClassnames.DATE_TIME;
20
20
 
21
21
  @observer
22
22
  export default class DateTime extends React.Component {
23
-
24
23
  static propTypes = {
25
24
  value: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired,
26
25
  onChange: PropTypes.func.isRequired,
@@ -38,6 +37,7 @@ export default class DateTime extends React.Component {
38
37
 
39
38
  @observable drop;
40
39
  @observable dateValue;
40
+
41
41
  @observable editingValue
42
42
 
43
43
  @action.bound
@@ -92,11 +92,7 @@ export default class DateTime extends React.Component {
92
92
  }
93
93
 
94
94
  @computed get value() {
95
- return this.dateValue || moment(this.props.value || new Date());
96
- }
97
-
98
- set value(value) {
99
- this.dateValue = value;
95
+ return this.dateValue || this.props.value ? moment(this.props.value) : '';
100
96
  }
101
97
 
102
98
  @action.bound
@@ -106,11 +102,13 @@ export default class DateTime extends React.Component {
106
102
 
107
103
  @action.bound
108
104
  onInputBlur() {
109
- if (this.editingValue) {
110
- this.value = moment(this.editingValue, this.props.format);
111
- delete this.editingValue;
112
- this.onForceClose();
113
- this.props.onChange(this.value);
105
+ if (!this.editingValue) { return; }
106
+ const value = moment(this.editingValue, this.props.format);
107
+ this.editingValue = '';
108
+ this.onForceClose();
109
+ if (value.isValid()) {
110
+ this.props.onChange(value);
111
+ this.dateValue = value;
114
112
  }
115
113
  }
116
114
 
@@ -125,8 +123,9 @@ export default class DateTime extends React.Component {
125
123
 
126
124
  @action.bound
127
125
  onDateChange(date) {
128
- this.value = moment(date);
129
- this.props.onChange(this.value.toDate());
126
+ const value = moment(date);
127
+ this.props.onChange(value.toDate());
128
+ this.dateValue = value;
130
129
  }
131
130
 
132
131
  renderDrop() {
@@ -139,9 +138,14 @@ export default class DateTime extends React.Component {
139
138
  );
140
139
  }
141
140
 
141
+ @computed get inputValue() {
142
+ if (this.editingValue) { return this.editingValue; }
143
+ if (this.value) { return this.value.format(this.props.format); }
144
+ return '';
145
+ }
146
+
142
147
  render() {
143
- const { props: { format, dateOnly } } = this;
144
- const inputValue = this.editingValue || this.value.format(format);
148
+ const { inputValue, props: { format, dateOnly } } = this;
145
149
  const Icon = dateOnly ? CalendarIcon : ClockIcon;
146
150
 
147
151
  return (
@@ -165,5 +169,4 @@ export default class DateTime extends React.Component {
165
169
  </div>
166
170
  );
167
171
  }
168
-
169
172
  }
@@ -12,12 +12,12 @@ import LinkPreviousIcon from 'grommet/components/icons/base/LinkPrevious';
12
12
  import LinkNextIcon from 'grommet/components/icons/base/LinkNext';
13
13
 
14
14
  const Day = ({ i, w, d, className, ...props }) => {
15
- const prevMonth = w === 0 && i > 7;
15
+ const prevMonth = 0 === w && i > 7;
16
16
  const nextMonth = w >= 4 && i <= 14;
17
17
  const cls = cx(className, {
18
18
  'prev-month': prevMonth,
19
19
  'next-month': nextMonth,
20
- 'current-day': !prevMonth && !nextMonth && i === d
20
+ 'current-day': !prevMonth && !nextMonth && i === d,
21
21
  });
22
22
 
23
23
  return <td className={cls} {...props}>{i}</td>;
@@ -26,7 +26,6 @@ const Day = ({ i, w, d, className, ...props }) => {
26
26
 
27
27
  @observer
28
28
  export default class Calendar extends React.PureComponent {
29
-
30
29
  static propTypes = {
31
30
  moment: PropTypes.object.isRequired,
32
31
  onChange: PropTypes.func.isRequired,
@@ -34,14 +33,13 @@ export default class Calendar extends React.PureComponent {
34
33
 
35
34
  @action.bound
36
35
  selectDate(i, w) {
37
- const prevMonth = w === 0 && i > 7;
36
+ const prevMonth = 0 === w && i > 7;
38
37
  const nextMonth = w >= 4 && i <= 14;
39
38
  const m = this.props.moment;
40
39
 
41
40
  m.date(i);
42
41
  if (prevMonth) m.subtract(1, 'month');
43
42
  if (nextMonth) m.add(1, 'month');
44
-
45
43
  this.props.onChange(m);
46
44
  this.forceUpdate();
47
45
  }
@@ -67,9 +65,9 @@ export default class Calendar extends React.PureComponent {
67
65
  const d2 = m.clone().date(1).day();
68
66
  const d3 = m.clone().endOf('month').date();
69
67
  const days = [].concat(
70
- range(d1 - d2 + 1, d1 + 1),
68
+ range((d1 - d2) + 1, d1 + 1),
71
69
  range(1, d3 + 1),
72
- range(1, 42 - d3 - d2 + 1),
70
+ range(1, ((42 - d3) - d2) + 1),
73
71
  );
74
72
  const weeks = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
75
73
 
@@ -16,7 +16,6 @@ const CLASS_ROOT = 'date-time';
16
16
 
17
17
  @observer
18
18
  export default class DateTimeDrop extends React.Component {
19
-
20
19
  static propTypes = {
21
20
  value: PropTypes.object.isRequired,
22
21
  onChange: PropTypes.func.isRequired,
@@ -73,5 +72,4 @@ export default class DateTimeDrop extends React.Component {
73
72
  </Box>
74
73
  );
75
74
  }
76
-
77
75
  }
@@ -18,7 +18,6 @@ function getDigits(ev) {
18
18
 
19
19
  @observer
20
20
  export default class TimeSelector extends React.PureComponent {
21
-
22
21
  static propTypes = {
23
22
  moment: PropTypes.object.isRequired,
24
23
  onChange: PropTypes.func.isRequired,
@@ -8,7 +8,7 @@ import { isBlank } from '../lib/util';
8
8
 
9
9
  export Form from './form/wrapper';
10
10
  export Field from './form/fields';
11
- export { FormField, FormState } from './form/model';
11
+ export { FormField, FormState } from './form/api';
12
12
 
13
13
  function buildTest(options, defaultOptions) {
14
14
  return merge({}, defaultOptions, options);
@@ -3,7 +3,7 @@
3
3
  }] */
4
4
  import { observable, computed, when, action } from 'mobx';
5
5
  import {
6
- pick, isFunction, mapValues, every, get, filter, isNil, each,
6
+ pick, isFunction, mapValues, every, get, set, filter, isNil, each,
7
7
  } from 'lodash';
8
8
 
9
9
  export class FormField {
@@ -38,6 +38,13 @@ export class FormField {
38
38
  this.value = updatedValue;
39
39
  }
40
40
 
41
+ @action.bound
42
+ exposeError() {
43
+ if (!this.isValid) {
44
+ this.isTouched = true;
45
+ }
46
+ }
47
+
41
48
  @action.bound
42
49
  onBlur() {
43
50
  this.isTouched = true;
@@ -102,6 +109,16 @@ export class FormState {
102
109
  return !every(this.fields.values(), { isTouched: false });
103
110
  }
104
111
 
112
+ @action
113
+ exposeErrors() {
114
+ this.fields.forEach(field => field.exposeError());
115
+ }
116
+
117
+ @action
118
+ reset() {
119
+ this.fields.forEach(field => field.reset());
120
+ }
121
+
105
122
  get(path, defaultValue) {
106
123
  const [name, ...rest] = path.split('.');
107
124
  const field = this.fields.get(name);
@@ -112,14 +129,15 @@ export class FormState {
112
129
  return field;
113
130
  }
114
131
 
115
- reset() {
116
- this.fields.forEach(field => field.reset());
117
- }
118
-
132
+ @action
119
133
  set(values) {
120
- this.fields.forEach((field, name) => (field.value = isNil(values[name]) ? '' : values[name]));
134
+ this.fields.forEach((field, name) => {
135
+ const value = get(values, name);
136
+ field.value = isNil(value) ? '' : value;
137
+ });
121
138
  }
122
139
 
140
+ @action
123
141
  setFromModel(model) {
124
142
  if (get(model, 'syncInProgress.isFetch')) {
125
143
  when(
@@ -132,7 +150,7 @@ export class FormState {
132
150
  }
133
151
 
134
152
  persistTo(model) {
135
- this.fields.forEach((field, name) => (model[name] = field.value));
153
+ this.fields.forEach((field, name) => (set(model, name, field.value)));
136
154
  return Promise.resolve(model);
137
155
  }
138
156
  }