lanes 0.5.6 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +6 -2
- data/client/lanes/Config.coffee +6 -5
- data/client/lanes/access/LoginDialog.cjsx +4 -2
- data/client/lanes/access/Roles.coffee +3 -0
- data/client/lanes/access/screens/user-management/Editor.cjsx +1 -1
- data/client/lanes/components/grid/Body.cjsx +4 -3
- data/client/lanes/components/grid/Grid.cjsx +4 -3
- data/client/lanes/components/grid/Header.cjsx +1 -1
- data/client/lanes/components/grid/PopOverMixin.cjsx +6 -6
- data/client/lanes/components/grid/Selections.cjsx +16 -6
- data/client/lanes/components/grid/Toolbar.cjsx +1 -1
- data/client/lanes/components/grid/styles.scss +21 -5
- data/client/lanes/components/modal/Modal.cjsx +18 -9
- data/client/lanes/components/record-finder/Clause.cjsx +1 -2
- data/client/lanes/components/record-finder/Dialog.cjsx +11 -3
- data/client/lanes/components/record-finder/RecordFinder.cjsx +14 -7
- data/client/lanes/components/record-finder/styles.scss +1 -0
- data/client/lanes/components/select-field/SelectField.cjsx +36 -10
- data/client/lanes/components/select-field/styles.scss +7 -0
- data/client/lanes/components/shared/Checkbox.cjsx +34 -0
- data/client/lanes/components/shared/DateTime.cjsx +3 -2
- data/client/lanes/components/shared/ErrorDisplay.cjsx +1 -1
- data/client/lanes/components/shared/FieldMixin.cjsx +26 -15
- data/client/lanes/components/shared/FieldSet.cjsx +1 -1
- data/client/lanes/components/shared/FieldWrapper.cjsx +2 -2
- data/client/lanes/components/shared/FormGroup.cjsx +2 -2
- data/client/lanes/components/shared/Icon.cjsx +31 -4
- data/client/lanes/components/shared/IconButton.cjsx +8 -0
- data/client/lanes/components/shared/ImageAsset.cjsx +8 -5
- data/client/lanes/components/shared/IndeterminateCheckbox.cjsx +19 -0
- data/client/lanes/components/shared/InputFieldMixin.cjsx +6 -0
- data/client/lanes/components/shared/JobProgress.cjsx +4 -3
- data/client/lanes/components/shared/NetworkActivityOverlay.cjsx +1 -1
- data/client/lanes/components/shared/ScreenWrapper.cjsx +1 -1
- data/client/lanes/components/shared/ToggleField.cjsx +2 -1
- data/client/lanes/components/shared/Tooltip.cjsx +10 -2
- data/client/lanes/components/shared/fields.scss +7 -2
- data/client/lanes/components/toolbar/RemoteChangeSets.cjsx +10 -7
- data/client/lanes/components/toolbar/SaveButton.cjsx +5 -4
- data/client/lanes/components/toolbar/Toolbar.cjsx +18 -19
- data/client/lanes/components/toolbar/changes-notification.scss +3 -1
- data/client/lanes/components/toolbar/styles.scss +6 -3
- data/client/lanes/lib/HotReload.coffee +1 -1
- data/client/lanes/lib/all.js +1 -1
- data/client/lanes/lib/dom.coffee +14 -1
- data/client/lanes/lib/format.coffee +3 -0
- data/client/lanes/lib/loader.coffee +0 -2
- data/client/lanes/lib/{dom-polyfills.coffee → polyfills.coffee} +3 -0
- data/client/lanes/lib/utilFunctions.coffee +5 -7
- data/client/lanes/models/Asset.coffee +33 -20
- data/client/lanes/models/AssociationMap.coffee +5 -6
- data/client/lanes/models/Base.coffee +5 -2
- data/client/lanes/models/Collection.coffee +23 -2
- data/client/lanes/models/PubSub.coffee +51 -13
- data/client/lanes/models/Query.coffee +53 -42
- data/client/lanes/models/State.coffee +5 -4
- data/client/lanes/models/Sync.coffee +5 -3
- data/client/lanes/models/index.js +1 -1
- data/client/lanes/models/mixins/TrackCollectionRemovals.coffee +17 -0
- data/client/lanes/models/query/ArrayResult.coffee +16 -17
- data/client/lanes/models/query/CollectionResult.coffee +4 -4
- data/client/lanes/react/Component.coffee +14 -13
- data/client/lanes/react/Root.cjsx +1 -1
- data/client/lanes/react/Screen.coffee +1 -0
- data/client/lanes/react/Viewport.coffee +52 -16
- data/client/lanes/react/mixins/Access.coffee +5 -0
- data/client/lanes/react/mixins/Data.coffee +52 -144
- data/client/lanes/react/mixins/MonitorSize.coffee +1 -1
- data/client/lanes/react/mixins/ReadEditingState.coffee +3 -0
- data/client/lanes/screens/Commands.coffee +1 -1
- data/client/lanes/screens/CommonComponents.cjsx +2 -2
- data/client/lanes/screens/Definitions.coffee +3 -1
- data/client/lanes/screens/SystemSettings.cjsx +13 -18
- data/client/lanes/screens/UserPreferences.cjsx +1 -1
- data/client/lanes/styles/fonts.scss +2 -3
- data/client/lanes/styles/global/styles.scss +2 -1
- data/client/lanes/testing/TestObjects.coffee +6 -2
- data/client/lanes/vendor/action_cable.js +590 -0
- data/client/lanes/vendor/development/calendar.js +56 -56
- data/client/lanes/vendor/development/commons.js +7819 -6690
- data/client/lanes/vendor/development/data.js +1877 -1455
- data/client/lanes/vendor/development/helpers.js +39 -82
- data/client/lanes/vendor/development/toggle.js +20 -20
- data/client/lanes/vendor/development/ui.js +14629 -14261
- data/client/lanes/vendor/development/widgets.js +3146 -2173
- data/client/lanes/vendor/index.js +1 -2
- data/client/lanes/vendor/production/calendar.js +56 -56
- data/client/lanes/vendor/production/commons.js +6352 -6185
- data/client/lanes/vendor/production/data.js +1871 -1456
- data/client/lanes/vendor/production/toggle.js +20 -20
- data/client/lanes/vendor/production/ui.js +14694 -14286
- data/client/lanes/vendor/production/widgets.js +3139 -2166
- data/client/lanes/vendor/standalone/index.js +5666 -4586
- data/client/lanes/vendor/styles/widgets.scss +5 -5
- data/client/lanes/workspace/Layout.cjsx +1 -10
- data/client/lanes/workspace/Navbar.cjsx +8 -13
- data/client/lanes/workspace/ScreenView.cjsx +3 -4
- data/client/lanes/workspace/ScreensMenu.cjsx +8 -19
- data/client/lanes/workspace/Tabs.cjsx +6 -14
- data/db/migrate/02_create_assets.rb +1 -3
- data/lanes.gemspec +16 -11
- data/lib/lanes/access/test_fixture_extensions.rb +6 -10
- data/lib/lanes/access/track_modifications.rb +24 -0
- data/lib/lanes/api/cable.rb +49 -0
- data/lib/lanes/api/controller_base.rb +52 -9
- data/lib/lanes/api/default_routes.rb +9 -0
- data/lib/lanes/api/generic_controller.rb +2 -9
- data/lib/lanes/api/handlers/asset.rb +5 -6
- data/lib/lanes/api/helper_methods.rb +3 -2
- data/lib/lanes/api/javascript_processor.rb +6 -5
- data/lib/lanes/api/pub_sub.rb +14 -32
- data/lib/lanes/api/request_wrapper.rb +1 -1
- data/lib/lanes/api/root.rb +4 -7
- data/lib/lanes/api/routing.rb +3 -3
- data/lib/lanes/api/sprockets_extension.rb +1 -1
- data/lib/lanes/api.rb +4 -0
- data/lib/lanes/asset.rb +25 -25
- data/lib/lanes/concerns/asset_uploader.rb +25 -47
- data/lib/lanes/concerns/export_scope.rb +5 -7
- data/lib/lanes/concerns/queries.rb +7 -3
- data/lib/lanes/concerns/set_attribute_data.rb +12 -6
- data/lib/lanes/configuration.rb +4 -7
- data/lib/lanes/db.rb +3 -1
- data/lib/lanes/guard_tasks.rb +2 -1
- data/lib/lanes/hot_reload_plugin.rb +2 -1
- data/lib/lanes/job.rb +0 -1
- data/lib/lanes/logger.rb +3 -3
- data/lib/lanes/model.rb +0 -3
- data/lib/lanes/spec_helper.rb +1 -1
- data/lib/lanes/system_settings.rb +8 -14
- data/lib/lanes/version.rb +1 -1
- data/npm-build/data.js +1 -0
- data/npm-build/package.json +21 -19
- data/npm-build/ui.js +3 -0
- data/npm-build/update-dayz +2 -2
- data/npm-build/update-model-bindings.js +5 -0
- data/spec/command-reference-files/initial/Gemfile +1 -1
- data/spec/command-reference-files/initial/config/database.yml +1 -0
- data/spec/command-reference-files/initial/config/lanes.rb +3 -3
- data/spec/command-reference-files/screen/spec/appy-app/screens/ready-set-go/ReadySetGoSpec.coffee +1 -1
- data/spec/lanes/components/grid/GridSpec.coffee +2 -2
- data/spec/lanes/components/grid/PopoverEditorSpec.coffee +11 -12
- data/spec/lanes/components/select-field/SelectFieldSpec.coffee +6 -4
- data/spec/lanes/components/shared/NetworkActivityOverlaySpec.coffee +1 -1
- data/spec/lanes/models/PubSubSpec.coffee +6 -8
- data/spec/lanes/models/QuerySpec.coffee +19 -0
- data/spec/lanes/react/mixins/DataSpec.coffee +18 -16
- data/spec/server/api/coffeescript_processor_spec.rb +1 -1
- data/spec/server/api/controller_base_spec.rb +77 -0
- data/spec/server/api/pub_sub_spec.rb +9 -0
- data/spec/server/asset_spec.rb +23 -18
- data/spec/server/concerns/export_scope_spec.rb +2 -1
- data/spec/server/concerns/exported_limits_spec.rb +14 -9
- data/spec/server/concerns/set_attribute_data_spec.rb +17 -0
- data/spec/server/spec_helper.rb +29 -11
- data/templates/config/database.yml +1 -0
- data/templates/spec/client/Screen.coffee +1 -1
- data/views/specs.erb +4 -1
- metadata +138 -89
- data/client/lanes/vendor/message-bus-ajax.js +0 -44
- data/client/lanes/vendor/message-bus.js +0 -414
@@ -1,7 +1,7 @@
|
|
1
|
-
# This file will be loaded
|
2
|
-
# one controlling Lanes.
|
1
|
+
# This file will be loaded as part of Lanes startup.
|
3
2
|
#
|
4
|
-
#
|
3
|
+
# Extensions are called in load order, so be aware latter extensions may
|
4
|
+
# override config options specified
|
5
5
|
Lanes.configure do | config |
|
6
6
|
# You can specify a different initial vew by setting it here
|
7
7
|
# It must be set if the "Workspace" extension is disabled in
|
@@ -15,10 +15,10 @@ renderGrid = (q, done) ->
|
|
15
15
|
grid = LT.renderComponent(LC.Grid, props: query: q)
|
16
16
|
expect(loaded).toHaveBeenCalled()
|
17
17
|
_.defer ->
|
18
|
-
expect(_.dom(grid).
|
19
|
-
.toEqual( q.results.length )
|
18
|
+
expect(_.dom(grid).qs('.r').el).not.toBeNull()
|
20
19
|
done()
|
21
20
|
|
21
|
+
|
22
22
|
describe "Lanes.Components.Grid", ->
|
23
23
|
|
24
24
|
beforeEach (done) ->
|
@@ -1,11 +1,10 @@
|
|
1
1
|
#= require lanes/components/grid
|
2
2
|
|
3
|
-
COLLECTION_DATA = [
|
4
|
-
{id:1, code:'TEST1', name: 'Nathan Stitt', notes: 'swell guy'}
|
5
|
-
{id:2, code:'TEST2', name: 'Nathan Stitt', notes: 'Dupe of id #1'}
|
6
|
-
]
|
7
3
|
|
8
|
-
|
4
|
+
DATA = {total:2, success:true, message:"Retrieve succeeded", data:[
|
5
|
+
[1, "TEST1", "Nathan Stitt", "swell guy"]
|
6
|
+
[2, "TEST2", "Nathan Stitt", "Dupe of id #1"]
|
7
|
+
]}
|
9
8
|
|
10
9
|
Model = Lanes.Test.defineModel(
|
11
10
|
props: {id: 'integer', code: 'string', name: 'string', notes: 'string'}
|
@@ -17,15 +16,15 @@ ADD_ROW_SELECTOR = 'button.add-row'
|
|
17
16
|
describe "Lanes.Components.Grid.PopoverEditor", ->
|
18
17
|
|
19
18
|
beforeEach (done) ->
|
19
|
+
LT.syncRespondWith(DATA)
|
20
20
|
@query = new Lanes.Models.Query(
|
21
|
-
fields: [ 'id', 'code', 'name', 'notes' ]
|
21
|
+
src: Model, fields: [ 'id', 'code', 'name', 'notes' ]
|
22
22
|
)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
})
|
23
|
+
@query.ensureLoaded().then =>
|
24
|
+
@grid = LT.renderComponent(LC.Grid, props: {
|
25
|
+
allowCreate: true, editor: Lanes.Components.Grid.PopoverEditor, query: @query
|
26
|
+
})
|
27
|
+
done()
|
29
28
|
|
30
29
|
it "edits", (done) ->
|
31
30
|
_.dom(@grid).qs(LAST_ROW_SELECTOR).click(clientX: 5)
|
@@ -10,6 +10,8 @@ BRAND_DATA = {total:3, success:true, message:"Retrieve succeeded", data:[
|
|
10
10
|
{id: 3, code: "DODGE", name: "Chrysler/Dodge"}
|
11
11
|
]}
|
12
12
|
|
13
|
+
VALUE_CLASS = '.form-control-static'
|
14
|
+
|
13
15
|
Car = Lanes.Test.defineModel(
|
14
16
|
props: {id: 'integer', code: 'string', brand_id: 'integer'}
|
15
17
|
session:
|
@@ -29,10 +31,10 @@ describe "Lanes.Components.SelectField", ->
|
|
29
31
|
it "renders read only", (done) ->
|
30
32
|
sf = LT.renderComponent(LC.SelectField,
|
31
33
|
props:{model: @car, name: 'brand', labelField: 'name'})
|
32
|
-
expect(_.dom(sf).qs(
|
34
|
+
expect(_.dom(sf).qs(VALUE_CLASS).text).toBe('')
|
33
35
|
@car.set(brand: @brands.at(0))
|
34
36
|
_.defer ->
|
35
|
-
expect(_.dom(sf).qs(
|
37
|
+
expect(_.dom(sf).qs(VALUE_CLASS).text).toBe('General Motors')
|
36
38
|
done()
|
37
39
|
|
38
40
|
it "renders as edit", ->
|
@@ -83,7 +85,7 @@ describe "Lanes.Components.SelectField", ->
|
|
83
85
|
model: @car, name: 'brand', labelField: 'name',
|
84
86
|
choices: @brands.models
|
85
87
|
})
|
86
|
-
expect(_.dom(sf).qs(
|
88
|
+
expect(_.dom(sf).qs(VALUE_CLASS).text).toEqual('Chrysler/Dodge')
|
87
89
|
|
88
90
|
it 'renders label for multiple values', ->
|
89
91
|
@car.carTypes = [ @brands.at(0), @brands.at(2) ]
|
@@ -91,7 +93,7 @@ describe "Lanes.Components.SelectField", ->
|
|
91
93
|
queryModel: Car, multiSelect: true, model: @car, name: 'carTypes'
|
92
94
|
labelField: 'name', choices: @brands.models
|
93
95
|
})
|
94
|
-
expect(_.dom(sf).qs(
|
96
|
+
expect(_.dom(sf).qs(VALUE_CLASS).text).toEqual('General Motors and Chrysler/Dodge')
|
95
97
|
|
96
98
|
|
97
99
|
it "renders all choices", ->
|
@@ -26,7 +26,7 @@ describe "Lanes.Components.NetworkActivityOverlay", ->
|
|
26
26
|
model = new Model
|
27
27
|
na = LT.renderComponent(LC.NetworkActivityOverlay, props:{
|
28
28
|
errorTimeout: 2, model:model})
|
29
|
-
na.
|
29
|
+
na.setModelState(hasError: true)
|
30
30
|
expect(_.dom(na).qs('.message').text).toBe('Error')
|
31
31
|
_.delay( ->
|
32
32
|
expect(_.dom(na).el).toBe(null)
|
@@ -8,13 +8,15 @@ describe "Lanes.Model.PubSub", ->
|
|
8
8
|
@getModelConfig = ->
|
9
9
|
Lanes.Models.PubSub.types.get('/s').records[1]
|
10
10
|
|
11
|
-
it "checks in/out a model when it binds to a view", ->
|
11
|
+
it "checks in/out a model when it binds to a view", (done) ->
|
12
12
|
spyOn(Lanes.Models.PubSub, 'add').and.callThrough()
|
13
13
|
spyOn(Lanes.Models.PubSub, 'remove')
|
14
14
|
component = Lanes.Test.makeComponent({}, model: @model)
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
_.defer =>
|
16
|
+
expect(Lanes.Models.PubSub.add).toHaveBeenCalledWith(@model)
|
17
|
+
component.modelBindings.destroy()
|
18
|
+
expect(Lanes.Models.PubSub.remove).toHaveBeenCalledWith(@model)
|
19
|
+
done()
|
18
20
|
|
19
21
|
it "can retrieve a model after checkin", ->
|
20
22
|
record = new @Model(id: 11, foo: 'bar')
|
@@ -34,12 +36,10 @@ describe "Lanes.Model.PubSub", ->
|
|
34
36
|
Lanes.Models.PubSub.remove(@model)
|
35
37
|
).not.toThrowError()
|
36
38
|
|
37
|
-
|
38
39
|
it 'removes models', ->
|
39
40
|
Lanes.Models.PubSub.add(@model)
|
40
41
|
configs = Lanes.Models.PubSub.types.get('/s').records[1].models
|
41
42
|
expect(configs.length).toEqual(1)
|
42
|
-
|
43
43
|
Lanes.Models.PubSub.remove(@model)
|
44
44
|
expect(configs[0].count).toEqual(1)
|
45
45
|
Lanes.Models.PubSub.remove(@model)
|
@@ -66,8 +66,6 @@ describe "Lanes.Model.PubSub", ->
|
|
66
66
|
expect(Lanes.Models.PubSub.mb.subscribe.calls.count()).toEqual(1)
|
67
67
|
expect(Lanes.Models.PubSub.mb.unsubscribe.calls.count()).toEqual(0)
|
68
68
|
Lanes.Models.PubSub.remove(newModel)
|
69
|
-
|
70
69
|
Lanes.Models.PubSub.remove(newModel)
|
71
|
-
|
72
70
|
expect(@getModelConfig()).toBeUndefined()
|
73
71
|
expect(Lanes.Models.PubSub.mb.unsubscribe.calls.count()).toEqual(1)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
describe "Lanes.Models.Query", ->
|
2
|
+
|
3
|
+
beforeEach ->
|
4
|
+
@query =
|
5
|
+
new Lanes.Models.Query({
|
6
|
+
syncOptions: @syncOptions
|
7
|
+
src: Lanes.Models.User, fields: [
|
8
|
+
{id:'id', visible: false}
|
9
|
+
{id:'email', fixedWidth: 130 },
|
10
|
+
{id:'login', },
|
11
|
+
{id:'name', flex: 1}
|
12
|
+
]
|
13
|
+
})
|
14
|
+
|
15
|
+
|
16
|
+
it "can be cloned unsaved attributes", ->
|
17
|
+
newQuery = @query.clone()
|
18
|
+
expect(newQuery).toBeDefined()
|
19
|
+
expect(newQuery.fields.pluck('id')).toEqual(@query.fields.pluck('id'))
|
@@ -1,21 +1,21 @@
|
|
1
1
|
describe "Lanes.React.DataMixin", ->
|
2
2
|
|
3
|
-
it "fires
|
3
|
+
it "fires forceUpdate for a model", ->
|
4
4
|
model = Lanes.Test.makeModel
|
5
5
|
props:
|
6
6
|
id: 'integer'
|
7
7
|
foo: 'string'
|
8
8
|
comp = Lanes.Test.makeComponent({}, model: model)
|
9
|
-
spyOn(comp, '
|
9
|
+
spyOn(comp, 'forceUpdate')
|
10
10
|
model.foo = "bar"
|
11
|
-
expect(comp.
|
11
|
+
expect(comp.forceUpdate).toHaveBeenCalled()
|
12
12
|
|
13
|
-
it "fires
|
13
|
+
it "fires forceUpdate for a collection", ->
|
14
14
|
collection = Lanes.Test.makeCollection()
|
15
15
|
comp = Lanes.Test.makeComponent({}, collection: collection)
|
16
|
-
spyOn(comp, '
|
16
|
+
spyOn(comp, 'forceUpdate')
|
17
17
|
collection.add([{}])
|
18
|
-
expect(comp.
|
18
|
+
expect(comp.forceUpdate).toHaveBeenCalled()
|
19
19
|
|
20
20
|
it "obeys global pubsub settings", ->
|
21
21
|
spyOn(Lanes.Models.PubSub, 'add').and.callThrough()
|
@@ -39,17 +39,18 @@ describe "Lanes.React.DataMixin", ->
|
|
39
39
|
props:
|
40
40
|
foo: 'string'
|
41
41
|
bar: 'string'
|
42
|
+
|
42
43
|
comp = Lanes.Test.makeComponent({
|
43
|
-
|
44
|
+
bindEvents:
|
44
45
|
model: 'change:bar'
|
45
46
|
}, {
|
46
47
|
model: model
|
47
48
|
})
|
48
|
-
spyOn(comp, '
|
49
|
+
spyOn(comp, 'forceUpdate')
|
49
50
|
model.foo = "bar"
|
50
|
-
expect(comp.
|
51
|
+
expect(comp.forceUpdate).not.toHaveBeenCalled()
|
51
52
|
model.bar = "foo"
|
52
|
-
expect(comp.
|
53
|
+
expect(comp.forceUpdate).toHaveBeenCalled()
|
53
54
|
|
54
55
|
it "can rebind events", ->
|
55
56
|
Model = Lanes.Test.defineModel
|
@@ -60,13 +61,14 @@ describe "Lanes.React.DataMixin", ->
|
|
60
61
|
comp = Lanes.Test.makeComponent({}, {
|
61
62
|
model: m1
|
62
63
|
})
|
63
|
-
spyOn(comp, '
|
64
|
+
spyOn(comp, 'forceUpdate')
|
64
65
|
m1.foo = "bar"
|
65
|
-
expect(comp.
|
66
|
+
expect(comp.forceUpdate).toHaveBeenCalled()
|
67
|
+
|
68
|
+
comp.modelBindings.reset(model: m2)
|
69
|
+
comp.forceUpdate.calls.reset()
|
66
70
|
|
67
|
-
comp.data.rebind(model: m2)
|
68
|
-
comp.setState.calls.reset()
|
69
71
|
m1.foo = "a different bar"
|
70
|
-
expect(comp.
|
72
|
+
expect(comp.forceUpdate).not.toHaveBeenCalled()
|
71
73
|
m2.foo = "bar"
|
72
|
-
expect(comp.
|
74
|
+
expect(comp.forceUpdate).toHaveBeenCalled()
|
@@ -101,7 +101,7 @@ Foo = (function() {
|
|
101
101
|
|
102
102
|
Bar.extend(Foo);
|
103
103
|
|
104
|
-
})(window.Lanes,(window.Lanes ? window.Lanes['Foo'] : null),window.Lanes.Vendor.ld,window.Lanes.Components,window.Lanes.Vendor.React,window.Lanes.Vendor.ReactBootstrap,{namespace:window.Lanes['Foo'],extension:{name:'Foo',identifier:'foo'},path:[\"foo\",\"bar\",\"baz\"]},window);
|
104
|
+
})((window.Lanes = (window.Lanes || {})),(window.Lanes ? window.Lanes['Foo'] : null),(window.Lanes.Vendor = (window.Lanes.Vendor || {})).ld,window.Lanes.Components,window.Lanes.Vendor.React,window.Lanes.Vendor.ReactBootstrap,{namespace:window.Lanes['Foo'],extension:{name:'Foo',identifier:'foo'},path:[\"foo\",\"bar\",\"baz\"]},window);
|
105
105
|
EOS
|
106
106
|
|
107
107
|
Scope = Struct.new(:logical_path)
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
require 'lanes/access/user'
|
3
|
+
|
4
|
+
class ControllerBaseSpec < Lanes::TestCase
|
5
|
+
|
6
|
+
include TestingModels
|
7
|
+
|
8
|
+
def test_record_retrieval
|
9
|
+
1.upto(10){|i| TestModel.create!(id: i, name:'test') }
|
10
|
+
controller = Lanes::API::ControllerBase.new(TestModel,
|
11
|
+
Lanes::API::AuthenticationProvider.new({}),
|
12
|
+
{id: 1})
|
13
|
+
assert_equal(controller.send(:perform_retrieval), {
|
14
|
+
:success=>true, :message=>"Retrieve succeeded",
|
15
|
+
:data=>{"id"=>1, "bt_id"=>nil, "name"=>"test", "number"=>nil}
|
16
|
+
})
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_single_update
|
20
|
+
TestModel.create!(id: 1, name:'Joe')
|
21
|
+
controller = Lanes::API::ControllerBase.new(TestModel,
|
22
|
+
Lanes::API::AuthenticationProvider.new({}),
|
23
|
+
{id: 1}, {name:'Bob'})
|
24
|
+
assert_equal(controller.send(:perform_single_update), {
|
25
|
+
:success=>true, :message=>"Update succeeded",
|
26
|
+
:data=>{"id"=>1, "bt_id"=>nil, "name"=>"Bob", "number"=>nil}
|
27
|
+
})
|
28
|
+
assert_equal TestModel.where(id: 1).first.name, 'Bob'
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_multiple_updates
|
32
|
+
TestModel.create!(id: 1, name:'Joe')
|
33
|
+
TestModel.create!(id: 2, name:'Bob')
|
34
|
+
def TestModel.access_limits_for_query(query, user, params)
|
35
|
+
query.where(name:'Joe')
|
36
|
+
end
|
37
|
+
controller = Lanes::API::ControllerBase.new(TestModel,
|
38
|
+
Lanes::API::AuthenticationProvider.new({}),
|
39
|
+
{},
|
40
|
+
[{'id'=>1}, {'id'=>2}])
|
41
|
+
|
42
|
+
assert_equal( controller.send(:perform_multiple_updates), {
|
43
|
+
:success=>true,
|
44
|
+
:message=>"Update succeeded",
|
45
|
+
:data=>[{"id"=>1, "bt_id"=>nil, "name"=>"Joe", "number"=>nil}]
|
46
|
+
})
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_single_destroy
|
50
|
+
TestModel.create!(id: 1, name:'Joe')
|
51
|
+
controller = Lanes::API::ControllerBase.new(TestModel,
|
52
|
+
Lanes::API::AuthenticationProvider.new({}),
|
53
|
+
{id: 1}, {})
|
54
|
+
assert_equal( controller.send(:perform_single_destroy), {
|
55
|
+
:success=>true, :message=>"Destroy succeeded", :data=>[]
|
56
|
+
})
|
57
|
+
assert_empty TestModel.where(id: 1).to_a
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def test_multiple_destroy
|
62
|
+
TestModel.create!(id: 1, name:'Joe')
|
63
|
+
TestModel.create!(id: 2, name:'Bob')
|
64
|
+
|
65
|
+
controller = Lanes::API::ControllerBase.new(TestModel,
|
66
|
+
Lanes::API::AuthenticationProvider.new({}),
|
67
|
+
{},
|
68
|
+
[{'id'=>1}, {'id'=>2}])
|
69
|
+
assert_equal( controller.send(:perform_multiple_destroy), {
|
70
|
+
:success=>true,
|
71
|
+
:message=>"Destroy succeeded",
|
72
|
+
:data=>[]
|
73
|
+
})
|
74
|
+
assert_empty TestModel.all.to_a
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
data/spec/server/asset_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative "spec_helper"
|
2
|
-
require "lanes/cli"
|
3
|
-
require "find"
|
2
|
+
# require "lanes/cli"
|
3
|
+
# require "find"
|
4
4
|
|
5
5
|
class Lanes::AssetTest < Lanes::TestCase
|
6
6
|
|
@@ -8,27 +8,32 @@ class Lanes::AssetTest < Lanes::TestCase
|
|
8
8
|
|
9
9
|
def setup
|
10
10
|
TestModel.has_one :asset, as: :owner, :class_name=>'Lanes::Asset'
|
11
|
-
@model = TestModel.new
|
12
11
|
end
|
13
12
|
|
14
13
|
def test_saveing_image
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
tm = TestModel.new
|
15
|
+
@model = TestModel.new
|
16
|
+
asset = @model.build_asset# (file: fixtures_path.join('logo.png').open)
|
17
|
+
tf=Tempfile.new
|
18
|
+
tf.write fixtures_path.join('logo.png').read
|
19
|
+
tf.rewind
|
20
|
+
asset.file = {
|
21
|
+
type: "image/png", name: "file",
|
22
|
+
filename: "Screen Shot 2016-10-28 at 5.15.37 PM.png",
|
23
|
+
head: "Content-Disposition: form-data; name=\"file\"; filename=\"Screen Shot 2016-10-28 at 5.15.37 PM.png\"\r\nContent-Type: image/png\r\n",
|
24
|
+
tempfile: tf
|
22
25
|
}
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_saving_blob
|
26
|
-
@model.build_asset(file: fixtures_path.join('system_settings.yml').open)
|
27
26
|
assert @model.save
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
|
28
|
+
assert_equal(@model.asset.file_data.keys, ["original", "medium", "thumbnail"])
|
29
|
+
assert_equal(
|
30
|
+
@model.asset.file_data['original']['metadata'].without('filename'), {
|
31
|
+
"size"=>42228,
|
32
|
+
"mime_type"=>"image/png",
|
33
|
+
"width"=>500,
|
34
|
+
"height"=>223
|
35
|
+
}
|
36
|
+
)
|
32
37
|
end
|
33
38
|
|
34
39
|
end
|
@@ -5,9 +5,10 @@ class ExportScopeTest < Lanes::TestCase
|
|
5
5
|
|
6
6
|
def test_scope_method_creation
|
7
7
|
refute TestModel.respond_to?(:big_query)
|
8
|
-
TestModel.send( :
|
8
|
+
TestModel.send( :scope, :big_query, ->{}, {export: true} )
|
9
9
|
assert TestModel.respond_to?(:big_query)
|
10
10
|
assert TestModel.has_exported_scope?(:big_query,DummyUser.new)
|
11
11
|
end
|
12
12
|
|
13
|
+
|
13
14
|
end
|
@@ -1,14 +1,21 @@
|
|
1
1
|
require_relative "../spec_helper"
|
2
2
|
|
3
3
|
class ExportedLimitsTest < Lanes::TestCase
|
4
|
+
module FakeScope
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
class_methods do
|
7
|
+
def scope(*args) # act like ActiveRecord model
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
4
11
|
|
5
|
-
class
|
6
|
-
|
12
|
+
class Base
|
13
|
+
include FakeScope
|
7
14
|
include Lanes::Concerns::ExportScope
|
8
15
|
include Lanes::Concerns::ExportMethods
|
16
|
+
end
|
9
17
|
|
10
|
-
|
11
|
-
end
|
18
|
+
class LimitsTestingModel < Base
|
12
19
|
|
13
20
|
def secret_method( name, query )
|
14
21
|
end
|
@@ -20,9 +27,9 @@ class ExportedLimitsTest < Lanes::TestCase
|
|
20
27
|
user == 'anon'
|
21
28
|
}
|
22
29
|
|
23
|
-
|
30
|
+
scope :admin_data, lambda { | param |
|
24
31
|
param
|
25
|
-
}, limit: :only_admins
|
32
|
+
}, export: {limit: :only_admins}
|
26
33
|
|
27
34
|
export_methods :secret_method, limit: :only_admins
|
28
35
|
|
@@ -34,11 +41,9 @@ class ExportedLimitsTest < Lanes::TestCase
|
|
34
41
|
end
|
35
42
|
|
36
43
|
def test_limits
|
37
|
-
|
38
|
-
|
44
|
+
assert LimitsTestingModel.has_exported_method?( 'test_method', 'anon' ), "anyone can retrieve no_limit data"
|
39
45
|
assert LimitsTestingModel.has_exported_scope?( 'admin_data', 'admin' ), "Admins can retrieve admin data"
|
40
46
|
refute LimitsTestingModel.has_exported_scope?( 'admin_data', 'non-admin' ), "Non-Admin cannot retrieve admin data"
|
41
|
-
|
42
47
|
assert LimitsTestingModel.has_exported_method?( 'secret_method', 'admin' ), "Public can retrieve public data"
|
43
48
|
refute LimitsTestingModel.has_exported_method?( 'secret_method', 'unk' ), "User must be admin to retrieve public data"
|
44
49
|
end
|
@@ -55,4 +55,21 @@ class SetAttributeDataTest < Lanes::TestCase
|
|
55
55
|
assert_equal 42, tm.instance_variable_get(:@setting)
|
56
56
|
end
|
57
57
|
|
58
|
+
def test_deleting_has_many
|
59
|
+
tm = TestModel.create!
|
60
|
+
1.upto(3) { |x| tm.hm.create({description: "description-#{x}"}) }
|
61
|
+
|
62
|
+
assert_equal tm.hm(true).count, 3
|
63
|
+
tm.set_attribute_data({
|
64
|
+
hm: [
|
65
|
+
{ 'id' => 1, 'description' => 'updated' },
|
66
|
+
{ 'id' => 2, '_delete' => true }
|
67
|
+
]
|
68
|
+
}, @user)
|
69
|
+
assert_saves tm
|
70
|
+
assert_equal tm.hm(true).count, 2
|
71
|
+
refute tm.hm.find_by(id: 2)
|
72
|
+
assert_equal tm.hm.find(1).description, 'updated'
|
73
|
+
end
|
74
|
+
|
58
75
|
end
|
data/spec/server/spec_helper.rb
CHANGED
@@ -6,26 +6,44 @@ require 'lanes/command'
|
|
6
6
|
require 'lanes/workspace/extension'
|
7
7
|
require 'mocha/mini_test'
|
8
8
|
|
9
|
+
require "shrine/storage/memory"
|
10
|
+
|
11
|
+
# Shrine.storages = {
|
12
|
+
# }
|
13
|
+
require "shrine"
|
14
|
+
require "shrine/storage/file_system"
|
15
|
+
|
16
|
+
Lanes::Concerns::AssetUploader.storages = {
|
17
|
+
cache: Shrine::Storage::Memory.new,
|
18
|
+
store: Shrine::Storage::Memory.new,
|
19
|
+
}
|
20
|
+
|
9
21
|
|
10
22
|
module TestingModels
|
11
23
|
include ActiveRecordMocks::IncludeMe
|
12
24
|
|
13
25
|
def around(&block)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
26
|
+
self.with_testing_models(&block)
|
27
|
+
|
28
|
+
# cw_root = CarrierWave.root
|
29
|
+
# begin
|
30
|
+
# Dir.mktmpdir('lanes-cw-root') do | dir |
|
31
|
+
# # CarrierWave.root = dir
|
32
|
+
# self.with_testing_models(&block)
|
33
|
+
# end
|
34
|
+
# ensure
|
35
|
+
# # CarrierWave.root = cw_root
|
36
|
+
# end
|
23
37
|
end
|
24
38
|
|
25
39
|
def with_testing_models
|
26
|
-
with_mocked_tables do |m|
|
27
40
|
|
28
|
-
|
41
|
+
with_mocked_tables do |m|
|
42
|
+
[:test_models, :tmbts, :tmhms].each do | table |
|
43
|
+
if ActiveRecord::Base.connection.data_source_exists? table
|
44
|
+
ActiveRecord::Base.connection.drop_table table
|
45
|
+
end
|
46
|
+
end
|
29
47
|
|
30
48
|
m.create_table do |t|
|
31
49
|
t.model_name :TestModel
|
data/views/specs.erb
CHANGED
@@ -14,7 +14,10 @@
|
|
14
14
|
<script src="<%= js_file %>" type="text/javascript"></script>
|
15
15
|
<% end %>
|
16
16
|
<script type="text/javascript">
|
17
|
-
|
17
|
+
Lanes.config.bootstrap( <%=
|
18
|
+
client_bootstrap_data(mergedWith: {
|
19
|
+
api_path: 'http://localhost:8888' + Lanes.config.api_path
|
20
|
+
}) %> );
|
18
21
|
</script>
|
19
22
|
|
20
23
|
</head>
|