hippo-fw 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +0 -3
  3. data/.nvmrc +1 -2
  4. data/.ruby-version +1 -1
  5. data/Rakefile +1 -1
  6. data/client/hippo/access/login-dialog.jsx +2 -0
  7. data/client/hippo/boot.jsx +12 -0
  8. data/client/hippo/components/asset.jsx +5 -1
  9. data/client/hippo/components/asset.scss +1 -0
  10. data/client/hippo/components/data-list.jsx +6 -4
  11. data/client/hippo/components/data-table.jsx +7 -6
  12. data/client/hippo/components/data-table/header-cell.jsx +2 -0
  13. data/client/hippo/components/date-time.jsx +12 -2
  14. data/client/hippo/components/form/api.js +12 -0
  15. data/client/hippo/components/form/fields.jsx +8 -1
  16. data/client/hippo/components/form/fields/checkbox-wrapper.jsx +2 -0
  17. data/client/hippo/components/form/fields/date-wrapper.jsx +2 -0
  18. data/client/hippo/components/form/fields/form-field.scss +2 -0
  19. data/client/hippo/components/form/fields/label.jsx +2 -0
  20. data/client/hippo/components/form/fields/react-tags.scss +170 -0
  21. data/client/hippo/components/form/fields/select-wrapper.jsx +2 -0
  22. data/client/hippo/components/form/fields/tags-wrapper.jsx +46 -0
  23. data/client/hippo/components/form/fields/text-wrapper.jsx +9 -1
  24. data/client/hippo/components/form/fields/textarea-wrapper.jsx +15 -0
  25. data/client/hippo/components/form/wrapper.jsx +21 -1
  26. data/client/hippo/components/help.jsx +21 -0
  27. data/client/hippo/components/master-detail.jsx +2 -0
  28. data/client/hippo/components/network-activity-overlay.jsx +3 -1
  29. data/client/hippo/components/popout-window.jsx +126 -0
  30. data/client/hippo/components/query-builder.jsx +9 -117
  31. data/client/hippo/components/query-builder/boolean-picker.jsx +28 -0
  32. data/client/hippo/components/query-builder/clause-filter.jsx +58 -0
  33. data/client/hippo/components/query-builder/clause.jsx +98 -0
  34. data/client/hippo/components/query-builder/date-picker.jsx +23 -0
  35. data/client/hippo/components/query-builder/query-builder.scss +7 -0
  36. data/client/hippo/components/record-finder.jsx +2 -0
  37. data/client/hippo/components/record-finder/query-layer.jsx +5 -1
  38. data/client/hippo/components/save-button.jsx +7 -1
  39. data/client/hippo/components/screen.jsx +2 -0
  40. data/client/hippo/components/text-editor.jsx +4 -5
  41. data/client/hippo/components/text-editor/display-modes/Button.jsx +5 -2
  42. data/client/hippo/components/text-editor/display-modes/ToggleEdit.jsx +2 -1
  43. data/client/hippo/components/text-editor/display-modes/ToggleInsert.jsx +2 -1
  44. data/client/hippo/components/text-editor/display-modes/ToggleLayout.jsx +2 -1
  45. data/client/hippo/components/text-editor/display-modes/TogglePreview.jsx +2 -1
  46. data/client/hippo/components/text-editor/display-modes/ToggleResize.jsx +2 -1
  47. data/client/hippo/components/text-editor/display-modes/index.js +7 -7
  48. data/client/hippo/components/text-editor/image-plugin/Component/Display/index.js +4 -2
  49. data/client/hippo/components/text-editor/image-plugin/Component/Form/index.js +2 -0
  50. data/client/hippo/components/text-editor/renderer.jsx +2 -0
  51. data/client/hippo/components/text-editor/text-editor.scss +13 -4
  52. data/client/hippo/components/time-zone-select.jsx +2 -0
  53. data/client/hippo/components/tool-tip.jsx +2 -0
  54. data/client/hippo/extensions/base.js +2 -0
  55. data/client/hippo/extensions/hippo.js +2 -0
  56. data/client/hippo/lib/__mocks__/request-assets.js +1 -2
  57. data/client/hippo/lib/bootstrap.js +2 -0
  58. data/client/hippo/lib/computed-properties.js +24 -0
  59. data/client/hippo/lib/date-range.js +13 -2
  60. data/client/hippo/lib/request-assets.js +3 -2
  61. data/client/hippo/lib/smooth-scroll.js +2 -0
  62. data/client/hippo/lib/util.js +1 -2
  63. data/client/hippo/models/asset.js +2 -0
  64. data/client/hippo/models/base.js +5 -2
  65. data/client/hippo/models/collection.js +2 -0
  66. data/client/hippo/models/config.js +3 -1
  67. data/client/hippo/models/pub_sub.js +2 -0
  68. data/client/hippo/models/pub_sub/channel.js +2 -0
  69. data/client/hippo/models/pub_sub/map.js +2 -0
  70. data/client/hippo/models/query.js +21 -12
  71. data/client/hippo/models/query/array-result.js +52 -16
  72. data/client/hippo/models/query/clause.js +11 -4
  73. data/client/hippo/models/query/field.js +2 -1
  74. data/client/hippo/models/query/info.js +7 -1
  75. data/client/hippo/models/query/operator.js +2 -0
  76. data/client/hippo/models/query/result.js +2 -0
  77. data/client/hippo/models/query/types.js +4 -0
  78. data/client/hippo/models/sync.js +2 -0
  79. data/client/hippo/models/system-setting.js +1 -15
  80. data/client/hippo/models/tenant.js +23 -7
  81. data/client/hippo/react/Root.jsx +2 -0
  82. data/client/hippo/react/component-not-found.jsx +2 -0
  83. data/client/hippo/screens/definition.js +2 -0
  84. data/client/hippo/screens/group.js +2 -0
  85. data/client/hippo/screens/instance.js +5 -1
  86. data/client/hippo/screens/system-settings.jsx +19 -5
  87. data/client/hippo/screens/system-settings/mailer-config.jsx +4 -2
  88. data/client/hippo/screens/system-settings/system-settings.scss +1 -1
  89. data/client/hippo/screens/system-settings/tenant.jsx +4 -2
  90. data/client/hippo/screens/user-management.jsx +2 -0
  91. data/client/hippo/screens/user-management/edit-form.jsx +2 -0
  92. data/client/hippo/testing/screens.js +10 -2
  93. data/client/hippo/user.js +4 -0
  94. data/client/hippo/workspace/index.jsx +3 -1
  95. data/client/hippo/workspace/menu-group.jsx +2 -0
  96. data/client/hippo/workspace/menu-option.jsx +2 -0
  97. data/client/hippo/workspace/menu.jsx +6 -3
  98. data/client/hippo/workspace/navbar.jsx +2 -0
  99. data/client/hippo/workspace/screen.jsx +2 -0
  100. data/client/hippo/workspace/styles.scss +5 -1
  101. data/command-reference-files/initial/.eslintrc.js +0 -3
  102. data/command-reference-files/initial/Gemfile +1 -1
  103. data/config/routes.rb +3 -1
  104. data/db/seed.rb +1 -1
  105. data/hippo-fw.gemspec +2 -2
  106. data/lib/hippo/api/controller_base.rb +2 -1
  107. data/lib/hippo/api/handlers/asset.rb +3 -2
  108. data/lib/hippo/api/handlers/tenant.rb +4 -6
  109. data/lib/hippo/api/helper_methods.rb +5 -7
  110. data/lib/hippo/api/route_set.rb +3 -2
  111. data/lib/hippo/asset.rb +4 -0
  112. data/lib/hippo/command/console.rb +1 -1
  113. data/lib/hippo/concerns/asset_uploader.rb +9 -4
  114. data/lib/hippo/concerns/queries.rb +3 -3
  115. data/lib/hippo/extension.rb +14 -4
  116. data/lib/hippo/extension/definition.rb +5 -1
  117. data/lib/hippo/logger.rb +26 -27
  118. data/lib/hippo/mailer.rb +19 -7
  119. data/lib/hippo/system_settings.rb +10 -4
  120. data/lib/hippo/templates/liquid.rb +1 -0
  121. data/lib/hippo/templates/liquid/pluralize.rb +16 -0
  122. data/lib/hippo/tenant.rb +17 -1
  123. data/lib/hippo/user.rb +10 -9
  124. data/lib/hippo/version.rb +1 -1
  125. data/lib/hippo/webpack.rb +22 -2
  126. data/package-lock.json +5462 -883
  127. data/package.json +9 -11
  128. data/spec/client/access/login-dialog.spec.jsx +2 -2
  129. data/spec/client/components/__snapshots__/query-builder.spec.jsx.snap +1 -1
  130. data/spec/client/components/__snapshots__/record-finder.spec.jsx.snap +1 -1
  131. data/spec/client/components/master-detail.spec.jsx +2 -1
  132. data/spec/client/components/query-builder.spec.jsx +3 -3
  133. data/spec/client/extension/base.spec.js +2 -0
  134. data/spec/client/models/base.spec.js +5 -3
  135. data/spec/client/models/query.spec.js +18 -6
  136. data/spec/client/models/sync.spec.js +2 -1
  137. data/spec/client/models/system-setting.spec.js +0 -12
  138. data/spec/client/screens/user-management.spec.jsx +1 -2
  139. data/spec/client/test-models.js +10 -0
  140. data/spec/server/api/tenant_change_spec.rb +1 -2
  141. data/spec/server/asset_spec.rb +2 -2
  142. data/templates/js/config-data.js +1 -1
  143. data/templates/spec/factories/model.rb +1 -1
  144. data/views/hippo_root_view.erb +1 -3
  145. metadata +17 -6
  146. data/client/hippo/components/text-editor/display-modes/SaveState.jsx +0 -17
