hippo-fw 0.9.4 → 0.9.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +2 -3
- data/Gemfile +1 -1
- data/client/hippo/__mocks__/config.js +4 -4
- data/client/hippo/boot.jsx +1 -0
- data/client/hippo/components/asset.jsx +4 -4
- data/client/hippo/components/date-time.jsx +169 -0
- data/client/hippo/components/date-time.scss +38 -0
- data/client/hippo/components/date-time/calendar.jsx +115 -0
- data/client/hippo/components/date-time/date-time-drop.jsx +77 -0
- data/client/hippo/components/date-time/date-time.scss +157 -0
- data/client/hippo/components/date-time/time.jsx +120 -0
- data/client/hippo/components/form/fields/date-wrapper.jsx +4 -3
- data/client/hippo/components/form/model.js +0 -2
- data/client/hippo/components/text-editor.jsx +85 -0
- data/client/hippo/components/text-editor/display-modes/Button.jsx +17 -0
- data/client/hippo/components/text-editor/display-modes/SaveState.jsx +17 -0
- data/client/hippo/components/text-editor/display-modes/ToggleEdit.jsx +22 -0
- data/client/hippo/components/text-editor/display-modes/ToggleInsert.jsx +21 -0
- data/client/hippo/components/text-editor/display-modes/ToggleLayout.jsx +21 -0
- data/client/hippo/components/text-editor/display-modes/TogglePreview.jsx +21 -0
- data/client/hippo/components/text-editor/display-modes/ToggleResize.jsx +21 -0
- data/client/hippo/components/text-editor/display-modes/index.css +0 -0
- data/client/hippo/components/text-editor/display-modes/index.js +30 -0
- data/client/hippo/components/text-editor/image-plugin/Component/Display/index.js +80 -0
- data/client/hippo/components/text-editor/image-plugin/Component/Form/index.js +40 -0
- data/client/hippo/components/text-editor/image-plugin/Component/index.js +16 -0
- data/client/hippo/components/text-editor/image-plugin/Component/index.scss +0 -0
- data/client/hippo/components/text-editor/image-plugin/index.js +32 -0
- data/client/hippo/components/text-editor/image-plugin/index.scss +25 -0
- data/client/hippo/components/text-editor/plugins.js +22 -0
- data/client/hippo/components/text-editor/renderer.jsx +37 -0
- data/client/hippo/components/text-editor/text-editor.scss +49 -0
- data/client/hippo/extensions/base.js +5 -2
- data/client/hippo/extensions/hippo.js +5 -2
- data/client/hippo/extensions/index.js +9 -3
- data/client/hippo/lib/__mocks__/request-assets.js +2 -2
- data/client/hippo/lib/bootstrap.js +0 -1
- data/client/hippo/lib/smooth-scroll.js +0 -1
- data/client/hippo/lib/util.js +4 -4
- data/client/hippo/models/asset.js +43 -23
- data/client/hippo/models/base.js +1 -2
- data/client/hippo/models/config.js +0 -1
- data/client/hippo/models/decorators.js +3 -3
- data/client/hippo/models/pub_sub.js +2 -5
- data/client/hippo/models/pub_sub/channel.js +0 -1
- data/client/hippo/models/query.js +0 -1
- data/client/hippo/models/query/array-result.js +0 -1
- data/client/hippo/models/query/clause.js +0 -1
- data/client/hippo/models/query/field.js +0 -1
- data/client/hippo/models/query/info.js +0 -3
- data/client/hippo/models/query/operator.js +0 -2
- data/client/hippo/models/query/result.js +0 -1
- data/client/hippo/models/sync.js +1 -1
- data/client/hippo/models/system-setting.js +0 -2
- data/client/hippo/models/tenant.js +0 -1
- data/client/hippo/screens/definition.js +0 -2
- data/client/hippo/screens/group.js +0 -2
- data/client/hippo/screens/instance.js +0 -3
- data/client/hippo/screens/system-settings/mailer-config.jsx +0 -3
- data/client/hippo/styles/global.scss +3 -0
- data/client/hippo/testing/mocks/fetch.js +6 -6
- data/client/hippo/user.js +4 -4
- data/client/hippo/workspace/index.jsx +12 -5
- data/client/hippo/workspace/root-view.jsx +10 -0
- data/command-reference-files/initial/.gitignore +1 -0
- data/command-reference-files/initial/Gemfile +1 -1
- data/command-reference-files/initial/client/appy-app/extension.js +4 -0
- data/command-reference-files/initial/config/webpack.config.js +25 -23
- data/config/routes.rb +4 -1
- data/config/webpack.config.js +1 -2
- data/hippo-fw.gemspec +4 -2
- data/lib/hippo.rb +0 -1
- data/lib/hippo/api/handlers/asset.rb +9 -0
- data/lib/hippo/api/updates.rb +2 -2
- data/lib/hippo/configuration.rb +0 -4
- data/lib/hippo/db.rb +2 -2
- data/lib/hippo/{rails.rb → db/fake_rails.rb} +0 -0
- data/lib/hippo/extension.rb +1 -2
- data/lib/hippo/mailer.rb +1 -0
- data/lib/hippo/spec_helper.rb +1 -0
- data/lib/hippo/version.rb +1 -1
- data/package-lock.json +626 -68
- data/package.json +14 -13
- data/spec/client/access/login-dialog.spec.jsx +1 -0
- data/spec/client/components/asset.spec.jsx +1 -2
- data/spec/client/components/date-time.spec.jsx +20 -0
- data/spec/client/extension/base.spec.js +0 -2
- data/spec/client/models/base.spec.js +4 -4
- data/spec/client/models/query.spec.js +2 -2
- data/spec/client/models/sync.spec.js +1 -1
- data/spec/client/screens/system-settings.spec.jsx +2 -1
- data/spec/client/setup.js +3 -0
- data/spec/client/test-models.js +0 -2
- data/spec/server/api/tenant_change_spec.rb +1 -1
- data/spec/server/api/tenant_isolation_spec.rb +6 -3
- data/spec/server/concerns/api_path_spec.rb +2 -2
- data/templates/.gitignore +1 -0
- data/templates/client/extension.js +4 -0
- data/templates/config/webpack.config.js +25 -23
- metadata +48 -12
- data/client/hippo/lib/pub_sub.js +0 -34
- data/client/hippo/react/viewport-root.jsx +0 -44
- data/spec/client/components/__snapshots__/asset.spec.jsx.snap +0 -48
- data/spec/client/screens/__snapshots__/system-settings.spec.jsx.snap +0 -443
- data/templates/gitignore +0 -4
@@ -0,0 +1,157 @@
|
|
1
|
+
@import '../../styles/global';
|
2
|
+
|
3
|
+
.date-time-drop {
|
4
|
+
$slider-handle-size: 20px;
|
5
|
+
$slider-size: 4px;
|
6
|
+
$slider-fix: 20px;
|
7
|
+
.calendar {
|
8
|
+
header {
|
9
|
+
min-height: 50px;
|
10
|
+
}
|
11
|
+
.grid {
|
12
|
+
width: 100%;
|
13
|
+
padding: 12px;
|
14
|
+
}
|
15
|
+
table {
|
16
|
+
width: 100%;
|
17
|
+
border-collapse: collapse;
|
18
|
+
border-spacing: 0;
|
19
|
+
}
|
20
|
+
td {
|
21
|
+
padding: 8px 0;
|
22
|
+
text-align: center;
|
23
|
+
cursor: pointer;
|
24
|
+
}
|
25
|
+
thead {
|
26
|
+
td {
|
27
|
+
color: $secondary-text-color;
|
28
|
+
font-weight: normal;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
tbody td {
|
32
|
+
color: #666666;
|
33
|
+
|
34
|
+
&:hover {
|
35
|
+
background-color: $hover-background-color;
|
36
|
+
color: $hover-text-color;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
.current-day {
|
40
|
+
background-color: $brand-color;
|
41
|
+
color: $colored-text-color;
|
42
|
+
font-weight: 700;
|
43
|
+
}
|
44
|
+
.prev-month,
|
45
|
+
.next-month {
|
46
|
+
color: #999999;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
|
51
|
+
.time-picker {
|
52
|
+
color: $background-color;
|
53
|
+
padding-top: 50px;
|
54
|
+
|
55
|
+
.showtime {
|
56
|
+
text-align: center;
|
57
|
+
}
|
58
|
+
|
59
|
+
.am-pm {
|
60
|
+
display: flex;
|
61
|
+
flex-direction: column;
|
62
|
+
margin-left: 10px;
|
63
|
+
}
|
64
|
+
|
65
|
+
.separater {
|
66
|
+
display: inline-block;
|
67
|
+
font-size: 32px;
|
68
|
+
font-weight: bold;
|
69
|
+
color: $inverse-background-color;
|
70
|
+
width: 32px;
|
71
|
+
height: 65px;
|
72
|
+
line-height: 65px;
|
73
|
+
text-align: center;
|
74
|
+
}
|
75
|
+
|
76
|
+
.time-text {
|
77
|
+
position: relative;
|
78
|
+
left: -10px;
|
79
|
+
font-size: 15px;
|
80
|
+
color: $inverse-background-color;
|
81
|
+
margin-top: 7px;
|
82
|
+
margin-bottom: 10px;
|
83
|
+
}
|
84
|
+
|
85
|
+
.sliders {
|
86
|
+
padding: 40px;
|
87
|
+
max-width: 500px;
|
88
|
+
margin: auto;
|
89
|
+
}
|
90
|
+
|
91
|
+
.minutes,
|
92
|
+
.hour {
|
93
|
+
width: 65px;
|
94
|
+
height: 65px;
|
95
|
+
padding: 0;
|
96
|
+
font-size: 38px;
|
97
|
+
background-color: $inverse-background-color;
|
98
|
+
border-radius: 3px;
|
99
|
+
text-align: center;
|
100
|
+
&:focus {
|
101
|
+
padding: 0;
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
|
107
|
+
.u-slider-time {
|
108
|
+
position: relative;
|
109
|
+
display: inline-block;
|
110
|
+
background-color: $control-background-color;
|
111
|
+
border-radius: 3px;
|
112
|
+
height: $slider-size;
|
113
|
+
width: 100%;
|
114
|
+
cursor: pointer;
|
115
|
+
|
116
|
+
.value {
|
117
|
+
position: absolute;
|
118
|
+
background-color: $brand-color;
|
119
|
+
border-radius: 3px;
|
120
|
+
top: 0;
|
121
|
+
height: 100%;
|
122
|
+
}
|
123
|
+
|
124
|
+
.handle {
|
125
|
+
position: absolute;
|
126
|
+
width: $slider-size;
|
127
|
+
height: $slider-size;
|
128
|
+
|
129
|
+
&:after {
|
130
|
+
position: relative;
|
131
|
+
display: block;
|
132
|
+
content: '';
|
133
|
+
top: -$slider-fix/2 - 2;
|
134
|
+
left: -($slider-size+$slider-fix)/2;
|
135
|
+
width: $slider-size + $slider-fix;
|
136
|
+
height: $slider-size + $slider-fix;
|
137
|
+
background-color: #fff;
|
138
|
+
border: 3px solid $brand-color; //inverse-background-color;
|
139
|
+
border-radius: 50%;
|
140
|
+
cursor: pointer;
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
.tab {
|
146
|
+
display: none;
|
147
|
+
&.active { display: block; }
|
148
|
+
}
|
149
|
+
|
150
|
+
.tabs {
|
151
|
+
> * { padding: 0.5rem; }
|
152
|
+
margin-bottom: 10px;
|
153
|
+
border-bottom: 1px solid;
|
154
|
+
.grommetux-control-icon { margin-right: 0.5rem; }
|
155
|
+
}
|
156
|
+
|
157
|
+
}
|
@@ -0,0 +1,120 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import cn from 'classnames';
|
4
|
+
import { inRange, get, isString } from 'lodash';
|
5
|
+
import { action, observable } from 'mobx';
|
6
|
+
import { observer } from 'mobx-react';
|
7
|
+
import InputSlider from 'react-input-slider';
|
8
|
+
import CheckBox from 'grommet/components/CheckBox';
|
9
|
+
import Box from 'grommet/components/Box';
|
10
|
+
|
11
|
+
const NON_DIGIT = /\D/;
|
12
|
+
|
13
|
+
function getDigits(ev) {
|
14
|
+
const val = get(ev, 'target.value', ev.x);
|
15
|
+
if (isString(val) && (!val || NON_DIGIT.test(val))) { return null; }
|
16
|
+
return parseInt(val, 10);
|
17
|
+
}
|
18
|
+
|
19
|
+
@observer
|
20
|
+
export default class TimeSelector extends React.PureComponent {
|
21
|
+
|
22
|
+
static propTypes = {
|
23
|
+
moment: PropTypes.object.isRequired,
|
24
|
+
onChange: PropTypes.func.isRequired,
|
25
|
+
minuteStep: PropTypes.number,
|
26
|
+
}
|
27
|
+
|
28
|
+
@observable isPM;
|
29
|
+
@observable hour;
|
30
|
+
@observable minutes;
|
31
|
+
|
32
|
+
componentWillMount() {
|
33
|
+
this.set(this.props);
|
34
|
+
}
|
35
|
+
|
36
|
+
componentWillReceiveProps(nextProps) {
|
37
|
+
this.set(nextProps);
|
38
|
+
}
|
39
|
+
|
40
|
+
set(props) {
|
41
|
+
this.isPM = !!(12 <= props.moment.hour());
|
42
|
+
this.hour = (12 <= props.moment.hour()) ? props.moment.hour() - 12 : props.moment.hour();
|
43
|
+
this.minutes = props.moment.minute();
|
44
|
+
}
|
45
|
+
|
46
|
+
@action.bound
|
47
|
+
onHourChange(ev) {
|
48
|
+
const d = getDigits(ev);
|
49
|
+
const m = this.props.moment;
|
50
|
+
if (inRange(d, 1, 13)) {
|
51
|
+
m.hours(this.isPM ? d + 12 : d);
|
52
|
+
this.hour = d;
|
53
|
+
} else {
|
54
|
+
this.hour = 0;
|
55
|
+
m.hours(0);
|
56
|
+
}
|
57
|
+
this.props.onChange(m);
|
58
|
+
}
|
59
|
+
|
60
|
+
@action.bound
|
61
|
+
onMinuteChange(ev) {
|
62
|
+
const d = getDigits(ev);
|
63
|
+
if (inRange(d, 0, 60)) {
|
64
|
+
const m = this.props.moment;
|
65
|
+
m.minutes(d);
|
66
|
+
this.props.onChange(m);
|
67
|
+
this.minutes = d;
|
68
|
+
} else {
|
69
|
+
this.minutes = 0;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
@action.bound
|
74
|
+
toggleAMPM(ev) {
|
75
|
+
this.isPM = ev.target.checked;
|
76
|
+
this.props.moment.hours(this.isPM ? this.hour + 12 : this.hour);
|
77
|
+
this.props.onChange(this.props.moment);
|
78
|
+
}
|
79
|
+
|
80
|
+
render() {
|
81
|
+
const { hour, minutes } = this;
|
82
|
+
|
83
|
+
return (
|
84
|
+
<div className={cn('time-picker', this.props.className)}>
|
85
|
+
<Box direction='row' className="showtime" justify="center" align="center">
|
86
|
+
<input className="hour" value={hour} onChange={this.onHourChange} />
|
87
|
+
<span className="separater">:</span>
|
88
|
+
<input className="minutes" value={minutes} onChange={this.onMinuteChange} />
|
89
|
+
<CheckBox
|
90
|
+
toggle
|
91
|
+
className="am-pm"
|
92
|
+
label='AM / PM'
|
93
|
+
checked={this.isPM}
|
94
|
+
onChange={this.toggleAMPM}
|
95
|
+
/>
|
96
|
+
</Box>
|
97
|
+
|
98
|
+
<div className="sliders">
|
99
|
+
<div className="time-text">Hours:</div>
|
100
|
+
<InputSlider
|
101
|
+
className="u-slider-time"
|
102
|
+
xmin={1}
|
103
|
+
xmax={12}
|
104
|
+
step={this.props.minuteStep}
|
105
|
+
x={hour}
|
106
|
+
onChange={this.onHourChange}
|
107
|
+
/>
|
108
|
+
<div className="time-text">Minutes:</div>
|
109
|
+
<InputSlider
|
110
|
+
className="u-slider-time"
|
111
|
+
xmin={0}
|
112
|
+
xmax={59}
|
113
|
+
x={minutes || 0}
|
114
|
+
onChange={this.onMinuteChange}
|
115
|
+
/>
|
116
|
+
</div>
|
117
|
+
</div>
|
118
|
+
);
|
119
|
+
}
|
120
|
+
}
|
@@ -3,11 +3,13 @@ import PropTypes from 'prop-types';
|
|
3
3
|
import { observer } from 'mobx-react';
|
4
4
|
import { action, observable } from 'mobx';
|
5
5
|
import moment from 'moment';
|
6
|
-
import DateTime from '
|
6
|
+
import DateTime from '../../date-time';
|
7
7
|
|
8
8
|
@observer
|
9
9
|
export default class DateWrapper extends React.PureComponent {
|
10
|
-
static defaultProps = {
|
10
|
+
static defaultProps = {
|
11
|
+
format: 'M/D/YYYY h:mm a'
|
12
|
+
}
|
11
13
|
static childContextTypes = { onDropChange: PropTypes.func }
|
12
14
|
@observable isSelecting;
|
13
15
|
@observable dateValue;
|
@@ -29,7 +31,6 @@ export default class DateWrapper extends React.PureComponent {
|
|
29
31
|
this.props.onChange({ target: { value: this.dateValue } });
|
30
32
|
}
|
31
33
|
|
32
|
-
|
33
34
|
@action.bound onBlur(ev) {
|
34
35
|
this.dateValue = moment(ev.target.value, this.props.format).toDate();
|
35
36
|
const event = { target: { value: this.dateValue } };
|
@@ -69,7 +69,6 @@ export class FormField {
|
|
69
69
|
|
70
70
|
|
71
71
|
export class FormState {
|
72
|
-
|
73
72
|
fields = observable.map();
|
74
73
|
|
75
74
|
@action
|
@@ -136,5 +135,4 @@ export class FormState {
|
|
136
135
|
this.fields.forEach((field, name) => (model[name] = field.value));
|
137
136
|
return Promise.resolve(model);
|
138
137
|
}
|
139
|
-
|
140
138
|
}
|
@@ -0,0 +1,85 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { action, observable, toJS } from 'mobx';
|
4
|
+
import { isEmpty } from 'lodash';
|
5
|
+
import { observer } from 'mobx-react';
|
6
|
+
import { Provider, PropTypes as MobxPropTypes } from 'mobx-react';
|
7
|
+
|
8
|
+
// The editor core
|
9
|
+
import Editor, { Editable, createEmptyState } from 'ory-editor-core';
|
10
|
+
|
11
|
+
// Require our ui components (optional). You can implement and use your own ui too!
|
12
|
+
import { Trash, Toolbar } from 'ory-editor-ui';
|
13
|
+
import tapEventPlugin from 'react-tap-event-plugin';
|
14
|
+
|
15
|
+
import { plugins, defaultPlugin } from './text-editor/plugins';
|
16
|
+
|
17
|
+
import 'ory-editor-ui/lib/index.css';
|
18
|
+
import 'ory-editor-core/lib/index.css';
|
19
|
+
|
20
|
+
import DisplayModeToggle from './text-editor/display-modes';
|
21
|
+
import './text-editor/text-editor.scss';
|
22
|
+
|
23
|
+
|
24
|
+
@observer
|
25
|
+
export default class TextEditor extends React.PureComponent {
|
26
|
+
|
27
|
+
static defaultProps = {
|
28
|
+
assets: observable.array(),
|
29
|
+
}
|
30
|
+
|
31
|
+
static propTypes = {
|
32
|
+
defaultContent: PropTypes.object,
|
33
|
+
assets: MobxPropTypes.observableArray,
|
34
|
+
onComplete: PropTypes.func.isRequired,
|
35
|
+
}
|
36
|
+
|
37
|
+
componentWillMount() {
|
38
|
+
const content = toJS(this.props.defaultContent);
|
39
|
+
this.content = isEmpty(content) ? createEmptyState() : content;
|
40
|
+
this.editor = new Editor({
|
41
|
+
plugins,
|
42
|
+
editables: [this.content],
|
43
|
+
defaultPlugin,
|
44
|
+
});
|
45
|
+
tapEventPlugin();
|
46
|
+
}
|
47
|
+
|
48
|
+
@action.bound
|
49
|
+
onSave() {
|
50
|
+
this.props.onComplete({ content: this.content });
|
51
|
+
}
|
52
|
+
|
53
|
+
@action.bound
|
54
|
+
onEditStateChange(state) {
|
55
|
+
this.content = state;
|
56
|
+
}
|
57
|
+
|
58
|
+
render() {
|
59
|
+
return (
|
60
|
+
<Provider
|
61
|
+
assets={this.props.assets}
|
62
|
+
>
|
63
|
+
<div className="text-editor">
|
64
|
+
<DisplayModeToggle
|
65
|
+
editor={this.editor}
|
66
|
+
onSave={this.onSave}
|
67
|
+
>
|
68
|
+
{this.props.children}
|
69
|
+
</DisplayModeToggle>
|
70
|
+
<div className="text-editor-content">
|
71
|
+
<Editable
|
72
|
+
editor={this.editor}
|
73
|
+
id={this.content.id}
|
74
|
+
onAddImage={this.props.onAddImage}
|
75
|
+
onChange={this.onEditStateChange}
|
76
|
+
/>
|
77
|
+
</div>
|
78
|
+
<Trash editor={this.editor}/>
|
79
|
+
<Toolbar editor={this.editor} />
|
80
|
+
</div>
|
81
|
+
|
82
|
+
</Provider>
|
83
|
+
);
|
84
|
+
}
|
85
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react'; // eslint-disable-line no-unused-vars
|
2
|
+
import Button from 'grommet/components/Button';
|
3
|
+
|
4
|
+
const DisplayModeButton = ({ label, icon, onClick, active, disabled }) => (
|
5
|
+
<span className={active ? 'active' : ''}>
|
6
|
+
<Button
|
7
|
+
plain
|
8
|
+
secondary={active}
|
9
|
+
onClick={onClick}
|
10
|
+
label={label}
|
11
|
+
disabled={disabled}
|
12
|
+
icon={icon}
|
13
|
+
/>
|
14
|
+
</span>
|
15
|
+
);
|
16
|
+
|
17
|
+
export default DisplayModeButton;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import SaveIcon from 'grommet/components/icons/base/Save';
|
3
|
+
import Button from './Button';
|
4
|
+
|
5
|
+
export default class SaveState extends React.PureComponent {
|
6
|
+
render() {
|
7
|
+
const { props: { onSave } } = this;
|
8
|
+
|
9
|
+
return (
|
10
|
+
<Button
|
11
|
+
icon={<SaveIcon />}
|
12
|
+
label="Save"
|
13
|
+
onClick={onSave}
|
14
|
+
/>
|
15
|
+
);
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
// @flow
|
2
|
+
import React from 'react'; // eslint-disable-line no-unused-vars
|
3
|
+
import { connect } from 'react-redux';
|
4
|
+
import { editMode } from 'ory-editor-core/lib/actions/display';
|
5
|
+
import { isEditMode } from 'ory-editor-core/lib/selector/display';
|
6
|
+
import { createStructuredSelector } from 'reselect';
|
7
|
+
import EditIcon from 'grommet/components/icons/base/Edit';
|
8
|
+
import Button from './Button';
|
9
|
+
|
10
|
+
const Inner = ({ isEditMode: isedm, editMode: edm }) => (
|
11
|
+
<Button
|
12
|
+
icon={<EditIcon />}
|
13
|
+
label="Edit"
|
14
|
+
active={isedm}
|
15
|
+
onClick={edm}
|
16
|
+
/>
|
17
|
+
);
|
18
|
+
|
19
|
+
const mapStateToProps = createStructuredSelector({ isEditMode });
|
20
|
+
const mapDispatchToProps = { editMode };
|
21
|
+
|
22
|
+
export default connect(mapStateToProps, mapDispatchToProps)(Inner);
|