lanes 0.8.2 → 0.8.3

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/Gemfile +2 -3
  4. data/client/lanes/boot.jsx +1 -1
  5. data/client/lanes/index.js +0 -11
  6. data/client/lanes/jest/matchers.js +14 -0
  7. data/{lib/js/jest/mocks.js → client/lanes/jest/mocks/fetch.js} +1 -1
  8. data/client/lanes/models/base.js +0 -32
  9. data/client/lanes/screens/definition.js +7 -8
  10. data/client/lanes/screens/index.js +24 -240
  11. data/client/lanes/workspace/menu.jsx +3 -34
  12. data/client/lanes/workspace/screen.jsx +3 -3
  13. data/config/routes.rb +2 -0
  14. data/config/screens.rb +2 -2
  15. data/lanes.gemspec +10 -7
  16. data/lib/lanes/access/authentication_provider.rb +4 -4
  17. data/lib/lanes/api.rb +1 -0
  18. data/lib/lanes/api/default_routes.rb +1 -1
  19. data/lib/lanes/api/handlers/screens.rb +26 -0
  20. data/lib/lanes/api/helper_methods.rb +5 -4
  21. data/lib/lanes/cli.rb +7 -0
  22. data/lib/lanes/command/app.rb +4 -6
  23. data/lib/lanes/command/client_config.rb +59 -0
  24. data/lib/lanes/command/generate_model.rb +4 -4
  25. data/lib/lanes/command/jest.rb +14 -29
  26. data/lib/lanes/command/model_attribute.rb +6 -1
  27. data/lib/lanes/command/named_command.rb +1 -0
  28. data/lib/lanes/command/puma.rb +56 -0
  29. data/lib/lanes/command/server.rb +21 -18
  30. data/lib/lanes/command/webpack.rb +54 -0
  31. data/lib/lanes/extension.rb +0 -7
  32. data/lib/lanes/guard_tasks.rb +21 -20
  33. data/lib/lanes/rake_tasks.rb +13 -0
  34. data/lib/lanes/reloadable_sinatra.rb +24 -0
  35. data/lib/lanes/screen.rb +15 -6
  36. data/lib/lanes/spec_helper.rb +70 -136
  37. data/lib/lanes/version.rb +1 -1
  38. data/package.json +1 -1
  39. data/spec/server/api/controller_base_spec.rb +61 -53
  40. data/spec/server/spec_helper.rb +37 -45
  41. data/templates/client/models/model.js +17 -0
  42. data/templates/config/database.yml +2 -1
  43. data/templates/config/jest.config.json +14 -0
  44. data/templates/config/jest/babel-transform.js +47 -0
  45. data/templates/config/routes.rb +3 -2
  46. data/templates/config/webpack.config.js +1 -1
  47. data/templates/js/jest.config.json +2 -10
  48. data/templates/spec/client/models/model.spec.js +10 -0
  49. data/templates/spec/client/setup.js +9 -0
  50. data/templates/spec/server/spec_helper.rb +3 -11
  51. metadata +40 -41
  52. data/lib/js/jest.config.json +0 -14
  53. data/lib/js/jest/fileMock.js +0 -1
  54. data/lib/js/jest/setup.js +0 -26
  55. data/lib/js/jest/stubs/screen-definitions.js +0 -0
  56. data/lib/js/jest/styleMock.js +0 -1
  57. data/lib/js/webpack.config.js +0 -93
  58. data/lib/lanes/hot_reload_plugin.rb +0 -47
  59. data/lib/lanes/webpack.rb +0 -73
  60. data/spec/server/api/coffeescript_processor_spec.rb +0 -116
  61. data/templates/client/models/Model.coffee +0 -17
  62. data/templates/spec/client/models/ModelSpec.coffee +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4e996b32bc8dc10aa628ae2eaf9683e14f070ae9
4
- data.tar.gz: 7b1e8f708c347328a33e5962068db0df86669ad6
3
+ metadata.gz: fa9dfa9407c5c84e02cac8d1ec0aba080ba79f3b
4
+ data.tar.gz: 6e04d2ad5c485bb3b216b8a0a4b272f7c6ed7f47
5
5
  SHA512:
6
- metadata.gz: 841d9120509bc907ea6e434068b82346e37efdf9ed85baefa2e3f1293c3e947af65ed3c53ae4060f47e89caddcff2e02c72e9c4f785ce869b86a2651dd31fb49
7
- data.tar.gz: 9828cea8c1618a6635b090a19c93260b6ffe1939484325b2e4f26d41040cd786319a9d3893bb692e867a198cd6c0a31f6f461ecdff714ee0948df79c2e31f52d
6
+ metadata.gz: e15bcd8e90226888c02d1fb4a174aba4211a422740d6844f3d6ef22543c48715c540f35c900398a54d500d53a4320e0002dc9a6e2d46a4c0df9e72416fa8268b
7
+ data.tar.gz: d08bb632d089915d690715f11b63277526886db844fa0ceef43a64f755d3af94c712f8f065b5ff6f6f8d89f2f9756269ef0b322e8ae5913a1eab68327f595852
@@ -1,3 +1,5 @@
1
+ Metrics/LineLength:
2
+ Max: 100
1
3
 
2
4
  StringLiterals:
3
5
  Enabled: false
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
- gem "active_record_mocks",
7
- git: 'https://github.com/active_record_mocks',
8
- branch: 'develop'
6
+
7
+ gem "temping"
9
8
 
10
9
  gem 'puma'
11
10
  gem 'pry-byebug'
@@ -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
 
@@ -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
+ };
@@ -49,4 +49,4 @@ fetch.mockResponses = (...responses) => {
49
49
  // Default mock is just a empty string.
50
50
  fetch.mockResponse('');
51
51
 
52
- module.exports = { fetch };
52
+ module.exports = fetch;
@@ -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
- const All = observable.map();
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
- // @session({ type: 'array' }) assets;
39
+
41
40
  @session url;
42
41
 
43
42
  static register(json, comp) {
44
- let screen = All.get(json.id);
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
- All.set(screen.id, screen);
50
- const group = Group.forId(screen.group_id);
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 { computed } from 'mobx';
2
- import { compact } from 'lodash';
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 { createAsyncComponent } from 'react-async-component';
4
+ import Config from '../config';
5
+ import Sync from '../models/sync';
7
6
 
8
- export default {
7
+ import user from '../user';
9
8
 
10
- @computed get active() {
11
- return Instance.active;
12
- },
9
+ const Screens = observable({
13
10
 
14
- @computed get groups() {
15
- return Group.all;
16
- },
11
+ all: observable.map(),
17
12
 
18
- @computed get displaying() {
19
- return Instance.displaying;
20
- },
13
+ active: observable.array(),
21
14
 
15
+ groups: observable.map(),
22
16
 
23
- getDefinition(screenId) {
24
- return Definition.all.get(screenId);
17
+ get activeGroups() {
18
+ return uniq(map(this.active, s => Group.forId(s.group_id)));
25
19
  },
26
20
 
27
- setBrowserLocation(location) {
28
- let instance;
29
- const [instanceId, screenId, ...args] = Array.from(compact(location.pathname.split('/')));
30
- if (!screenId) { return; }
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
- // display(screenId, props = {}) {
44
- // const screen = Definition.all.get(screenId);
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
- // function __guardMethod__(obj, methodName, transform) {
244
- // if (typeof obj !== 'undefined' && obj !== null && typeof obj[methodName] === 'function') {
245
- // return transform(obj, methodName);
246
- // } else {
247
- // return undefined;
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.groups.map(g => <Group key={g.id} group={g} />)}
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>*/