@@ -2,7 +2,7 @@ import {
2
2
  isEmpty, isNil, extend, map, bindAll, inRange, find, range, isUndefined,
3
3
  } from 'lodash';
4
4
  import { reaction, observe, toJS } from 'mobx';
5
-
5
+ import objectHash from 'object-hash';
6
6
  import Sync from '../sync';
7
7
  import Result from './result';
8
8
  import {
@@ -11,6 +11,7 @@ import {
11
11
 
12
12
  @identifiedBy('hippo/query/array-result')
13
13
  export default class ArrayResult extends Result {
14
+
14
15
  @belongsTo query;
15
16
  @observable totalCount = 0;
16
17
  @observable rows;
@@ -18,6 +19,7 @@ export default class ArrayResult extends Result {
18
19
  @observable sortAscending;
19
20
  @observable sortField;
20
21
  @observable.shallow loadingRows = [];
22
+ @observable syncInProgress;
21
23
 
22
24
  constructor(attrs) {
23
25
  super(attrs);
@@ -33,18 +35,30 @@ export default class ArrayResult extends Result {
33
35
  }
34
36
 
35
37
  @computed get fingerprint() {
36
- return [
37
- this.query.fingerprint,
38
- this.rows.length,
39
- (this.sortField ? this.sortField.id : 'none'),
40
- this.sortAscending,
41
- this.rowUpdateCount,
42
- ].join(';');
38
+ return objectHash({
39
+ q: this.query.fingerprint,
40
+ sy: toJS(this.syncInProgress),
41
+ rl: this.rows.length,
42
+ sf: (this.sortField ? this.sortField.id : 'none'),
43
+ sa: this.sortAscending,
44
+ ru: this.rowUpdateCount,
45
+ });
46
+ }
47
+
48
+ createModel(attrs = {}) {
49
+ return new this.query.src(attrs); // eslint-disable-line new-cap
43
50
  }
44
51
 
45
- insertRow() {
46
- this.rows.unshift(Array(this.query.info.loadableFields.length));
52
+ insertRow({ index = 0, model = this.createModel(), observeSave = false } = {}) {
53
+ if (-1 === index) { index = this.rows.length; } // eslint-disable-line
54
+ const row = Array(this.query.info.loadableFields.length);
55
+ this.query.fields.forEach((f) => {
56
+ if (!isUndefined(model[f.id])) { row[f.dataIndex] = model[f.id]; }
57
+ });
58
+ this.rows.splice(index, 0, row);
47
59
  this.totalCount += 1;
60
+ if (observeSave) { this.observeModelSave(model, index); }
61
+ return { model, index };
48
62
  }
49
63
 
50
64
  isIndexSaved(index) {
@@ -67,8 +81,7 @@ export default class ArrayResult extends Result {
67
81
  return obj;
68
82
  }
69
83
 
70
- modelForRow(index) {
71
- const model = new this.query.src(this.rowAsObject(index)); // eslint-disable-line new-cap
84
+ observeModelSave(model, index) {
72
85
  observe(model, 'syncInProgress', ({ newValue, oldValue }) => {
73
86
  if (newValue && !oldValue && newValue.isUpdate) {
74
87
  newValue.whenComplete(() => {
@@ -80,6 +93,11 @@ export default class ArrayResult extends Result {
80
93
  }, 99);
81
94
  }
82
95
  });
96
+ }
97
+
98
+ modelForRow(index) {
99
+ const model = this.createModel(this.rowAsObject(index));
100
+ this.observeModelSave(model, index);
83
101
  return model;
84
102
  }
85
103
 
@@ -143,6 +161,14 @@ export default class ArrayResult extends Result {
143
161
  return !!find(this.loadingRows, ([start, end]) => inRange(index, start, end));
144
162
  }
145
163
 
164
+ canKeySetPage(index) {
165
+ return Boolean(
166
+ this.rows.length && this.rows.length >= index &&
167
+ this.query.sortField && this.query.sortField.dataIndex &&
168
+ !isEmpty(this.rows[index - 1]),
169
+ );
170
+ }
171
+
146
172
  fetch({ start = this.rows.length, limit = this.query.pageSize } = {}) {
147
173
  const inProgress = [start, start + limit];
148
174
  this.loadingRows.push(inProgress);
@@ -155,7 +181,6 @@ export default class ArrayResult extends Result {
155
181
  });
156
182
 
157
183
  const options = extend({}, toJS(this.query.syncOptions), {
158
- start,
159
184
  limit,
160
185
  total_count: 't',
161
186
  format: 'array',
@@ -166,12 +191,22 @@ export default class ArrayResult extends Result {
166
191
  options.query = query;
167
192
  }
168
193
 
169
- if (!isNil(this.sortField)) {
194
+ if (this.query.sortField) {
170
195
  options.order = {
171
- [`${this.sortField.id}`]: (this.sortAscending ? 'asc' : 'desc'),
196
+ [`${this.query.sortField.id}`]: this.query.sortAscending ? 'asc' : 'desc',
172
197
  };
173
198
  }
174
199
 
200
+ if (this.canKeySetPage(start)) {
201
+ const lastKey = this.rows[start - 1][this.query.sortField.dataIndex];
202
+ options.query[this.query.sortField.id] = {
203
+ op: this.query.sortAscending ? 'gt' : 'lt',
204
+ value: lastKey,
205
+ };
206
+ } else {
207
+ options.start = start;
208
+ }
209
+
175
210
  extend(options, toJS(this.query.info.syncOptions));
176
211
 
177
212
  this.syncInProgress = options;
@@ -184,8 +219,9 @@ export default class ArrayResult extends Result {
184
219
  this.rows.splice(start, Math.max(limit, rows.length), ...rows);
185
220
  this.totalCount = resp.total;
186
221
  this.loadingRows.remove(inProgress);
187
- delete this.syncInProgress;
222
+ this.syncInProgress = null;
188
223
  return this;
189
224
  });
190
225
  }
226
+
191
227
  }
@@ -1,4 +1,4 @@
1
- import { get, compact, first, filter, uniqueId } from 'lodash';
1
+ import { get, compact, first, filter, uniqueId, isNil, isEmpty } from 'lodash';
2
2
  import { action, observe } from 'mobx';
3
3
  import {
4
4
  BaseModel, identifiedBy, belongsTo, computed, observable, session,
@@ -6,6 +6,7 @@ import {
6
6
 
7
7
  @identifiedBy('hippo/query/clause')
8
8
  export default class Clause extends BaseModel {
9
+
9
10
  @observable id = uniqueId('clause');
10
11
  @session visible = true;
11
12
  @session value;
@@ -19,7 +20,10 @@ export default class Clause extends BaseModel {
19
20
  if (!this.field) {
20
21
  this.field = first(this.query.info.queryableFields);
21
22
  }
22
- observe(this, 'field', this.updateOperatorOnFieldChange, true);
23
+ if (!this.operator) {
24
+ this.operator = this.field.preferredOperator;
25
+ }
26
+ observe(this, 'field', this.updateOperatorOnFieldChange);
23
27
  }
24
28
 
25
29
  @computed get description() {
@@ -35,13 +39,14 @@ export default class Clause extends BaseModel {
35
39
  }
36
40
 
37
41
  @computed get isValid() {
38
- return !!(this.value && this.operator.isValidForField(this.field));
42
+ if ('like' === this.operator.id) { return !isEmpty(this.value); }
43
+ return Boolean(!isNil(this.value) && this.operator.isValidForField(this.field));
39
44
  }
40
45
 
41
46
  toParam() {
42
47
  const param = {};
43
48
  let op = this.operator.id;
44
- let value = this.value;
49
+ let { value } = this;
45
50
  if ('like' === op) { value += '%'; }
46
51
  if ('contains' === op) {
47
52
  op = 'like';
@@ -54,6 +59,8 @@ export default class Clause extends BaseModel {
54
59
 
55
60
  @action.bound
56
61
  updateOperatorOnFieldChange() {
62
+ this.value = this.field.defaultValue;
57
63
  this.operator = this.field.preferredOperator;
58
64
  }
65
+
59
66
  }
@@ -7,6 +7,7 @@ import {
7
7
 
8
8
  @identifiedBy('hippo/query/field')
9
9
  export default class Field extends BaseModel {
10
+
10
11
  @identifier({ type: 'string' }) id;
11
12
  @session title;
12
13
  @session selected = false;
@@ -23,7 +24,6 @@ export default class Field extends BaseModel {
23
24
  @session dataType = 'string'
24
25
  @session cellRenderer;
25
26
  @session defaultValue;
26
- @session fetchIndex;
27
27
  @session sortBy;
28
28
 
29
29
  @observable onColumnClick;
@@ -80,4 +80,5 @@ export default class Field extends BaseModel {
80
80
  @computed get preferredOperator() {
81
81
  return this.query.operators.find(o => o.isValidForField(this));
82
82
  }
83
+
83
84
  }
@@ -1,7 +1,8 @@
1
- import { filter, reduce, find } from 'lodash';
1
+ import { isNil, filter, reduce, find } from 'lodash';
2
2
  import { computed } from 'mobx';
3
3
 
4
4
  export default class Info {
5
+
5
6
  constructor(query) {
6
7
  this.query = query;
7
8
  }
@@ -41,4 +42,9 @@ export default class Info {
41
42
  const property = this.query.src.identifierFieldName;
42
43
  return find(this.query.fields, { id: property });
43
44
  }
45
+
46
+ @computed get valuedClauses() {
47
+ return filter(this.query.clauses, c => !isNil(c.value));
48
+ }
49
+
44
50
  }
@@ -4,6 +4,7 @@ import {
4
4
 
5
5
  @identifiedBy('hippo/query/operators/operator')
6
6
  export default class Operator extends BaseModel {
7
+
7
8
  @identifier({ type: 'string' }) id;
8
9
  @session label;
9
10
  @session selected;
@@ -16,4 +17,5 @@ export default class Operator extends BaseModel {
16
17
  if (!this.types.length) { return true; }
17
18
  return !!this.types.find(t => t === field.queryType);
18
19
  }
20
+
19
21
  }
@@ -8,6 +8,7 @@ import {
8
8
 
9
9
  @identifiedBy('hippo/query/result')
10
10
  export default class Result extends BaseModel {
11
+
11
12
  @belongsTo({ type: 'hippo/query' }) query;
12
13
 
13
14
  sortingFunction() {
@@ -17,4 +18,5 @@ export default class Result extends BaseModel {
17
18
  }
18
19
 
19
20
  loadFully() { return Promise.resolve(this); }
21
+
20
22
  }
@@ -2,4 +2,8 @@ export default {
2
2
  LIKE_QUERY_TYPES: ['string', 'code', 'visible_id'],
3
3
  LESS_THAN_QUERY_TYPES: ['integer', 'bigdec', 'number'],
4
4
  GREATER_THAN_QUERY_TYPES: ['integer', 'bigdec', 'number'],
5
+ BETWEEN_TYPES: ['date'],
6
+ EQUAL_TYPES: [
7
+ 'string', 'code', 'visible_id', 'integer', 'bigdec', 'number',
8
+ ],
5
9
  };
@@ -32,6 +32,7 @@ function isUpdate(method) {
32
32
  }
33
33
 
34
34
  class SyncProgess {
35
+
35
36
  constructor(options) {
36
37
  extend(this, options);
37
38
  this._whenComplete = [];
@@ -42,6 +43,7 @@ class SyncProgess {
42
43
  get isFetch() { return 'GET' === this.method; }
43
44
  get isCreate() { return 'POST' === this.method; }
44
45
  get isUpdate() { return isUpdate(this.method); }
46
+
45
47
  }
46
48
 
47
49
  function invokeWhenComplete(json, progress) {
@@ -1,14 +1,13 @@
1
1
  import { merge } from 'lodash';
2
- import { when } from 'mobx';
3
2
  import {
4
3
  BaseModel, identifiedBy, identifier, belongsTo, field, computed,
5
4
  } from './base';
6
5
  import Sync from './sync';
7
- import Config from '../config';
8
6
  import Asset from './asset';
9
7
 
10
8
  @identifiedBy('hippo/system-settings')
11
9
  export default class SystemSettings extends BaseModel {
10
+
12
11
  @identifier id;
13
12
  @field({ type: 'object' }) settings;
14
13
 
@@ -23,17 +22,4 @@ export default class SystemSettings extends BaseModel {
23
22
  return this.constructor.syncUrl;
24
23
  }
25
24
 
26
- get syncData() {
27
- return this.serialize();
28
- }
29
-
30
- set syncData(data) {
31
- super.syncData = data;
32
- if (this.logo && this.logo.isDirty) {
33
- when(
34
- () => !this.logo.isDirty,
35
- () => { Config.logo = this.logo.file_data; },
36
- );
37
- }
38
- }
39
25
  }
@@ -1,29 +1,45 @@
1
- import { observable } from 'mobx';
1
+ import { observable, computed } from 'mobx';
2
+ import { first } from 'lodash';
2
3
  import {
3
- BaseModel, identifiedBy, field, identifier, computed,
4
+ BaseModel, identifiedBy, field, identifier,
4
5
  } from './base';
5
6
  import Config from '../config';
6
7
 
7
-
8
8
  const CACHED = observable.box();
9
9
 
10
10
  @identifiedBy('hippo/tenant')
11
11
  export default class Tenant extends BaseModel {
12
+
12
13
  @computed static get current() {
13
14
  let tenant = CACHED.get();
14
15
  if (!tenant) {
15
- tenant = new Tenant();
16
+ tenant = new Tenant({
17
+ slug: first(window.location.host.split('.')),
18
+ });
16
19
  CACHED.set(tenant);
17
- tenant.fetch({ query: 'current' });
18
20
  }
19
21
  return tenant;
20
22
  }
21
23
 
22
- @identifier id;
23
- @field slug = Tenant.slug;
24
+ static bootstrap(data) {
25
+ Tenant.current.update(data);
26
+ if (data.bootstrap) {
27
+ Config.update(data.bootstrap);
28
+ }
29
+ }
30
+
31
+ @identifier({ type: 'string' }) identifier = 'current';
24
32
  @field name;
33
+ @field email;
34
+ @field slug;
35
+
25
36
 
26
37
  @computed get domain() {
27
38
  return `${this.slug}.${Config.website_domain}`;
28
39
  }
40
+
41
+ set syncData(data) {
42
+ Tenant.bootstrap(data);
43
+ }
44
+
29
45
  }
@@ -3,6 +3,7 @@ import React from 'react';
3
3
  import PropTypes from 'prop-types';
4
4
 
5
5
  export default class Root extends React.Component {
6
+
6
7
  static childContextTypes = {
7
8
  viewport: PropTypes.object,
8
9
  }
@@ -20,4 +21,5 @@ export default class Root extends React.Component {
20
21
  </div>
21
22
  );
22
23
  }
24
+
23
25
  }
@@ -4,6 +4,7 @@ import { get } from 'lodash';
4
4
  import { classify } from '../lib/util';
5
5
 
6
6
  export default class ComponentNotFound extends React.PureComponent {
7
+
7
8
  static propTypes = {
8
9
  extension: PropTypes.shape({
9
10
  identifier: PropTypes.string,
@@ -18,4 +19,5 @@ export default class ComponentNotFound extends React.PureComponent {
18
19
  </div>
19
20
  );
20
21
  }
22
+
21
23
  }
@@ -12,6 +12,7 @@ export { asyncComponent } from 'react-async-component';
12
12
 
13
13
  @identifiedBy('hippo/screen/definition')
14
14
  export default class ScreenDefinition extends BaseModel {
15
+
15
16
  @identifier({ type: 'string' }) id;
16
17
  @session title;
17
18
  @session url_prefix;
@@ -62,4 +63,5 @@ export default class ScreenDefinition extends BaseModel {
62
63
  instance.isActive = true;
63
64
  return instance;
64
65
  }
66
+
65
67
  }
@@ -7,6 +7,7 @@ const All = observable.array();
7
7
 
8
8
  @identifiedBy('ScreensGroup')
9
9
  export default class ScreensGroup extends BaseModel {
10
+
10
11
  static all = All;
11
12
 
12
13
  @identifier({ type: 'string' }) id;
@@ -30,4 +31,5 @@ export default class ScreensGroup extends BaseModel {
30
31
  }
31
32
  return group;
32
33
  }
34
+
33
35
  }
@@ -6,6 +6,7 @@ import {
6
6
  } from '../models/base';
7
7
 
8
8
  class InstanceCollection {
9
+
9
10
  @observable models = []
10
11
  @observable active;
11
12
 
@@ -17,7 +18,7 @@ class InstanceCollection {
17
18
  const len = this.models.length;
18
19
  if (!len) { return; }
19
20
  if (1 === len) {
20
- this.active = this.models[0];
21
+ [this.active] = this.models;
21
22
  } else if (!this.active) {
22
23
  this.active = this.models[len - 1];
23
24
  }
@@ -32,6 +33,7 @@ class InstanceCollection {
32
33
 
33
34
  add(model) { this.models.push(model); }
34
35
  remove(model) { this.models.remove(model); }
36
+
35
37
  }
36
38
 
37
39
  const displaying = new InstanceCollection();
@@ -39,6 +41,7 @@ export { displaying };
39
41
 
40
42
  @identifiedBy('hippo/screen-view')
41
43
  export default class Instance extends BaseModel {
44
+
42
45
  static get displaying() {
43
46
  return displaying.models;
44
47
  }
@@ -93,4 +96,5 @@ export default class Instance extends BaseModel {
93
96
  remove() {
94
97
  displaying.remove(this);
95
98
  }
99
+
96
100
  }