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
@@ -3,9 +3,12 @@ import {
|
|
3
3
|
BaseExtension, identifiedBy, identifier,
|
4
4
|
} from './base';
|
5
5
|
|
6
|
+
import Extensions from './index';
|
7
|
+
|
6
8
|
@identifiedBy('extensions/hippo')
|
7
9
|
export default class HippoExtension extends BaseExtension {
|
8
|
-
|
9
10
|
@identifier id = 'hippo';
|
10
|
-
|
11
11
|
}
|
12
|
+
|
13
|
+
|
14
|
+
Extensions.register(HippoExtension);
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { invoke, each } from 'lodash';
|
2
2
|
import { observable } from 'mobx';
|
3
3
|
|
4
|
-
|
4
|
+
const Extensions = {
|
5
5
|
|
6
6
|
instances: observable.map(),
|
7
7
|
|
@@ -38,10 +38,16 @@ export default {
|
|
38
38
|
},
|
39
39
|
|
40
40
|
setBootstrapData(bootstrapData) {
|
41
|
-
|
41
|
+
if (bootstrapData.controlling_extension) {
|
42
|
+
this.controlling_id = bootstrapData.controlling_extension;
|
43
|
+
}
|
42
44
|
this.instances.forEach((instance, key) => {
|
43
|
-
|
45
|
+
if (bootstrapData[key]) {
|
46
|
+
invoke(instance, 'setBootstrapData', bootstrapData[key]);
|
47
|
+
}
|
44
48
|
});
|
45
49
|
},
|
46
50
|
|
47
51
|
};
|
52
|
+
|
53
|
+
export default Extensions;
|
data/client/hippo/lib/util.js
CHANGED
@@ -29,7 +29,7 @@ export function titleize(words) {
|
|
29
29
|
return (words)
|
30
30
|
.replace(/[\W_]/g, ' ')
|
31
31
|
.replace(/\S+/g, word => (word.charAt(0).toUpperCase() + word.slice(1)),
|
32
|
-
|
32
|
+
);
|
33
33
|
}
|
34
34
|
|
35
35
|
export function underscored(str) {
|
@@ -41,15 +41,15 @@ export function underscored(str) {
|
|
41
41
|
|
42
42
|
export function humanize(str) {
|
43
43
|
return capitalize(trim(underscored(str)
|
44
|
-
|
45
|
-
|
44
|
+
.replace(/_id$/, '')
|
45
|
+
.replace(/_/g, ' ')));
|
46
46
|
}
|
47
47
|
|
48
48
|
export function renameProperties(object, keyMap) {
|
49
49
|
each(keyMap, (to, from) => {
|
50
50
|
if (object[from]) {
|
51
51
|
object[to] = object[from]; // eslint-disable-line no-param-reassign
|
52
|
-
delete object[from];
|
52
|
+
delete object[from]; // eslint-disable-line no-param-reassign
|
53
53
|
}
|
54
54
|
});
|
55
55
|
return object;
|
@@ -1,5 +1,5 @@
|
|
1
|
-
import { includes, get } from 'lodash';
|
2
|
-
import { observe } from 'mobx';
|
1
|
+
import { includes, get, extend } from 'lodash';
|
2
|
+
import { observe, action } from 'mobx';
|
3
3
|
import {
|
4
4
|
BaseModel, identifiedBy, field, session, identifier, computed,
|
5
5
|
} from './base';
|
@@ -15,10 +15,8 @@ const UPDATE_METHODS = { POST: true, PUT: true, PATCH: true };
|
|
15
15
|
|
16
16
|
@identifiedBy('hippo/asset')
|
17
17
|
export default class Asset extends BaseModel {
|
18
|
-
|
19
18
|
@identifier id;
|
20
19
|
@field order;
|
21
|
-
@session file_data;
|
22
20
|
|
23
21
|
@session file;
|
24
22
|
|
@@ -30,27 +28,50 @@ export default class Asset extends BaseModel {
|
|
30
28
|
|
31
29
|
constructor(props) {
|
32
30
|
super(props);
|
33
|
-
observe(this, 'owner',
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
!this.syncInProgress &&
|
39
|
-
!oldValue &&
|
40
|
-
newValue && newValue.isUpdate
|
41
|
-
) {
|
42
|
-
newValue.whenComplete(() => this.save());
|
43
|
-
}
|
44
|
-
});
|
45
|
-
}, true);
|
31
|
+
observe(this, 'owner', this.onOwnerChange, true);
|
32
|
+
}
|
33
|
+
|
34
|
+
static get syncUrl() {
|
35
|
+
return Config.api_path + Config.assets_path_prefix;
|
46
36
|
}
|
47
37
|
|
48
|
-
|
49
|
-
|
38
|
+
|
39
|
+
@action.bound
|
40
|
+
onOwnerChange({ newValue: owner }) {
|
41
|
+
if (this.ownerSaveDisposer) { this.ownerSaveDisposer(); }
|
42
|
+
if (!owner || !owner.isModel) { return; }
|
43
|
+
this.ownerSaveDisposer = observe(owner, 'syncInProgress', ({ newValue, oldValue }) => {
|
44
|
+
if (this.isDirty &&
|
45
|
+
!this.syncInProgress &&
|
46
|
+
!oldValue &&
|
47
|
+
newValue && newValue.isUpdate
|
48
|
+
) {
|
49
|
+
newValue.whenComplete(() => this.save());
|
50
|
+
}
|
51
|
+
});
|
50
52
|
}
|
51
53
|
|
54
|
+
setFile(file) {
|
55
|
+
if (file.preview) {
|
56
|
+
this.file = file;
|
57
|
+
return Promise.resolve(this);
|
58
|
+
}
|
59
|
+
return new Promise((resolve) => {
|
60
|
+
const reader = new FileReader();
|
61
|
+
reader.onloadend = (ev) => {
|
62
|
+
if ('loadend' === ev.type) {
|
63
|
+
extend(file, { preview: reader.result });
|
64
|
+
this.file = file;
|
65
|
+
resolve(this);
|
66
|
+
}
|
67
|
+
};
|
68
|
+
reader.readAsDataURL(file);
|
69
|
+
});
|
70
|
+
}
|
71
|
+
|
72
|
+
|
52
73
|
@computed get isDirty() {
|
53
|
-
return
|
74
|
+
return Boolean(this.isNew || !this.file);
|
54
75
|
}
|
55
76
|
|
56
77
|
@computed get exists() {
|
@@ -68,13 +89,13 @@ export default class Asset extends BaseModel {
|
|
68
89
|
);
|
69
90
|
}
|
70
91
|
|
71
|
-
|
92
|
+
get previewUrl() {
|
72
93
|
return get(this, 'file.preview', this.urlFor('thumbnail'));
|
73
94
|
}
|
74
95
|
|
75
96
|
urlFor(type = 'original') {
|
76
97
|
const url = get(this, `file_data.${type}.id`);
|
77
|
-
return url ? `${this.
|
98
|
+
return url ? `${Config.api_host}${this.constructor.syncUrl}/${url}` : null;
|
78
99
|
}
|
79
100
|
|
80
101
|
save() {
|
@@ -98,5 +119,4 @@ export default class Asset extends BaseModel {
|
|
98
119
|
return json;
|
99
120
|
}).then(json => this.set(json.data));
|
100
121
|
}
|
101
|
-
|
102
122
|
}
|
data/client/hippo/models/base.js
CHANGED
@@ -29,7 +29,6 @@ export {
|
|
29
29
|
};
|
30
30
|
|
31
31
|
export class BaseModel {
|
32
|
-
|
33
32
|
static get propType() {
|
34
33
|
return PropTypes.instanceOf(this);
|
35
34
|
}
|
@@ -122,7 +121,7 @@ export class BaseModel {
|
|
122
121
|
|
123
122
|
fetch(options = {}) {
|
124
123
|
invariant((!this.isNew || options.query),
|
125
|
-
|
124
|
+
'Unable to fetch record without it’s identifier being set or a query');
|
126
125
|
const fetchOptions = extend(options, { limit: 1, method: 'GET' });
|
127
126
|
if (!fetchOptions.query) {
|
128
127
|
fetchOptions.query = { [`${this.constructor.identifierFieldName}`]: this.identifierFieldValue };
|
@@ -36,20 +36,20 @@ function validateChangeType(validator, propertyName, change) {
|
|
36
36
|
invariant(VALIDATORS[validator], `Unknown TypeCheck: ${validator} does not exist`);
|
37
37
|
if (COERCE[validator]) { COERCE[validator](change); }
|
38
38
|
invariant(VALIDATORS[validator](change.newValue),
|
39
|
-
|
39
|
+
`Bad Type: Attempted to set ${propertyName} to '${change.newValue}' which is not ${validator}`);
|
40
40
|
return change;
|
41
41
|
}
|
42
42
|
|
43
43
|
function addTypeSafeInterceptor(target, property, type) {
|
44
44
|
if (isEmpty(type)) { return; }
|
45
45
|
addLazyInitializer(target, (partial(intercept, partial.placeholder, property,
|
46
|
-
|
46
|
+
partial(validateChangeType, type, property))));
|
47
47
|
}
|
48
48
|
|
49
49
|
function decoratorWrapper(decorator, defaultOptions = {}) {
|
50
50
|
return (targetOrOptions, ...args) => {
|
51
51
|
const options = isEmpty(args) ?
|
52
|
-
|
52
|
+
defaults(targetOrOptions, defaultOptions) : defaultOptions;
|
53
53
|
|
54
54
|
const wrap = (target, property, descriptor) => {
|
55
55
|
const decorationFn = decorator(options);
|
@@ -1,9 +1,8 @@
|
|
1
1
|
import { Atom, when, reaction } from 'mobx';
|
2
2
|
import ActionCable from 'actioncable';
|
3
3
|
import invariant from 'invariant';
|
4
|
-
import {
|
4
|
+
import { invoke, mapValues } from 'lodash';
|
5
5
|
|
6
|
-
import { logger } from '../lib/util';
|
7
6
|
import User from '../user';
|
8
7
|
import Config from '../config';
|
9
8
|
|
@@ -12,7 +11,6 @@ import PubSubCableChannel from './pub_sub/channel';
|
|
12
11
|
let PubSub;
|
13
12
|
|
14
13
|
class PubSubMap {
|
15
|
-
|
16
14
|
constructor(modelKlass) {
|
17
15
|
this.channel_prefix = modelKlass.identifiedBy;
|
18
16
|
this.map = Object.create(null);
|
@@ -53,7 +51,7 @@ class PubSubMap {
|
|
53
51
|
remove(model) {
|
54
52
|
const { id, models } = this.forModel(model);
|
55
53
|
const indx = models.indexOf(model);
|
56
|
-
invariant(-1 !== indx,
|
54
|
+
invariant(-1 !== indx, 'Asked to remove model from pubsub but it was never observed');
|
57
55
|
if (1 === models.length) {
|
58
56
|
delete this.map[id];
|
59
57
|
PubSub.channel.unsubscribe(this.channelForId(id));
|
@@ -120,7 +118,6 @@ export function stop() {
|
|
120
118
|
}
|
121
119
|
|
122
120
|
export class PubSubAtom {
|
123
|
-
|
124
121
|
constructor(model) {
|
125
122
|
this.model = model;
|
126
123
|
if (model.identifierFieldValue) {
|
@@ -2,7 +2,6 @@ import { filter, reduce, find } from 'lodash';
|
|
2
2
|
import { computed } from 'mobx';
|
3
3
|
|
4
4
|
export default class Info {
|
5
|
-
|
6
5
|
constructor(query) {
|
7
6
|
this.query = query;
|
8
7
|
}
|
@@ -38,6 +37,4 @@ export default class Info {
|
|
38
37
|
const property = this.query.src.identifierFieldName;
|
39
38
|
return find(this.query.fields, { id: property });
|
40
39
|
}
|
41
|
-
|
42
|
-
|
43
40
|
}
|
@@ -4,7 +4,6 @@ import {
|
|
4
4
|
|
5
5
|
@identifiedBy('hippo/query/operators/operator')
|
6
6
|
export default class Operator extends BaseModel {
|
7
|
-
|
8
7
|
@identifier({ type: 'string' }) id;
|
9
8
|
@session label;
|
10
9
|
@session selected;
|
@@ -17,5 +16,4 @@ export default class Operator extends BaseModel {
|
|
17
16
|
if (!this.types.length) { return true; }
|
18
17
|
return !!this.types.find(t => t === field.queryType);
|
19
18
|
}
|
20
|
-
|
21
19
|
}
|
data/client/hippo/models/sync.js
CHANGED
@@ -82,7 +82,7 @@ function perform(urlPrefix, defaultOptions = {}) {
|
|
82
82
|
}
|
83
83
|
|
84
84
|
const peformMobxyRequest = action('SyncforModel', (mobxObj, options = {}) => {
|
85
|
-
mobxObj.syncInProgress = new SyncProgess(options);
|
85
|
+
mobxObj.syncInProgress = new SyncProgess(options); // eslint-disable-line no-param-reassign
|
86
86
|
return perform(options.url || mobxObj.syncUrl, options)
|
87
87
|
.then(action('syncSuccessHandler', (json) => {
|
88
88
|
extend(mobxObj, {
|
@@ -8,7 +8,6 @@ import Asset from './asset';
|
|
8
8
|
|
9
9
|
@identifiedBy('hippo/system-settings')
|
10
10
|
export default class SystemSettings extends BaseModel {
|
11
|
-
|
12
11
|
@identifier id;
|
13
12
|
@field({ type: 'object' }) settings;
|
14
13
|
|
@@ -22,5 +21,4 @@ export default class SystemSettings extends BaseModel {
|
|
22
21
|
@computed get syncUrl() {
|
23
22
|
return this.constructor.syncUrl;
|
24
23
|
}
|
25
|
-
|
26
24
|
}
|
@@ -12,7 +12,6 @@ export { asyncComponent } from 'react-async-component';
|
|
12
12
|
|
13
13
|
@identifiedBy('hippo/screen/definition')
|
14
14
|
export default class ScreenDefinition extends BaseModel {
|
15
|
-
|
16
15
|
@identifier({ type: 'string' }) id;
|
17
16
|
@session title;
|
18
17
|
@session url_prefix;
|
@@ -63,5 +62,4 @@ export default class ScreenDefinition extends BaseModel {
|
|
63
62
|
instance.isActive = true;
|
64
63
|
return instance;
|
65
64
|
}
|
66
|
-
|
67
65
|
}
|
@@ -7,7 +7,6 @@ const All = observable.array();
|
|
7
7
|
|
8
8
|
@identifiedBy('ScreensGroup')
|
9
9
|
export default class ScreensGroup extends BaseModel {
|
10
|
-
|
11
10
|
static all = All;
|
12
11
|
|
13
12
|
@identifier({ type: 'string' }) id;
|
@@ -31,5 +30,4 @@ export default class ScreensGroup extends BaseModel {
|
|
31
30
|
}
|
32
31
|
return group;
|
33
32
|
}
|
34
|
-
|
35
33
|
}
|
@@ -6,7 +6,6 @@ import {
|
|
6
6
|
} from '../models/base';
|
7
7
|
|
8
8
|
class InstanceCollection {
|
9
|
-
|
10
9
|
@observable models = []
|
11
10
|
@observable active;
|
12
11
|
|
@@ -33,7 +32,6 @@ class InstanceCollection {
|
|
33
32
|
|
34
33
|
add(model) { this.models.push(model); }
|
35
34
|
remove(model) { this.models.remove(model); }
|
36
|
-
|
37
35
|
}
|
38
36
|
|
39
37
|
const displaying = new InstanceCollection();
|
@@ -41,7 +39,6 @@ export { displaying };
|
|
41
39
|
|
42
40
|
@identifiedBy('hippo/screen-view')
|
43
41
|
export default class Instance extends BaseModel {
|
44
|
-
|
45
42
|
static get displaying() {
|
46
43
|
return displaying.models;
|
47
44
|
}
|