lanes 0.8.2 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/Gemfile +2 -3
- data/client/lanes/boot.jsx +1 -1
- data/client/lanes/index.js +0 -11
- data/client/lanes/jest/matchers.js +14 -0
- data/{lib/js/jest/mocks.js → client/lanes/jest/mocks/fetch.js} +1 -1
- data/client/lanes/models/base.js +0 -32
- data/client/lanes/screens/definition.js +7 -8
- data/client/lanes/screens/index.js +24 -240
- data/client/lanes/workspace/menu.jsx +3 -34
- data/client/lanes/workspace/screen.jsx +3 -3
- data/config/routes.rb +2 -0
- data/config/screens.rb +2 -2
- data/lanes.gemspec +10 -7
- data/lib/lanes/access/authentication_provider.rb +4 -4
- data/lib/lanes/api.rb +1 -0
- data/lib/lanes/api/default_routes.rb +1 -1
- data/lib/lanes/api/handlers/screens.rb +26 -0
- data/lib/lanes/api/helper_methods.rb +5 -4
- data/lib/lanes/cli.rb +7 -0
- data/lib/lanes/command/app.rb +4 -6
- data/lib/lanes/command/client_config.rb +59 -0
- data/lib/lanes/command/generate_model.rb +4 -4
- data/lib/lanes/command/jest.rb +14 -29
- data/lib/lanes/command/model_attribute.rb +6 -1
- data/lib/lanes/command/named_command.rb +1 -0
- data/lib/lanes/command/puma.rb +56 -0
- data/lib/lanes/command/server.rb +21 -18
- data/lib/lanes/command/webpack.rb +54 -0
- data/lib/lanes/extension.rb +0 -7
- data/lib/lanes/guard_tasks.rb +21 -20
- data/lib/lanes/rake_tasks.rb +13 -0
- data/lib/lanes/reloadable_sinatra.rb +24 -0
- data/lib/lanes/screen.rb +15 -6
- data/lib/lanes/spec_helper.rb +70 -136
- data/lib/lanes/version.rb +1 -1
- data/package.json +1 -1
- data/spec/server/api/controller_base_spec.rb +61 -53
- data/spec/server/spec_helper.rb +37 -45
- data/templates/client/models/model.js +17 -0
- data/templates/config/database.yml +2 -1
- data/templates/config/jest.config.json +14 -0
- data/templates/config/jest/babel-transform.js +47 -0
- data/templates/config/routes.rb +3 -2
- data/templates/config/webpack.config.js +1 -1
- data/templates/js/jest.config.json +2 -10
- data/templates/spec/client/models/model.spec.js +10 -0
- data/templates/spec/client/setup.js +9 -0
- data/templates/spec/server/spec_helper.rb +3 -11
- metadata +40 -41
- data/lib/js/jest.config.json +0 -14
- data/lib/js/jest/fileMock.js +0 -1
- data/lib/js/jest/setup.js +0 -26
- data/lib/js/jest/stubs/screen-definitions.js +0 -0
- data/lib/js/jest/styleMock.js +0 -1
- data/lib/js/webpack.config.js +0 -93
- data/lib/lanes/hot_reload_plugin.rb +0 -47
- data/lib/lanes/webpack.rb +0 -73
- data/spec/server/api/coffeescript_processor_spec.rb +0 -116
- data/templates/client/models/Model.coffee +0 -17
- data/templates/spec/client/models/ModelSpec.coffee +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa9dfa9407c5c84e02cac8d1ec0aba080ba79f3b
|
4
|
+
data.tar.gz: 6e04d2ad5c485bb3b216b8a0a4b272f7c6ed7f47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e15bcd8e90226888c02d1fb4a174aba4211a422740d6844f3d6ef22543c48715c540f35c900398a54d500d53a4320e0002dc9a6e2d46a4c0df9e72416fa8268b
|
7
|
+
data.tar.gz: d08bb632d089915d690715f11b63277526886db844fa0ceef43a64f755d3af94c712f8f065b5ff6f6f8d89f2f9756269ef0b322e8ae5913a1eab68327f595852
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
@@ -3,9 +3,8 @@ source 'https://rubygems.org'
|
|
3
3
|
gem "yard-activerecord",
|
4
4
|
git: 'https://github.com/nathanstitt/yard-activerecord',
|
5
5
|
branch: 'develop'
|
6
|
-
|
7
|
-
|
8
|
-
branch: 'develop'
|
6
|
+
|
7
|
+
gem "temping"
|
9
8
|
|
10
9
|
gem 'puma'
|
11
10
|
gem 'pry-byebug'
|
data/client/lanes/boot.jsx
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import ReactDOM from 'react-dom';
|
3
3
|
import whenDomReady from 'when-dom-ready';
|
4
|
-
import { delay } from 'lodash'
|
4
|
+
import { delay } from 'lodash';
|
5
5
|
import { AppContainer } from 'react-hot-loader';
|
6
6
|
import { withAsyncComponents } from 'react-async-component';
|
7
7
|
|
data/client/lanes/index.js
CHANGED
@@ -1,12 +1 @@
|
|
1
|
-
//= require ./lib
|
2
|
-
//= require ./extension
|
3
|
-
//= require ./models
|
4
|
-
//= require ./Config
|
5
|
-
//= require ./react
|
6
|
-
//= require ./components
|
7
|
-
//= require ./screens
|
8
|
-
//= require ./extension/LateLoaded
|
9
|
-
//= require ./Boot
|
10
|
-
|
11
|
-
import Config from './config';
|
12
1
|
import Boot from './boot';
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module.exports = {
|
2
|
+
|
3
|
+
toHaveRendered(wrapper, selector) {
|
4
|
+
const matchCount = wrapper.find(selector).length;
|
5
|
+
const result = { pass: 1 === matchCount };
|
6
|
+
if (result.pass) {
|
7
|
+
result.message = `${selector} was found`;
|
8
|
+
} else {
|
9
|
+
result.message = `Expected wrapper to contain '${selector}' only once, but it was found ${matchCount} times`;
|
10
|
+
}
|
11
|
+
return result;
|
12
|
+
},
|
13
|
+
|
14
|
+
};
|
data/client/lanes/models/base.js
CHANGED
@@ -24,30 +24,6 @@ export {
|
|
24
24
|
field, session, identifier,
|
25
25
|
} from './decorators';
|
26
26
|
|
27
|
-
// const ModelsMap = new Map();
|
28
|
-
|
29
|
-
// lookupModelUsing((propertyName, propertyOptions = {}) =>
|
30
|
-
// ModelsMap[propertyOptions.className] ||
|
31
|
-
// ModelsMap[capitalize(propertyName)] ||
|
32
|
-
// ModelsMap[capitalize(singular(propertyName))],
|
33
|
-
// );
|
34
|
-
|
35
|
-
// rememberModelUsing((klass) => {
|
36
|
-
// invariant(
|
37
|
-
// klass.identifiedBy,
|
38
|
-
// `${klass.name} lacks a static identifiedBy property, use model decorator to auto-set it`,
|
39
|
-
// );
|
40
|
-
// ModelsMap[klass.identifiedBy] = klass;
|
41
|
-
// });
|
42
|
-
|
43
|
-
// const REPLACEABLE_PROP_TYPES = {
|
44
|
-
// hasMany: true, array: true,
|
45
|
-
// };
|
46
|
-
|
47
|
-
// function propIsReplacable(prop) {
|
48
|
-
// return !!REPLACEABLE_PROP_TYPES[prop.type] || REPLACEABLE_PROP_TYPES[get(prop, 'options.type')];
|
49
|
-
// }
|
50
|
-
|
51
27
|
export {
|
52
28
|
observable, computed,
|
53
29
|
};
|
@@ -57,14 +33,6 @@ export class BaseModel {
|
|
57
33
|
return findModel(name);
|
58
34
|
}
|
59
35
|
|
60
|
-
// static get replaceableKeys() {
|
61
|
-
// const replaceable = [];
|
62
|
-
// this.$schema.forEach((prop, name) => {
|
63
|
-
// if (propIsReplacable(prop)) { replaceable.push(name); }
|
64
|
-
// });
|
65
|
-
// return replaceable;
|
66
|
-
// }
|
67
|
-
|
68
36
|
static get assignableKeys() {
|
69
37
|
return this.$schema.keys();
|
70
38
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { autorun, observable } from 'mobx';
|
2
|
-
import { get, delay, extend, filter } from 'lodash';
|
2
|
+
import { get, delay, extend, filter, map, uniq } from 'lodash';
|
3
3
|
|
4
4
|
import { classify, logger } from '../lib/util';
|
5
5
|
import Config from '../config'
|
@@ -16,14 +16,13 @@ import Group from './group';
|
|
16
16
|
import { createAsyncComponent } from 'react-async-component';
|
17
17
|
|
18
18
|
export { createAsyncComponent };
|
19
|
+
import Registry from './index';
|
19
20
|
|
20
|
-
|
21
|
+
import Groups from './group';
|
21
22
|
|
22
23
|
@modelDecorator('lanes/screen/definition')
|
23
24
|
export default class ScreenDefinition extends BaseModel {
|
24
25
|
|
25
|
-
static all = All;
|
26
|
-
|
27
26
|
@identifier({ type: 'string' }) id;
|
28
27
|
@session title;
|
29
28
|
@session url_prefix;
|
@@ -37,17 +36,17 @@ export default class ScreenDefinition extends BaseModel {
|
|
37
36
|
@session model;
|
38
37
|
@session({ type: 'object' }) component;
|
39
38
|
@session asset;
|
40
|
-
|
39
|
+
|
41
40
|
@session url;
|
42
41
|
|
43
42
|
static register(json, comp) {
|
44
|
-
let screen =
|
43
|
+
let screen = Registry.all.get(json.id);
|
45
44
|
if (screen) {
|
46
45
|
screen.update(json);
|
47
46
|
} else {
|
48
47
|
screen = new ScreenDefinition(json);
|
49
|
-
|
50
|
-
const group =
|
48
|
+
Registry.all.set(screen.id, screen);
|
49
|
+
const group = Groups.forId(screen.group_id);
|
51
50
|
if (group) { group.screens.push(screen); }
|
52
51
|
}
|
53
52
|
screen.component = comp;
|
@@ -1,252 +1,36 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import Instance from './instance';
|
4
|
-
import Definition from './definition';
|
1
|
+
import { observable, autorun } from 'mobx';
|
2
|
+
import { map, uniq } from 'lodash';
|
5
3
|
import Group from './group';
|
6
|
-
import
|
4
|
+
import Config from '../config';
|
5
|
+
import Sync from '../models/sync';
|
7
6
|
|
8
|
-
|
7
|
+
import user from '../user';
|
9
8
|
|
10
|
-
|
11
|
-
return Instance.active;
|
12
|
-
},
|
9
|
+
const Screens = observable({
|
13
10
|
|
14
|
-
|
15
|
-
return Group.all;
|
16
|
-
},
|
11
|
+
all: observable.map(),
|
17
12
|
|
18
|
-
|
19
|
-
return Instance.displaying;
|
20
|
-
},
|
13
|
+
active: observable.array(),
|
21
14
|
|
15
|
+
groups: observable.map(),
|
22
16
|
|
23
|
-
|
24
|
-
return
|
17
|
+
get activeGroups() {
|
18
|
+
return uniq(map(this.active, s => Group.forId(s.group_id)));
|
25
19
|
},
|
26
20
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
if (instanceId) {
|
32
|
-
instance = Instance.displaying.findInstance(screenId, instanceId);
|
33
|
-
} else {
|
34
|
-
instance = Instance.displaying.find((instance) => instance.screen.id === screenId);
|
35
|
-
}
|
36
|
-
if (instance) {
|
37
|
-
instance.active = true;
|
38
|
-
} else {
|
39
|
-
this.display(screenId, { args });
|
40
|
-
}
|
21
|
+
refresh() {
|
22
|
+
Sync.perform(`${Config.api_path}/lanes/screens`).then(({ data: { screens: screenIds } }) => {
|
23
|
+
this.active.replace(map(screenIds, id => this.all.get(id)));
|
24
|
+
});
|
41
25
|
},
|
42
26
|
|
43
|
-
|
44
|
-
|
45
|
-
// if (!screen) {
|
46
|
-
// msg = `Unable to find screen definition for ${screenId}`;
|
47
|
-
// logger.warn(msg);
|
48
|
-
// Promise.reject(msg);
|
49
|
-
// }
|
50
|
-
// return new Instance({ screen, props, active: true });
|
51
|
-
// },
|
52
|
-
};
|
53
|
-
|
54
|
-
// import { autorun, observable } from 'mobx';
|
55
|
-
// import { get, delay, extend } from 'lodash';
|
56
|
-
|
57
|
-
// import { classify, warn } from '../lib/util';
|
58
|
-
// import RequestAssets from '../lib/RequestAssets';
|
59
|
-
|
60
|
-
// import {
|
61
|
-
// BaseModel, modelDecorator, session,
|
62
|
-
// belongsTo, identifier, computed,
|
63
|
-
// } from '../models/base';
|
64
|
-
// import User from '../User';
|
65
|
-
|
66
|
-
// import ScreenDefinition from './definition';
|
67
|
-
|
68
|
-
// let Displaying;
|
69
|
-
// let All;
|
70
|
-
|
71
|
-
|
72
|
-
// All = observable.map([]);
|
73
|
-
// const registerScreen = (json) => {
|
74
|
-
// const definition = new ScreenDefinition(json);
|
75
|
-
// All.set(json.id, definition);
|
76
|
-
// return definition;
|
77
|
-
// }
|
78
|
-
|
79
|
-
// const registerGroup = (json) => {
|
80
|
-
// const group = new Group(json)
|
81
|
-
// Groups.set(json.id, new Group(json));
|
82
|
-
// return group;
|
83
|
-
// }
|
84
|
-
|
85
|
-
// export { All, registerScreen, registerGroup };
|
86
|
-
|
87
|
-
|
88
|
-
// @modelDecorator('ScreenViewSet')
|
89
|
-
// class ScreenViewSet extends BaseModel {
|
90
|
-
|
91
|
-
// // static model = ScreenView;
|
92
|
-
|
93
|
-
|
94
|
-
// active() {
|
95
|
-
// return this.findWhere({ active: true });
|
96
|
-
// }
|
97
|
-
|
98
|
-
// constructor(models, options) {
|
99
|
-
// super();
|
100
|
-
// if (options == null) { options = {}; }
|
101
|
-
// autorun(this::onUserChange);
|
102
|
-
// }
|
103
|
-
|
104
|
-
// onUserChange() {
|
105
|
-
// if (User.isLoggedIn) {
|
106
|
-
// get(User, 'options.initial_screens', []).forEach(
|
107
|
-
// screenId => All.get(screenId).display(),
|
108
|
-
// );
|
109
|
-
// } else {
|
110
|
-
// this.reset();
|
111
|
-
// }
|
112
|
-
// }
|
113
|
-
|
114
|
-
// remove(model) {
|
115
|
-
// const index = this.indexOf(model);
|
116
|
-
// super.remove(...arguments);
|
117
|
-
// if (model.active && this.length) {
|
118
|
-
// this.at(_.min([index, this.length - 1])).active = true;
|
119
|
-
// }
|
120
|
-
// model.active = false;
|
121
|
-
// return this;
|
122
|
-
// }
|
123
|
-
|
124
|
-
// @computed onActiveChange(changed, active) {
|
125
|
-
// if (!changed.active) { return; }
|
126
|
-
// return this.each(function(screen) {
|
127
|
-
// if (screen !== changed) { return screen.set({ active: false }); }
|
128
|
-
// });
|
129
|
-
// }
|
130
|
-
|
131
|
-
// activateNext() { return this._moveActive(+1); }
|
132
|
-
// activatePrev() { return this._moveActive(-1); }
|
133
|
-
|
134
|
-
// _moveActive(inc) {
|
135
|
-
// if (this.length === 1) { return; }
|
136
|
-
// let current = this.findIndexWhere({ active: true });
|
137
|
-
// if (current === -1) { return; }
|
138
|
-
// if ((inc > 0) && (current === (this.length - 1))) {
|
139
|
-
// current = -1;
|
140
|
-
// }
|
141
|
-
// if ((inc < 0) && (current === 0)) {
|
142
|
-
// current = this.length;
|
143
|
-
// }
|
144
|
-
// return this.at(current + inc).active = true;
|
145
|
-
// }
|
146
|
-
|
147
|
-
// findInstance(screenId, instanceId) {
|
148
|
-
// return this.find(instance => (instance.screen.id === screenId) && (instance.id === instanceId));
|
149
|
-
// }
|
150
|
-
// }
|
151
|
-
|
152
|
-
//ScreenViewSet.initClass();
|
153
|
-
|
154
|
-
// @SerializableModel
|
155
|
-
// class ScreenSet extends BaseModel {
|
156
|
-
|
157
|
-
// @observable.map models;
|
158
|
-
|
159
|
-
// // static initClass() {
|
160
|
-
// // this.prototype.model = ScreenDefinition;
|
161
|
-
// // this.prototype.register = Lanes.emptyFn;
|
162
|
-
// // }
|
163
|
-
|
164
|
-
// get(id) {
|
165
|
-
|
166
|
-
// }
|
167
|
-
|
168
|
-
// addScreen(screen) {
|
169
|
-
// const screen = this.add( screen );
|
170
|
-
// return screen.set({active:true});
|
171
|
-
// }
|
172
|
-
|
173
|
-
// isLoading() {
|
174
|
-
// return !!this.findWhere({loading: true});
|
175
|
-
// }
|
176
|
-
// }
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
// @modelDecorator('MenuGroupSet')
|
183
|
-
// class MenuGroupSet extends BaseModel {
|
184
|
-
// // static initClass() {
|
185
|
-
// // this.prototype.model = MenuGroup;
|
186
|
-
// // }
|
187
|
-
|
188
|
-
// constructor() {
|
189
|
-
// super(...arguments);
|
190
|
-
// }
|
191
|
-
|
192
|
-
// available() {
|
193
|
-
// return this.cache || (this.cache = new Lanes.Models.SubCollection(this, {
|
194
|
-
// filter(group) {
|
195
|
-
// group.screens().filter();
|
196
|
-
// return group.screens().length > 0;
|
197
|
-
// }
|
198
|
-
// }));
|
199
|
-
// }
|
200
|
-
// }
|
201
|
-
|
202
|
-
|
203
|
-
// Lanes.Screens.display_id = function(screen_id) {
|
204
|
-
// const definition = Lanes.Screens.Definitions.all.get(screen_id);
|
205
|
-
// if (definition) {
|
206
|
-
// return definition.display();
|
207
|
-
// } else {
|
208
|
-
// return Lanes.warn(`Unable to find definition for screen ${screen_id}`);
|
209
|
-
// }
|
210
|
-
// };
|
211
|
-
|
212
|
-
|
213
|
-
// Definitions = {
|
214
|
-
|
215
|
-
// displaying: new ScreenViewSet([], { single_active_only: true }),
|
216
|
-
// groups: new MenuGroupSet,
|
217
|
-
// register(spec) {
|
218
|
-
// return this.all.add( spec );
|
219
|
-
// },
|
220
|
-
// setBrowserLocation(location) {
|
221
|
-
// let instance;
|
222
|
-
// const [instanceId, screenId, ...args] = Array.from(_.compact(location.pathname.split('/')));
|
223
|
-
// if (!screenId) { return; }
|
224
|
-
|
225
|
-
// if (instanceId && ( instance = this.displaying.findInstance(screenId, instanceId) )) {
|
226
|
-
// return instance.active = true;
|
227
|
-
// } else {
|
228
|
-
// return __guard__(this.all.get(screenId), x => x.display({id: instanceId, props: {args}}));
|
229
|
-
// }
|
230
|
-
// }
|
231
|
-
|
232
|
-
// };
|
233
|
-
|
234
|
-
// Lanes.current_user.on("change:isLoggedIn", function(user) {
|
235
|
-
// Lanes.Screens.Definitions.groups.each(group => delete group.cache);
|
236
|
-
// delete Lanes.Screens.Definitions.groups.cache;
|
237
|
-
|
238
|
-
// if (!user.isLoggedIn) {
|
239
|
-
// return Lanes.Screens.Definitions.displaying.reset();
|
240
|
-
// }
|
241
|
-
// });
|
27
|
+
});
|
28
|
+
export default Screens;
|
242
29
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
// function __guard__(value, transform) {
|
251
|
-
// return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
|
252
|
-
// }
|
30
|
+
let previousLoggedIn = null;
|
31
|
+
autorun(() => {
|
32
|
+
if (user.isLoggedIn !== previousLoggedIn){
|
33
|
+
previousLoggedIn = user.isLoggedIn;
|
34
|
+
Screens.refresh();
|
35
|
+
}
|
36
|
+
});
|
@@ -16,11 +16,10 @@ import Icon from '../components/icon';
|
|
16
16
|
import User from '../user';
|
17
17
|
|
18
18
|
const OnLogoutClick = (ev) => {
|
19
|
-
debugger
|
20
19
|
ev.stopPropagation();
|
21
20
|
ev.preventDefault();
|
22
21
|
User.logout();
|
23
|
-
}
|
22
|
+
};
|
24
23
|
|
25
24
|
function Logout() {
|
26
25
|
return (
|
@@ -32,19 +31,8 @@ function Logout() {
|
|
32
31
|
);
|
33
32
|
}
|
34
33
|
|
34
|
+
@observer
|
35
35
|
export default class WorkspaceMenu extends React.Component {
|
36
|
-
/* renderGroup(group) {
|
37
|
-
* return (
|
38
|
-
* <ScreenGroup {...this.props} model={group} key={group.id} />
|
39
|
-
* );
|
40
|
-
* }
|
41
|
-
|
42
|
-
* logOut(ev) {
|
43
|
-
* ev.preventDefault();
|
44
|
-
* return (
|
45
|
-
* Lanes.current_user.logout()
|
46
|
-
* );
|
47
|
-
* }*/
|
48
36
|
|
49
37
|
render() {
|
50
38
|
return (
|
@@ -55,7 +43,7 @@ export default class WorkspaceMenu extends React.Component {
|
|
55
43
|
<Header justify="between" size="large" pad={{ horizontal: 'medium' }}>
|
56
44
|
Logo
|
57
45
|
</Header>
|
58
|
-
{Screens.
|
46
|
+
{Screens.activeGroups.map(g => <Group key={g.id} group={g} />)}
|
59
47
|
<Footer size="large" primary pad={{ horizontal: 'medium' }}>
|
60
48
|
<Logout />
|
61
49
|
</Footer>
|
@@ -63,22 +51,3 @@ export default class WorkspaceMenu extends React.Component {
|
|
63
51
|
);
|
64
52
|
}
|
65
53
|
}
|
66
|
-
|
67
|
-
/*
|
68
|
-
*
|
69
|
-
* <div className="screens-menu">
|
70
|
-
* <div className="screens-menu-content">
|
71
|
-
* <ul className="navigation">
|
72
|
-
* {Screens.groups.map(g => <Group key={g.id} group={g} />)}
|
73
|
-
* </ul>
|
74
|
-
* </div>
|
75
|
-
* <ul className="navigation">
|
76
|
-
* <li
|
77
|
-
* className="group logout"
|
78
|
-
* data-tooltip-message="Log Out"
|
79
|
-
* data-placement="right"
|
80
|
-
* >
|
81
|
-
* <Logout />
|
82
|
-
* </li>
|
83
|
-
* </ul>
|
84
|
-
* </div>*/
|