hippo-fw 0.9.5 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }