hippo-fw 0.9.4 → 0.9.5

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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +2 -3
  4. data/Gemfile +1 -1
  5. data/client/hippo/__mocks__/config.js +4 -4
  6. data/client/hippo/boot.jsx +1 -0
  7. data/client/hippo/components/asset.jsx +4 -4
  8. data/client/hippo/components/date-time.jsx +169 -0
  9. data/client/hippo/components/date-time.scss +38 -0
  10. data/client/hippo/components/date-time/calendar.jsx +115 -0
  11. data/client/hippo/components/date-time/date-time-drop.jsx +77 -0
  12. data/client/hippo/components/date-time/date-time.scss +157 -0
  13. data/client/hippo/components/date-time/time.jsx +120 -0
  14. data/client/hippo/components/form/fields/date-wrapper.jsx +4 -3
  15. data/client/hippo/components/form/model.js +0 -2
  16. data/client/hippo/components/text-editor.jsx +85 -0
  17. data/client/hippo/components/text-editor/display-modes/Button.jsx +17 -0
  18. data/client/hippo/components/text-editor/display-modes/SaveState.jsx +17 -0
  19. data/client/hippo/components/text-editor/display-modes/ToggleEdit.jsx +22 -0
  20. data/client/hippo/components/text-editor/display-modes/ToggleInsert.jsx +21 -0
  21. data/client/hippo/components/text-editor/display-modes/ToggleLayout.jsx +21 -0
  22. data/client/hippo/components/text-editor/display-modes/TogglePreview.jsx +21 -0
  23. data/client/hippo/components/text-editor/display-modes/ToggleResize.jsx +21 -0
  24. data/client/hippo/components/text-editor/display-modes/index.css +0 -0
  25. data/client/hippo/components/text-editor/display-modes/index.js +30 -0
  26. data/client/hippo/components/text-editor/image-plugin/Component/Display/index.js +80 -0
  27. data/client/hippo/components/text-editor/image-plugin/Component/Form/index.js +40 -0
  28. data/client/hippo/components/text-editor/image-plugin/Component/index.js +16 -0
  29. data/client/hippo/components/text-editor/image-plugin/Component/index.scss +0 -0
  30. data/client/hippo/components/text-editor/image-plugin/index.js +32 -0
  31. data/client/hippo/components/text-editor/image-plugin/index.scss +25 -0
  32. data/client/hippo/components/text-editor/plugins.js +22 -0
  33. data/client/hippo/components/text-editor/renderer.jsx +37 -0
  34. data/client/hippo/components/text-editor/text-editor.scss +49 -0
  35. data/client/hippo/extensions/base.js +5 -2
  36. data/client/hippo/extensions/hippo.js +5 -2
  37. data/client/hippo/extensions/index.js +9 -3
  38. data/client/hippo/lib/__mocks__/request-assets.js +2 -2
  39. data/client/hippo/lib/bootstrap.js +0 -1
  40. data/client/hippo/lib/smooth-scroll.js +0 -1
  41. data/client/hippo/lib/util.js +4 -4
  42. data/client/hippo/models/asset.js +43 -23
  43. data/client/hippo/models/base.js +1 -2
  44. data/client/hippo/models/config.js +0 -1
  45. data/client/hippo/models/decorators.js +3 -3
  46. data/client/hippo/models/pub_sub.js +2 -5
  47. data/client/hippo/models/pub_sub/channel.js +0 -1
  48. data/client/hippo/models/query.js +0 -1
  49. data/client/hippo/models/query/array-result.js +0 -1
  50. data/client/hippo/models/query/clause.js +0 -1
  51. data/client/hippo/models/query/field.js +0 -1
  52. data/client/hippo/models/query/info.js +0 -3
  53. data/client/hippo/models/query/operator.js +0 -2
  54. data/client/hippo/models/query/result.js +0 -1
  55. data/client/hippo/models/sync.js +1 -1
  56. data/client/hippo/models/system-setting.js +0 -2
  57. data/client/hippo/models/tenant.js +0 -1
  58. data/client/hippo/screens/definition.js +0 -2
  59. data/client/hippo/screens/group.js +0 -2
  60. data/client/hippo/screens/instance.js +0 -3
  61. data/client/hippo/screens/system-settings/mailer-config.jsx +0 -3
  62. data/client/hippo/styles/global.scss +3 -0
  63. data/client/hippo/testing/mocks/fetch.js +6 -6
  64. data/client/hippo/user.js +4 -4
  65. data/client/hippo/workspace/index.jsx +12 -5
  66. data/client/hippo/workspace/root-view.jsx +10 -0
  67. data/command-reference-files/initial/.gitignore +1 -0
  68. data/command-reference-files/initial/Gemfile +1 -1
  69. data/command-reference-files/initial/client/appy-app/extension.js +4 -0
  70. data/command-reference-files/initial/config/webpack.config.js +25 -23
  71. data/config/routes.rb +4 -1
  72. data/config/webpack.config.js +1 -2
  73. data/hippo-fw.gemspec +4 -2
  74. data/lib/hippo.rb +0 -1
  75. data/lib/hippo/api/handlers/asset.rb +9 -0
  76. data/lib/hippo/api/updates.rb +2 -2
  77. data/lib/hippo/configuration.rb +0 -4
  78. data/lib/hippo/db.rb +2 -2
  79. data/lib/hippo/{rails.rb → db/fake_rails.rb} +0 -0
  80. data/lib/hippo/extension.rb +1 -2
  81. data/lib/hippo/mailer.rb +1 -0
  82. data/lib/hippo/spec_helper.rb +1 -0
  83. data/lib/hippo/version.rb +1 -1
  84. data/package-lock.json +626 -68
  85. data/package.json +14 -13
  86. data/spec/client/access/login-dialog.spec.jsx +1 -0
  87. data/spec/client/components/asset.spec.jsx +1 -2
  88. data/spec/client/components/date-time.spec.jsx +20 -0
  89. data/spec/client/extension/base.spec.js +0 -2
  90. data/spec/client/models/base.spec.js +4 -4
  91. data/spec/client/models/query.spec.js +2 -2
  92. data/spec/client/models/sync.spec.js +1 -1
  93. data/spec/client/screens/system-settings.spec.jsx +2 -1
  94. data/spec/client/setup.js +3 -0
  95. data/spec/client/test-models.js +0 -2
  96. data/spec/server/api/tenant_change_spec.rb +1 -1
  97. data/spec/server/api/tenant_isolation_spec.rb +6 -3
  98. data/spec/server/concerns/api_path_spec.rb +2 -2
  99. data/templates/.gitignore +1 -0
  100. data/templates/client/extension.js +4 -0
  101. data/templates/config/webpack.config.js +25 -23
  102. metadata +48 -12
  103. data/client/hippo/lib/pub_sub.js +0 -34
  104. data/client/hippo/react/viewport-root.jsx +0 -44
  105. data/spec/client/components/__snapshots__/asset.spec.jsx.snap +0 -48
  106. data/spec/client/screens/__snapshots__/system-settings.spec.jsx.snap +0 -443
  107. data/templates/gitignore +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 66252f602687cd15c345fe869696110e2b106c45
4
- data.tar.gz: 6e63cb8121ff3b3a7b5d4186306755648397342f
3
+ metadata.gz: 8a86a77e5eb0041425dcc05d9b6d8efb2c304a99
4
+ data.tar.gz: df658e7e5eb832884c88606575617b4247aa4e89
5
5
  SHA512:
6
- metadata.gz: 166aadffc4273278372aad7b702ddb0baac76f106afa7482be135aef026c5c0f3071ae6fa7dbffa5b3ff9667b81620b43356b64615a393d9d328156ae22e2a8a
7
- data.tar.gz: f9b71478268619454b76bd254e45c5947274f70228b355fc39f8f66cf752fb86c19e3eb3501ea63ac7fa5bc74e0d4c803ae6e76cfdf236d8ac7ceab4c4ceb957
6
+ metadata.gz: 3df81f86cd6613d3ad71237534c7c997bac329470697ab6a83af8182e155059d1ee99d0e54298d45352a81ebfc137793560116af7271537c87cc2b62dba3e388
7
+ data.tar.gz: 566662660f26bf8cbb0dd4c31a4afdab9d1da1b53ca380bdeff349a9e7e7f16dab0cc18455f07f85a24c9e7c190c5b773a8a1f8b2f956d3bce701a174d9060ba
data/.gitignore CHANGED
@@ -7,6 +7,7 @@
7
7
  .yardoc
8
8
  Gemfile.lock
9
9
  InstalledFiles
10
+ config/secrets.yml
10
11
  coverage
11
12
  doc/
12
13
  log/
@@ -17,8 +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="6.9.2"
20
+ - TRAVIS_NODE_VERSION="7"
21
21
  before_install:
22
22
  - nvm install $TRAVIS_NODE_VERSION
23
- - npm install yarn
24
- - yarn install
23
+ - npm install
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem "activerecord-multi-tenant", git: 'https://github.com/citusdata/activerecord-multi-tenant.git', branch: 'release-0.5.1'
5
+ # gem "activerecord-multi-tenant", git: 'https://github.com/citusdata/activerecord-multi-tenant.git', branch: 'release-0.5.1'
6
6
 
7
7
  # gem "activerecord-multi-tenant", git: "https://github.com/nathanstitt/activerecord-multi-tenant", branch: 'query_rewriter'
8
8
 
@@ -5,10 +5,10 @@ window.localStorage = {
5
5
  },
6
6
  };
7
7
 
8
- const config = jest.genMockFromModule('../models/config');
9
- //
10
- // config.bootstrapUserData = jest.fn();
11
- // config.reset = jest.fn();
8
+ const Config = jest.genMockFromModule('../models/config');
9
+ const { default: DefaultConfig } = Config;
10
+ const config = new DefaultConfig();
11
+
12
12
  Object.defineProperty(config, 'api_path', {
13
13
  value: '/api',
14
14
  });
@@ -4,6 +4,7 @@ import whenDomReady from 'when-dom-ready';
4
4
  import { delay } from 'lodash';
5
5
  import { AppContainer } from 'react-hot-loader';
6
6
  import { onBoot } from './models/pub_sub';
7
+ import './extensions/hippo';
7
8
 
8
9
  const Workspace = require('hippo/workspace').default;
9
10
 
@@ -22,9 +22,9 @@ export default class Asset extends React.PureComponent {
22
22
  }
23
23
 
24
24
  static propTypes = {
25
- model: PropTypes.instanceOf(BaseModel).isRequired,
26
- name: PropTypes.string.isRequired,
27
- label: PropTypes.string,
25
+ model: PropTypes.instanceOf(BaseModel).isRequired,
26
+ name: PropTypes.string.isRequired,
27
+ label: PropTypes.string,
28
28
  className: PropTypes.string,
29
29
  }
30
30
 
@@ -33,7 +33,7 @@ export default class Asset extends React.PureComponent {
33
33
  if (!this.asset) {
34
34
  this.props.model[this.props.name] = {};
35
35
  }
36
- this.asset.file = files[0];
36
+ this.asset.setFile(files[0]);
37
37
  }
38
38
 
39
39
  get asset() {
@@ -0,0 +1,169 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { action, observable, computed } from 'mobx';
4
+ import { observer } from 'mobx-react';
5
+ import CalendarIcon from 'grommet/components/icons/base/Calendar';
6
+ import ClockIcon from 'grommet/components/icons/base/Clock';
7
+ import Button from 'grommet/components/Button';
8
+ import CSSClassnames from 'grommet/utils/CSSClassnames';
9
+ import { findAncestor, isDescendant } from 'grommet/utils/DOM';
10
+ import KeyboardAccelerators from 'grommet/utils/KeyboardAccelerators';
11
+ import Drop from 'grommet/utils/Drop';
12
+ import moment from 'moment';
13
+
14
+ import DateTimeDrop from './date-time/date-time-drop';
15
+ import './date-time/date-time.scss';
16
+
17
+ const INPUT = CSSClassnames.INPUT;
18
+ const FORM_FIELD = CSSClassnames.FORM_FIELD;
19
+ const CLASS_ROOT = CSSClassnames.DATE_TIME;
20
+
21
+ @observer
22
+ export default class DateTime extends React.Component {
23
+
24
+ static propTypes = {
25
+ value: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired,
26
+ onChange: PropTypes.func.isRequired,
27
+ format: PropTypes.string,
28
+ }
29
+
30
+ static defaultProps = {
31
+ format: 'M/D/YYYY',
32
+ onDropChange: () => {},
33
+ }
34
+
35
+ static contextTypes = {
36
+ onDropChange: PropTypes.func,
37
+ }
38
+
39
+ @observable drop;
40
+ @observable dateValue;
41
+ @observable editingValue
42
+
43
+ @action.bound
44
+ onClose(ev) {
45
+ const dropElement = document.querySelector(`.${DateTimeDrop.className}`);
46
+ if (!isDescendant(this.containerRef, ev.target) &&
47
+ (!dropElement || !isDescendant(dropElement, ev.target))) {
48
+ this.setDropActivation(false);
49
+ }
50
+ }
51
+
52
+ @action.bound
53
+ onForceClose() {
54
+ this.setDropActivation(false);
55
+ }
56
+
57
+ @action.bound
58
+ setDropActivation(dropActive) {
59
+ const { onDropChange } = this.context;
60
+
61
+ const listeners = {
62
+ esc: this.onForceClose,
63
+ };
64
+
65
+ if (dropActive && !this.dropActive) {
66
+ document.addEventListener('click', this.onClose);
67
+ KeyboardAccelerators.startListeningToKeyboard(this, listeners);
68
+ // If this is inside a FormField, place the drop in reference to it.
69
+ const control = findAncestor(this.containerRef, `.${FORM_FIELD}`) || this.containerRef;
70
+ this.drop = new Drop(control, this.renderDrop(), {
71
+ align: { top: 'bottom', left: 'left' },
72
+ focusControl: true,
73
+ context: this.context,
74
+ });
75
+ this.dropActive = true;
76
+ this.props.onDropChange();
77
+ } else if (!dropActive && this.dropActive) {
78
+ document.removeEventListener('click', this.onClose);
79
+ KeyboardAccelerators.stopListeningToKeyboard(this, listeners);
80
+
81
+ if (this.drop) {
82
+ this.drop.remove();
83
+ this.drop = undefined;
84
+ }
85
+ this.dropActive = false;
86
+ this.props.onDropChange();
87
+ }
88
+
89
+ if (onDropChange) {
90
+ onDropChange(dropActive);
91
+ }
92
+ }
93
+
94
+ @computed get value() {
95
+ return this.dateValue || moment(this.props.value || new Date());
96
+ }
97
+
98
+ set value(value) {
99
+ this.dateValue = value;
100
+ }
101
+
102
+ @action.bound
103
+ onInputChange(ev) {
104
+ this.editingValue = ev.target.value;
105
+ }
106
+
107
+ @action.bound
108
+ 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);
114
+ }
115
+ }
116
+
117
+ componentWillUnmount() {
118
+ this.setDropActivation(false);
119
+ }
120
+
121
+ @action.bound
122
+ onControlClick() {
123
+ this.setDropActivation(true);
124
+ }
125
+
126
+ @action.bound
127
+ onDateChange(date) {
128
+ this.value = moment(date);
129
+ this.props.onChange(this.value.toDate());
130
+ }
131
+
132
+ renderDrop() {
133
+ return (
134
+ <DateTimeDrop
135
+ {...this.props}
136
+ onChange={this.onDateChange}
137
+ value={this.value}
138
+ />
139
+ );
140
+ }
141
+
142
+ render() {
143
+ const { props: { format, dateOnly } } = this;
144
+ const inputValue = this.editingValue || this.value.format(format);
145
+ const Icon = dateOnly ? CalendarIcon : ClockIcon;
146
+
147
+ return (
148
+ <div
149
+ ref={r => (this.containerRef = r)}
150
+ className={CLASS_ROOT}
151
+ >
152
+ <input
153
+ placeholder={format}
154
+ className={`${INPUT} ${CLASS_ROOT}__input`}
155
+ onClick={this.onControlClick}
156
+ onChange={this.onInputChange}
157
+ onBlur={this.onInputBlur}
158
+ value={inputValue || ''}
159
+ />
160
+ <Button
161
+ icon={<Icon />}
162
+ onClick={this.onControlClick}
163
+ className={`${CLASS_ROOT}__control`}
164
+ />
165
+ </div>
166
+ );
167
+ }
168
+
169
+ }
@@ -0,0 +1,38 @@
1
+ #hippo-root {
2
+ @import '~input-moment/dist/input-moment.css';
3
+ .date-time.component {
4
+
5
+ .tab {
6
+ display: none;
7
+ &.active { display: block; }
8
+ }
9
+
10
+ .tabs {
11
+ > * { padding: 0.23rem; }
12
+ margin-bottom: 10px;
13
+ .grommetux-control-icon { margin-right: 0.5rem; }
14
+ }
15
+
16
+ .toolbar {
17
+ display: flex;
18
+ justify-content: space-between;
19
+ button {
20
+ min-width: 30px;
21
+ padding: 0;
22
+ &.next-month {
23
+ &:before {
24
+ content: ">";
25
+ display: block;
26
+ }
27
+ }
28
+ &.prev-month {
29
+ &:before {
30
+ content: "<";
31
+ display: block;
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
37
+
38
+ }
@@ -0,0 +1,115 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { observer } from 'mobx-react';
4
+ import { action } from 'mobx';
5
+ import cx from 'classnames';
6
+ import range from 'lodash/range';
7
+ import chunk from 'lodash/chunk';
8
+ import Header from 'grommet/components/Header';
9
+ import Button from 'grommet/components/Button';
10
+ import Title from 'grommet/components/Title';
11
+ import LinkPreviousIcon from 'grommet/components/icons/base/LinkPrevious';
12
+ import LinkNextIcon from 'grommet/components/icons/base/LinkNext';
13
+
14
+ const Day = ({ i, w, d, className, ...props }) => {
15
+ const prevMonth = w === 0 && i > 7;
16
+ const nextMonth = w >= 4 && i <= 14;
17
+ const cls = cx(className, {
18
+ 'prev-month': prevMonth,
19
+ 'next-month': nextMonth,
20
+ 'current-day': !prevMonth && !nextMonth && i === d
21
+ });
22
+
23
+ return <td className={cls} {...props}>{i}</td>;
24
+ };
25
+
26
+
27
+ @observer
28
+ export default class Calendar extends React.PureComponent {
29
+
30
+ static propTypes = {
31
+ moment: PropTypes.object.isRequired,
32
+ onChange: PropTypes.func.isRequired,
33
+ }
34
+
35
+ @action.bound
36
+ selectDate(i, w) {
37
+ const prevMonth = w === 0 && i > 7;
38
+ const nextMonth = w >= 4 && i <= 14;
39
+ const m = this.props.moment;
40
+
41
+ m.date(i);
42
+ if (prevMonth) m.subtract(1, 'month');
43
+ if (nextMonth) m.add(1, 'month');
44
+
45
+ this.props.onChange(m);
46
+ this.forceUpdate();
47
+ }
48
+
49
+ @action.bound
50
+ prevMonth(e) {
51
+ e.preventDefault();
52
+ this.props.onChange(this.props.moment.subtract(1, 'month'));
53
+ this.forceUpdate();
54
+ }
55
+
56
+ @action.bound
57
+ nextMonth(e) {
58
+ e.preventDefault();
59
+ this.props.onChange(this.props.moment.add(1, 'month'));
60
+ this.forceUpdate();
61
+ }
62
+
63
+ render() {
64
+ const m = this.props.moment;
65
+ const d = m.date();
66
+ const d1 = m.clone().subtract(1, 'month').endOf('month').date();
67
+ const d2 = m.clone().date(1).day();
68
+ const d3 = m.clone().endOf('month').date();
69
+ const days = [].concat(
70
+ range(d1 - d2 + 1, d1 + 1),
71
+ range(1, d3 + 1),
72
+ range(1, 42 - d3 - d2 + 1),
73
+ );
74
+ const weeks = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
75
+
76
+ return (
77
+ <div className={cx('calendar', this.props.className)}>
78
+
79
+ <Header key='header' justify='between'>
80
+ <Button className="previous" icon={<LinkPreviousIcon />} onClick={this.prevMonth} />
81
+ <Title className="title" responsive={false}>
82
+ {m.format('MMMM YYYY')}
83
+ </Title>
84
+ <Button className="next" icon={<LinkNextIcon />} onClick={this.nextMonth} />
85
+ </Header>
86
+
87
+ <div className="grid">
88
+ <table>
89
+ <thead>
90
+ <tr>
91
+ {weeks.map((w, i) => <td key={i}>{w}</td>)}
92
+ </tr>
93
+ </thead>
94
+
95
+ <tbody>
96
+ {chunk(days, 7).map((row, w) =>
97
+ <tr key={w}>
98
+ {row.map(i =>
99
+ <Day
100
+ key={i}
101
+ i={i}
102
+ d={d}
103
+ w={w}
104
+ onClick={() => this.selectDate(i, w)}
105
+ />,
106
+ )}
107
+ </tr>,
108
+ )}
109
+ </tbody>
110
+ </table>
111
+ </div>
112
+ </div>
113
+ );
114
+ }
115
+ }
@@ -0,0 +1,77 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { action, observable } from 'mobx';
4
+ import { observer } from 'mobx-react';
5
+ import CSSClassnames from 'grommet/utils/CSSClassnames';
6
+ import CalendarIcon from 'grommet/components/icons/base/Calendar';
7
+ import ClockIcon from 'grommet/components/icons/base/Clock';
8
+ import Box from 'grommet/components/Box';
9
+ import cn from 'classnames';
10
+
11
+ import Calendar from './calendar';
12
+ import Time from './time';
13
+
14
+ const FORM_FIELD = CSSClassnames.FORM_FIELD;
15
+ const CLASS_ROOT = 'date-time';
16
+
17
+ @observer
18
+ export default class DateTimeDrop extends React.Component {
19
+
20
+ static propTypes = {
21
+ value: PropTypes.object.isRequired,
22
+ onChange: PropTypes.func.isRequired,
23
+ minuteStep: PropTypes.number,
24
+ }
25
+
26
+ static className = 'date-time-drop';
27
+
28
+ @observable isShowingTime = false;
29
+
30
+ @action.bound
31
+ toggleTabs() {
32
+ this.isShowingTime = !this.isShowingTime;
33
+ }
34
+
35
+ render() {
36
+ return (
37
+ <Box
38
+ className={`${this.constructor.className} component date-time-drop`}
39
+ >
40
+ <Box
41
+ direction='row'
42
+ className="tabs"
43
+ >
44
+ <Box
45
+ onClick={this.isShowingTime ? this.toggleTabs : null}
46
+ colorIndex={this.isShowingTime ? '' : 'neutral-1'}
47
+ align="center" justify="center" flex direction='row' className="calendar"
48
+ >
49
+ <CalendarIcon />
50
+ Day
51
+ </Box>
52
+ <Box
53
+ onClick={this.isShowingTime ? null : this.toggleTabs}
54
+ colorIndex={this.isShowingTime ? 'neutral-1' : ''}
55
+ align="center" justify="center" flex direction='row' className="time"
56
+ >
57
+ <ClockIcon />
58
+ Time
59
+ </Box>
60
+ </Box>
61
+ <div className={cn('tab', { active: !this.isShowingTime })}>
62
+ <Calendar
63
+ moment={this.props.value}
64
+ onChange={this.props.onChange}
65
+ />
66
+ </div>
67
+ <div className={cn('tab', { active: this.isShowingTime })}>
68
+ <Time
69
+ moment={this.props.value}
70
+ onChange={this.props.onChange}
71
+ />
72
+ </div>
73
+ </Box>
74
+ );
75
+ }
76
+
77
+ }