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.
- checksums.yaml +4 -4
- data/.nvmrc +2 -0
- data/.travis.yml +1 -1
- data/client/hippo/access/login-dialog.jsx +3 -5
- data/client/hippo/boot.jsx +2 -2
- data/client/hippo/components/asset.jsx +0 -1
- data/client/hippo/components/data-list.jsx +16 -15
- data/client/hippo/components/data-list/data-list.scss +10 -0
- data/client/hippo/components/data-table.jsx +14 -14
- data/client/hippo/components/data-table/header-cell.jsx +0 -1
- data/client/hippo/components/data-table/table-styles.scss +7 -0
- data/client/hippo/components/date-time.jsx +19 -16
- data/client/hippo/components/date-time/calendar.jsx +5 -7
- data/client/hippo/components/date-time/date-time-drop.jsx +0 -2
- data/client/hippo/components/date-time/time.jsx +0 -1
- data/client/hippo/components/form.jsx +1 -1
- data/client/hippo/components/form/{model.js → api.js} +25 -7
- data/client/hippo/components/form/fields.jsx +12 -11
- data/client/hippo/components/form/fields/date-wrapper.jsx +1 -1
- data/client/hippo/components/form/fields/form-field.scss +9 -1
- data/client/hippo/components/form/fields/label.jsx +14 -0
- data/client/hippo/components/form/fields/select-wrapper.jsx +2 -3
- data/client/hippo/components/form/wrapper.jsx +1 -3
- data/client/hippo/components/icon.jsx +2 -69
- data/client/hippo/components/master-detail.jsx +0 -2
- data/client/hippo/components/network-activity-overlay.jsx +1 -4
- data/client/hippo/components/query-builder.jsx +15 -16
- data/client/hippo/components/record-finder.jsx +2 -5
- data/client/hippo/components/record-finder/query-layer.jsx +1 -5
- data/client/hippo/components/screen.jsx +7 -3
- data/client/hippo/components/text-editor.jsx +2 -8
- data/client/hippo/components/tool-tip.jsx +2 -3
- data/client/hippo/components/warning-notification.jsx +3 -3
- data/client/hippo/lib/date-range.js +28 -0
- data/client/hippo/lib/util.js +6 -0
- data/client/hippo/models/asset.js +6 -3
- data/client/hippo/models/config.js +1 -1
- data/client/hippo/models/pub_sub.js +12 -7
- data/client/hippo/models/pub_sub/channel.js +6 -4
- data/client/hippo/models/query.js +19 -4
- data/client/hippo/models/query/array-result.js +9 -8
- data/client/hippo/models/query/clause.js +21 -13
- data/client/hippo/models/query/field.js +7 -2
- data/client/hippo/models/query/info.js +7 -3
- data/client/hippo/models/sync.js +11 -14
- data/client/hippo/react/Root.jsx +1 -2
- data/client/hippo/react/{DefaultComponentNotFound.jsx → component-not-found.jsx} +1 -3
- data/client/hippo/screens/index.js +6 -2
- data/client/hippo/screens/system-settings.jsx +10 -6
- data/client/hippo/screens/system-settings/mailer-config.jsx +0 -2
- data/client/hippo/screens/system-settings/tenant.jsx +1 -4
- data/client/hippo/screens/user-management.jsx +0 -1
- data/client/hippo/screens/user-management/edit-form.jsx +1 -2
- data/client/hippo/workspace/index.jsx +21 -12
- data/client/hippo/workspace/menu-group.jsx +4 -7
- data/client/hippo/workspace/menu-option.jsx +1 -3
- data/client/hippo/workspace/menu.jsx +29 -11
- data/client/hippo/workspace/navbar.jsx +1 -2
- data/client/hippo/workspace/root-view.jsx +5 -2
- data/client/hippo/workspace/screen.jsx +2 -3
- data/client/hippo/workspace/styles.scss +17 -0
- data/command-reference-files/screen/client/appy-app/screens/ready-set-go.jsx +2 -1
- data/db/migrate/20170530120004_create_users.rb +1 -1
- data/hippo-fw.gemspec +3 -2
- data/lib/hippo/api/cable.rb +13 -13
- data/lib/hippo/api/controller_base.rb +1 -0
- data/lib/hippo/api/handlers/tenant.rb +1 -1
- data/lib/hippo/api/handlers/user_session.rb +2 -1
- data/lib/hippo/api/helper_methods.rb +4 -1
- data/lib/hippo/api/pub_sub.rb +7 -6
- data/lib/hippo/api/to_json.rb +1 -1
- data/lib/hippo/api/updates.rb +2 -0
- data/lib/hippo/command/console.rb +11 -3
- data/lib/hippo/command/jest.rb +2 -0
- data/lib/hippo/configuration.rb +4 -7
- data/lib/hippo/rake_tasks.rb +1 -1
- data/lib/hippo/screen.rb +31 -93
- data/lib/hippo/screen/definition.rb +76 -0
- data/lib/hippo/screen/group.rb +26 -0
- data/lib/hippo/spec_helper.rb +3 -0
- data/lib/hippo/system_settings.rb +6 -0
- data/lib/hippo/user.rb +11 -3
- data/lib/hippo/version.rb +1 -1
- data/package-lock.json +419 -533
- data/package.json +32 -30
- data/spec/client/access/login-dialog.spec.jsx +4 -5
- data/spec/client/components/__snapshots__/query-builder.spec.jsx.snap +1 -1
- data/spec/client/components/__snapshots__/record-finder.spec.jsx.snap +72 -0
- data/spec/client/components/asset.spec.jsx +2 -6
- data/spec/client/components/data-list.spec.jsx +2 -6
- data/spec/client/components/data-table.spec.jsx +3 -5
- data/spec/client/components/date-time.spec.jsx +1 -1
- data/spec/client/components/form.spec.jsx +2 -2
- data/spec/client/components/master-detail.spec.jsx +1 -2
- data/spec/client/components/network-activity-overlay.spec.jsx +2 -3
- data/spec/client/components/query-builder.spec.jsx +3 -6
- data/spec/client/components/record-finder.spec.jsx +4 -4
- data/spec/client/models/pub_sub.spec.js +3 -1
- data/spec/client/models/query.spec.js +4 -9
- data/spec/client/screens/system-settings-tenants.spec.jsx +1 -1
- data/spec/client/screens/system-settings.spec.jsx +1 -4
- data/spec/client/workspace/__snapshots__/menu.spec.jsx.snap +15 -20
- data/spec/client/workspace/menu.spec.jsx +1 -2
- data/spec/server/api/user_sessions_spec.rb +15 -0
- data/templates/client/screens/screen.jsx +2 -1
- data/views/hippo_root_view.erb +1 -0
- metadata +30 -52
- data/client/hippo/components/calendar/Calendar.jsx +0 -25
- data/client/hippo/components/calendar/index.js +0 -3
- data/client/hippo/components/calendar/styles.scss +0 -3
- data/client/hippo/components/shared/AssetsListing.jsx +0 -23
- data/client/hippo/components/shared/Checkbox.jsx +0 -49
- data/client/hippo/components/shared/CountBadge.jsx +0 -13
- data/client/hippo/components/shared/DateTime.jsx +0 -58
- data/client/hippo/components/shared/DisplayValue.jsx +0 -15
- data/client/hippo/components/shared/ErrorDisplay.jsx +0 -37
- data/client/hippo/components/shared/FieldMixin.jsx +0 -254
- data/client/hippo/components/shared/FieldSet.jsx +0 -52
- data/client/hippo/components/shared/FieldWrapper.jsx +0 -94
- data/client/hippo/components/shared/FormGroup.jsx +0 -41
- data/client/hippo/components/shared/GenericField.jsx +0 -7
- data/client/hippo/components/shared/IconButton.jsx +0 -13
- data/client/hippo/components/shared/ImageAsset.jsx +0 -78
- data/client/hippo/components/shared/IndeterminateCheckbox.jsx +0 -31
- data/client/hippo/components/shared/Input.jsx +0 -16
- data/client/hippo/components/shared/InputFieldMixin.jsx +0 -78
- data/client/hippo/components/shared/JobProgress.jsx +0 -46
- data/client/hippo/components/shared/NumberInput.jsx +0 -37
- data/client/hippo/components/shared/PanelHeader.jsx +0 -15
- data/client/hippo/components/shared/RadioField.jsx +0 -33
- data/client/hippo/components/shared/ResizeSensor.jsx +0 -18
- data/client/hippo/components/shared/ScreenWrapper.jsx +0 -17
- data/client/hippo/components/shared/TextArea.jsx +0 -19
- data/client/hippo/components/shared/Throbber.jsx +0 -8
- data/client/hippo/components/shared/ToggleField.jsx +0 -2
- data/client/hippo/components/shared/Tooltip.jsx +0 -23
- data/client/hippo/components/shared/fields.scss +0 -58
- data/client/hippo/components/shared/fieldset.scss +0 -27
- data/client/hippo/components/shared/image-asset.scss +0 -53
- data/client/hippo/components/shared/index.js +0 -5
- data/client/hippo/components/shared/overlay.scss +0 -83
- data/client/hippo/components/shared/resize-sensor.scss +0 -30
- data/client/hippo/components/shared/styles.scss +0 -64
- data/client/hippo/components/shared/throbber.scss +0 -53
- data/client/hippo/fonts/fontawesome-webfont.woff +0 -0
- data/client/hippo/fonts/fontawesome-webfont.woff2 +0 -0
- data/client/hippo/workspace/content.jsx +0 -22
- data/client/hippo/workspace/tabs.jsx +0 -60
- data/client/hippo/workspace/viewport.jsx +0 -82
- data/spec/client/screens/__snapshots__/tabs.spec.jsx.snap +0 -127
- data/spec/client/screens/tabs.spec.jsx +0 -36
@@ -1,12 +1,11 @@
|
|
1
|
-
import React
|
1
|
+
import React from 'react';
|
2
2
|
import { Tooltip as Tippy } from 'react-tippy';
|
3
3
|
|
4
4
|
import 'react-tippy/dist/tippy.css';
|
5
5
|
|
6
6
|
// Use a wrapper component even though it doesn't really add any functionality
|
7
7
|
// In the future we'll add a Manager wrapper so that multiple tooltips cannot be shown at once
|
8
|
-
export default class ToolTip extends PureComponent {
|
9
|
-
|
8
|
+
export default class ToolTip extends React.PureComponent {
|
10
9
|
render() {
|
11
10
|
const { children, ...tipProps } = this.props;
|
12
11
|
return (
|
@@ -1,14 +1,14 @@
|
|
1
|
-
import React from 'react';
|
1
|
+
import React from 'react'; // eslint-disable-line no-unused-vars
|
2
2
|
import PropTypes from 'prop-types';
|
3
3
|
import Notification from 'grommet/components/Notification';
|
4
4
|
|
5
5
|
export default function WarningNotification(props) {
|
6
|
-
if (!props.message){ return null; }
|
6
|
+
if (!props.message) { return null; }
|
7
7
|
return (
|
8
8
|
<Notification message={props.message} size="small" status="warning" />
|
9
9
|
);
|
10
10
|
}
|
11
11
|
|
12
12
|
WarningNotification.propTypes = {
|
13
|
-
message: PropTypes.string
|
13
|
+
message: PropTypes.string,
|
14
14
|
};
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { isString, isEmpty, map } from 'lodash';
|
2
|
+
import {
|
3
|
+
identifiedBy,
|
4
|
+
} from 'mobx-decorated-models';
|
5
|
+
|
6
|
+
@identifiedBy('date-range')
|
7
|
+
export default class DateRange {
|
8
|
+
constructor(range) {
|
9
|
+
if (isString(range) && !isEmpty(range)) {
|
10
|
+
[this.start, this.end] = map(range.split('...'), d => new Date(d));
|
11
|
+
} else if (range) {
|
12
|
+
this.start = range.start;
|
13
|
+
this.end = range.end;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
toJSON() {
|
18
|
+
if (this.start && this.end) {
|
19
|
+
// this strange format is what PG user and is therefore what active record expects
|
20
|
+
return `[${this.start.toISOString()},${this.end.toISOString()})`;
|
21
|
+
}
|
22
|
+
return '';
|
23
|
+
}
|
24
|
+
|
25
|
+
static serialize(range) {
|
26
|
+
return (range ? range.toJSON() : '');
|
27
|
+
}
|
28
|
+
}
|
data/client/hippo/lib/util.js
CHANGED
@@ -4,6 +4,8 @@ import {
|
|
4
4
|
isNumber, isObject, isEmpty, isNil, isString, each,
|
5
5
|
} from 'lodash';
|
6
6
|
import pluralize from 'pluralize';
|
7
|
+
import classnames from 'classnames';
|
8
|
+
import { getColumnProps } from 'react-flexbox-grid';
|
7
9
|
|
8
10
|
function lcDash(char, match, index) {
|
9
11
|
return (0 === index ? '' : '_') + char.toLowerCase();
|
@@ -17,6 +19,10 @@ export function capitalize(str) {
|
|
17
19
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
18
20
|
}
|
19
21
|
|
22
|
+
export function columnClasses(props, ...classes) {
|
23
|
+
return classnames(getColumnProps(props).className, ...classes);
|
24
|
+
}
|
25
|
+
|
20
26
|
export function dasherize(str) {
|
21
27
|
return trim(str)
|
22
28
|
.replace(/([A-Z])/g, lcDash)
|
@@ -35,6 +35,10 @@ export default class Asset extends BaseModel {
|
|
35
35
|
return Config.api_path + Config.assets_path_prefix;
|
36
36
|
}
|
37
37
|
|
38
|
+
static urlForSize(data, size) {
|
39
|
+
const url = get(data, `${size}.id`);
|
40
|
+
return url ? `${Config.api_host}${this.syncUrl}/${url}` : null;
|
41
|
+
}
|
38
42
|
|
39
43
|
@action.bound
|
40
44
|
onOwnerChange({ newValue: owner }) {
|
@@ -93,9 +97,8 @@ export default class Asset extends BaseModel {
|
|
93
97
|
return get(this, 'file.preview', this.urlFor('thumbnail'));
|
94
98
|
}
|
95
99
|
|
96
|
-
urlFor(
|
97
|
-
|
98
|
-
return url ? `${Config.api_host}${this.constructor.syncUrl}/${url}` : null;
|
100
|
+
urlFor(size = 'original') {
|
101
|
+
return this.constructor.urlForSize(this.file_data, size);
|
99
102
|
}
|
100
103
|
|
101
104
|
save() {
|
@@ -1,8 +1,7 @@
|
|
1
1
|
import { Atom, when, reaction } from 'mobx';
|
2
2
|
import ActionCable from 'actioncable';
|
3
3
|
import invariant from 'invariant';
|
4
|
-
import {
|
5
|
-
|
4
|
+
import { isEmpty, mapValues } from 'lodash';
|
6
5
|
import User from '../user';
|
7
6
|
import Config from '../config';
|
8
7
|
|
@@ -32,9 +31,11 @@ class PubSubMap {
|
|
32
31
|
|
33
32
|
onChange(id, data) {
|
34
33
|
const models = this.map[id];
|
35
|
-
if (models) {
|
34
|
+
if (!isEmpty(models)) {
|
36
35
|
const update = mapValues(data.update, '[1]');
|
37
|
-
|
36
|
+
for (let i = 0; i < models.length; i += 1) {
|
37
|
+
models[i].set(update);
|
38
|
+
}
|
38
39
|
}
|
39
40
|
}
|
40
41
|
|
@@ -43,7 +44,8 @@ class PubSubMap {
|
|
43
44
|
if (!models.includes(model)) {
|
44
45
|
models.push(model);
|
45
46
|
if (1 === models.length) {
|
46
|
-
|
47
|
+
const channel = this.channelForId(id);
|
48
|
+
PubSub.channel.subscribe(channel);
|
47
49
|
}
|
48
50
|
}
|
49
51
|
}
|
@@ -93,8 +95,10 @@ PubSub = {
|
|
93
95
|
|
94
96
|
onLoginChange() {
|
95
97
|
if (User.isLoggedIn) {
|
96
|
-
const
|
97
|
-
|
98
|
+
const host = Config.api_host.replace(/^http/, 'ws');
|
99
|
+
const url = `${host}${Config.api_path}/cable?token=${Config.access_token}`;
|
100
|
+
ActionCable.startDebugging();
|
101
|
+
PubSub.cable = new ActionCable.Consumer(url);
|
98
102
|
PubSub.channel = new PubSubCableChannel(PubSub);
|
99
103
|
} else if (PubSub.cable) {
|
100
104
|
PubSub.cable.disconnect();
|
@@ -144,6 +148,7 @@ export class PubSubAtom {
|
|
144
148
|
}
|
145
149
|
|
146
150
|
export function observePubSub(...models) {
|
151
|
+
if (!PubSub.channel) { return; }
|
147
152
|
for (let i = 0; i < models.length; i += 1) {
|
148
153
|
const model = models[i];
|
149
154
|
if (!model.$pubSub) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { omit } from 'lodash';
|
2
|
-
|
2
|
+
import { action } from 'mobx';
|
3
3
|
import { logger } from '../../lib/util';
|
4
4
|
import { BaseModel } from '../base';
|
5
5
|
|
@@ -8,8 +8,9 @@ const CHANNEL_SPLITTER = new RegExp('^(.*):(.*)/([^/]+)$');
|
|
8
8
|
export default class PubSubCableChannel {
|
9
9
|
constructor(pub_sub) {
|
10
10
|
this.channel = pub_sub.cable.subscriptions.create(
|
11
|
-
'
|
11
|
+
'Hippo::API::PubSub', this,
|
12
12
|
);
|
13
|
+
this.channel.received = this.received;
|
13
14
|
this.pub_sub = pub_sub;
|
14
15
|
}
|
15
16
|
|
@@ -23,11 +24,12 @@ export default class PubSubCableChannel {
|
|
23
24
|
this.channel.perform('off', { channel });
|
24
25
|
}
|
25
26
|
|
27
|
+
@action.bound
|
26
28
|
received(data) {
|
27
|
-
const [
|
29
|
+
const [_, __, modelId, id] = Array.from(
|
28
30
|
data.channel.match(CHANNEL_SPLITTER),
|
29
31
|
);
|
30
|
-
|
32
|
+
|
31
33
|
const model = BaseModel.findDerived(modelId);
|
32
34
|
this.pub_sub.onModelChange(model, id, omit(data, 'channel'));
|
33
35
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { get, isString, find, extend, toPairs } from 'lodash';
|
2
|
-
import { action, reaction, observe } from 'mobx';
|
2
|
+
import { action, reaction, observe, observable } from 'mobx';
|
3
3
|
import {
|
4
4
|
BaseModel, identifiedBy, field, belongsTo, hasMany, identifier, computed, session,
|
5
5
|
} from './base';
|
@@ -30,7 +30,7 @@ export default class Query extends BaseModel {
|
|
30
30
|
@session customSyncUrl;
|
31
31
|
|
32
32
|
@session autoFetch = false;
|
33
|
-
|
33
|
+
@observable autoFetchDisposer;
|
34
34
|
@field({ type: 'object' }) syncOptions = {};
|
35
35
|
|
36
36
|
@hasMany({ model: Clause, inverseOf: 'query' }) clauses;
|
@@ -53,13 +53,17 @@ export default class Query extends BaseModel {
|
|
53
53
|
[
|
54
54
|
{ id: 'like', label: 'Starts With', types: Types.LIKE_QUERY_TYPES },
|
55
55
|
{ id: 'eq', label: 'Equals' },
|
56
|
+
{ id: 'contains', label: 'Contains', types: Types.LIKE_QUERY_TYPES },
|
56
57
|
{ id: 'lt', label: 'Less Than', types: Types.LESS_THAN_QUERY_TYPES },
|
57
58
|
{ id: 'gt', label: 'More Than', types: Types.LESS_THAN_QUERY_TYPES },
|
58
59
|
].forEach(op => this.operators.push(op));
|
59
60
|
this.info = new Info(this);
|
60
61
|
this.results = new ArrayResult({ query: this });
|
61
62
|
if (0 === this.clauses.length) {
|
62
|
-
this.
|
63
|
+
const ff = find(this.fields, { queryable: true });
|
64
|
+
if (ff) {
|
65
|
+
this.clauses.push({ field: ff, operator: ff.preferredOperator });
|
66
|
+
}
|
63
67
|
}
|
64
68
|
if (attrs.sort) {
|
65
69
|
const [fieldId, dir] = toPairs(attrs.sort)[0];
|
@@ -80,7 +84,7 @@ export default class Query extends BaseModel {
|
|
80
84
|
close() {
|
81
85
|
if (this.autoFetchDisposer) {
|
82
86
|
this.autoFetchDisposer();
|
83
|
-
this.autoFetchDisposer =
|
87
|
+
this.autoFetchDisposer = null;
|
84
88
|
}
|
85
89
|
}
|
86
90
|
|
@@ -89,6 +93,15 @@ export default class Query extends BaseModel {
|
|
89
93
|
return this.results.fetch({ start: 0 });
|
90
94
|
}
|
91
95
|
|
96
|
+
get rows() {
|
97
|
+
return this.results.rows;
|
98
|
+
}
|
99
|
+
|
100
|
+
reset() {
|
101
|
+
this.clauses.clear();
|
102
|
+
this.results.reset();
|
103
|
+
}
|
104
|
+
|
92
105
|
fetchSingle(query, queryOptions = {}) {
|
93
106
|
const options = extend(queryOptions, this.syncOptions, { query });
|
94
107
|
const { src: Src } = this;
|
@@ -102,10 +115,12 @@ export default class Query extends BaseModel {
|
|
102
115
|
this._startAutoFetch();
|
103
116
|
} else if (this.autoFetchDisposer) {
|
104
117
|
this.autoFetchDisposer();
|
118
|
+
this.autoFetchDisposer = null;
|
105
119
|
}
|
106
120
|
}
|
107
121
|
|
108
122
|
_startAutoFetch() {
|
123
|
+
if (this.autoFetchDisposer) { return; }
|
109
124
|
this.autoFetchDisposer = reaction(
|
110
125
|
() => this.fingerprint,
|
111
126
|
this.fetch,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import {
|
2
|
-
isEmpty, isNil, extend, map, bindAll,
|
2
|
+
isEmpty, isNil, extend, map, bindAll, inRange, find, range,
|
3
3
|
} from 'lodash';
|
4
|
-
import { reaction, observe } from 'mobx';
|
4
|
+
import { reaction, observe, toJS } from 'mobx';
|
5
5
|
|
6
6
|
import Sync from '../sync';
|
7
7
|
import Result from './result';
|
@@ -59,9 +59,10 @@ export default class ArrayResult extends Result {
|
|
59
59
|
rowAsObject(index) {
|
60
60
|
const row = this.rows[index];
|
61
61
|
const obj = {};
|
62
|
-
this.query.info.loadableFields.forEach(
|
63
|
-
|
64
|
-
|
62
|
+
this.query.info.loadableFields.forEach((f) => {
|
63
|
+
const value = row[f.dataIndex] || f.defaultValue;
|
64
|
+
if (!isNil(value)) { obj[f.id] = value; }
|
65
|
+
});
|
65
66
|
return obj;
|
66
67
|
}
|
67
68
|
|
@@ -84,7 +85,7 @@ export default class ArrayResult extends Result {
|
|
84
85
|
fetchModelForRow(index, syncOptions = {}) {
|
85
86
|
const model = this.modelForRow(index);
|
86
87
|
return model.isNew ? Promise.resolve(model) :
|
87
|
-
model.fetch(extend({}, this.query.syncOptions, syncOptions));
|
88
|
+
model.fetch(extend({}, toJS(this.query.syncOptions), syncOptions));
|
88
89
|
}
|
89
90
|
|
90
91
|
onQuerySortChange() {
|
@@ -152,7 +153,7 @@ export default class ArrayResult extends Result {
|
|
152
153
|
}
|
153
154
|
});
|
154
155
|
|
155
|
-
const options = extend({},
|
156
|
+
const options = extend({}, toJS(this.query.syncOptions), {
|
156
157
|
start,
|
157
158
|
limit,
|
158
159
|
total_count: 't',
|
@@ -170,7 +171,7 @@ export default class ArrayResult extends Result {
|
|
170
171
|
};
|
171
172
|
}
|
172
173
|
|
173
|
-
extend(options,
|
174
|
+
extend(options, toJS(this.query.info.syncOptions));
|
174
175
|
|
175
176
|
this.syncInProgress = options;
|
176
177
|
|
@@ -1,26 +1,29 @@
|
|
1
|
-
import { get, compact, first, filter,
|
1
|
+
import { get, compact, first, filter, uniqueId } from 'lodash';
|
2
|
+
import { action, observe } from 'mobx';
|
2
3
|
import {
|
3
|
-
BaseModel, identifiedBy,
|
4
|
+
BaseModel, identifiedBy, belongsTo, computed, observable, session,
|
4
5
|
} from '../base';
|
5
6
|
|
6
7
|
@identifiedBy('hippo/query/clause')
|
7
8
|
export default class Clause extends BaseModel {
|
8
9
|
@observable id = uniqueId('clause');
|
9
|
-
|
10
|
-
@
|
10
|
+
@session visible = true;
|
11
|
+
@session value;
|
11
12
|
@belongsTo({ type: 'hippo/query' }) query;
|
12
13
|
|
13
14
|
@belongsTo({ type: 'hippo/query/field' }) field;
|
14
15
|
@belongsTo({ type: 'hippo/query/operator' }) operator;
|
15
16
|
|
16
|
-
@computed get description() {
|
17
|
-
return compact([get(this, 'field.title'), get(this, 'operator.id')]).join(' ');
|
18
|
-
}
|
19
|
-
|
20
17
|
constructor(attrs) {
|
21
18
|
super(attrs);
|
22
|
-
|
23
|
-
|
19
|
+
if (!this.field) {
|
20
|
+
this.field = first(this.query.info.queryableFields);
|
21
|
+
}
|
22
|
+
observe(this, 'field', this.updateOperatorOnFieldChange, true);
|
23
|
+
}
|
24
|
+
|
25
|
+
@computed get description() {
|
26
|
+
return compact([get(this, 'field.title'), get(this, 'operator.id')]).join(' ');
|
24
27
|
}
|
25
28
|
|
26
29
|
@computed get validOperators() {
|
@@ -37,15 +40,20 @@ export default class Clause extends BaseModel {
|
|
37
40
|
|
38
41
|
toParam() {
|
39
42
|
const param = {};
|
40
|
-
|
43
|
+
let op = this.operator.id;
|
41
44
|
let value = this.value;
|
42
45
|
if ('like' === op) { value += '%'; }
|
46
|
+
if ('contains' === op) {
|
47
|
+
op = 'like';
|
48
|
+
value = `%${value}%`;
|
49
|
+
}
|
43
50
|
if ('n' === this.field.type) { value = parseFloat(value); }
|
44
51
|
param[this.field.id] = 'eq' === op ? value : { op, value };
|
45
52
|
return param;
|
46
53
|
}
|
47
54
|
|
48
|
-
|
49
|
-
|
55
|
+
@action.bound
|
56
|
+
updateOperatorOnFieldChange() {
|
57
|
+
this.operator = this.field.preferredOperator;
|
50
58
|
}
|
51
59
|
}
|
@@ -18,7 +18,8 @@ export default class Field extends BaseModel {
|
|
18
18
|
@session queryable = true;
|
19
19
|
@session sortable = true;
|
20
20
|
@session textAlign = 'left';
|
21
|
-
|
21
|
+
@session dataType = 'string'
|
22
|
+
@session cellRenderer;
|
22
23
|
@session defaultValue;
|
23
24
|
@session fetchIndex;
|
24
25
|
@session sortBy;
|
@@ -38,7 +39,7 @@ export default class Field extends BaseModel {
|
|
38
39
|
}
|
39
40
|
|
40
41
|
@computed get queryType() {
|
41
|
-
return get(this.query.src.propertyOptions[this.id], 'type',
|
42
|
+
return get(this.query.src.propertyOptions[this.id], 'type', this.dataType);
|
42
43
|
}
|
43
44
|
|
44
45
|
@computed get isNumeric() {
|
@@ -59,4 +60,8 @@ export default class Field extends BaseModel {
|
|
59
60
|
}
|
60
61
|
return null;
|
61
62
|
}
|
63
|
+
|
64
|
+
@computed get preferredOperator() {
|
65
|
+
return this.query.operators.find(o => o.isValidForField(this));
|
66
|
+
}
|
62
67
|
}
|
@@ -22,15 +22,19 @@ export default class Info {
|
|
22
22
|
}
|
23
23
|
|
24
24
|
@computed get visibleFields() {
|
25
|
-
return filter(this.query.fields,
|
25
|
+
return filter(this.query.fields, 'visible');
|
26
26
|
}
|
27
27
|
|
28
28
|
@computed get queryableFields() {
|
29
|
-
return filter(this.query.fields,
|
29
|
+
return filter(this.query.fields, 'queryable');
|
30
|
+
}
|
31
|
+
|
32
|
+
@computed get visibleClauses() {
|
33
|
+
return filter(this.query.clauses, 'visible');
|
30
34
|
}
|
31
35
|
|
32
36
|
@computed get loadableFields() {
|
33
|
-
return filter(this.query.fields,
|
37
|
+
return filter(this.query.fields, 'loadable');
|
34
38
|
}
|
35
39
|
|
36
40
|
@computed get identifierField() {
|
data/client/hippo/models/sync.js
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
/* eslint no-param-reassign: 0 */
|
2
|
+
|
1
3
|
import qs from 'qs';
|
2
4
|
import 'whatwg-fetch'; // fetch polyfill
|
3
5
|
|
@@ -82,32 +84,27 @@ function perform(urlPrefix, defaultOptions = {}) {
|
|
82
84
|
}
|
83
85
|
|
84
86
|
const peformMobxyRequest = action('SyncforModel', (mobxObj, options = {}) => {
|
85
|
-
mobxObj.syncInProgress = new SyncProgess(options);
|
87
|
+
mobxObj.syncInProgress = new SyncProgess(options);
|
86
88
|
return perform(options.url || mobxObj.syncUrl, options)
|
87
89
|
.then(action('syncSuccessHandler', (json) => {
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
});
|
90
|
+
mobxObj.syncData = json.data;
|
91
|
+
mobxObj.errors = json.errors;
|
92
|
+
mobxObj.lastServerMessage = json.message;
|
93
|
+
|
93
94
|
// sometimes the polyfill (or fetch iteself) sets a `:success` property?
|
94
95
|
if (false === json[':success']) { merge(mobxObj, { errors: { fetch: json[':message'] } }); }
|
95
96
|
return json;
|
96
97
|
}))
|
97
98
|
.then(action('whenComplete', json => invokeWhenComplete(json, mobxObj.syncInProgress)))
|
98
99
|
.then(action('syncDoneHandler', () => {
|
99
|
-
|
100
|
-
syncInProgress: undefined,
|
101
|
-
});
|
100
|
+
mobxObj.syncInProgress = undefined;
|
102
101
|
return mobxObj;
|
103
102
|
}))
|
104
103
|
.catch(action('syncErrorHandler', (e) => {
|
105
104
|
logger.warn(e);
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
lastServerMessage: e.toString(),
|
110
|
-
});
|
105
|
+
mobxObj.errors = { network: e };
|
106
|
+
mobxObj.syncInProgress = undefined;
|
107
|
+
mobxObj.lastServerMessage = e.toString();
|
111
108
|
return {};
|
112
109
|
}));
|
113
110
|
});
|