nutella_framework 0.4.27 → 0.4.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/VERSION +1 -1
  4. data/framework_components/order.json +2 -1
  5. data/framework_components/room-places-interface/.gitignore +3 -0
  6. data/framework_components/room-places-interface/LICENSE +21 -0
  7. data/framework_components/room-places-interface/Readme.md +0 -0
  8. data/framework_components/room-places-interface/bower.json +29 -0
  9. data/framework_components/room-places-interface/bower_components/bower-mqttws/.bower.json +23 -0
  10. data/framework_components/room-places-interface/bower_components/bower-mqttws/bower.json +14 -0
  11. data/framework_components/room-places-interface/bower_components/bower-mqttws/mqttws31.js +2081 -0
  12. data/framework_components/room-places-interface/bower_components/bower-mqttws/readme.md +4 -0
  13. data/framework_components/room-places-interface/bower_components/nutella_lib/.bower.json +37 -0
  14. data/framework_components/room-places-interface/bower_components/nutella_lib/LICENSE +21 -0
  15. data/framework_components/room-places-interface/bower_components/nutella_lib/README.md +15 -0
  16. data/framework_components/room-places-interface/bower_components/nutella_lib/bower.json +28 -0
  17. data/framework_components/room-places-interface/bower_components/nutella_lib/examples/browser/mqtt_client_hello_world.html +23 -0
  18. data/framework_components/room-places-interface/bower_components/nutella_lib/examples/browser/nutella_hello_world.html +52 -0
  19. data/framework_components/room-places-interface/bower_components/nutella_lib/examples/node/mqtt_client_hello_world.js +14 -0
  20. data/framework_components/room-places-interface/bower_components/nutella_lib/examples/node/nutella_hello_world.js +38 -0
  21. data/framework_components/room-places-interface/bower_components/nutella_lib/nutella_lib.js +789 -0
  22. data/framework_components/room-places-interface/bower_components/nutella_lib/package.json +30 -0
  23. data/framework_components/room-places-interface/css/animation.css +22 -0
  24. data/framework_components/room-places-interface/css/bootstrap.min.css +5 -0
  25. data/framework_components/room-places-interface/css/cursor.css +22 -0
  26. data/framework_components/room-places-interface/css/font-awesome/css/font-awesome.css +1801 -0
  27. data/framework_components/room-places-interface/css/font-awesome/css/font-awesome.min.css +4 -0
  28. data/framework_components/room-places-interface/css/font-awesome/fonts/FontAwesome.otf +0 -0
  29. data/framework_components/room-places-interface/css/font-awesome/fonts/fontawesome-webfont.eot +0 -0
  30. data/framework_components/room-places-interface/css/font-awesome/fonts/fontawesome-webfont.svg +565 -0
  31. data/framework_components/room-places-interface/css/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
  32. data/framework_components/room-places-interface/css/font-awesome/fonts/fontawesome-webfont.woff +0 -0
  33. data/framework_components/room-places-interface/css/font-awesome/fonts/fontawesome-webfont.woff2 +0 -0
  34. data/framework_components/room-places-interface/css/font-awesome/less/animated.less +34 -0
  35. data/framework_components/room-places-interface/css/font-awesome/less/bordered-pulled.less +16 -0
  36. data/framework_components/room-places-interface/css/font-awesome/less/core.less +13 -0
  37. data/framework_components/room-places-interface/css/font-awesome/less/fixed-width.less +6 -0
  38. data/framework_components/room-places-interface/css/font-awesome/less/font-awesome.less +17 -0
  39. data/framework_components/room-places-interface/css/font-awesome/less/icons.less +596 -0
  40. data/framework_components/room-places-interface/css/font-awesome/less/larger.less +13 -0
  41. data/framework_components/room-places-interface/css/font-awesome/less/list.less +19 -0
  42. data/framework_components/room-places-interface/css/font-awesome/less/mixins.less +27 -0
  43. data/framework_components/room-places-interface/css/font-awesome/less/path.less +15 -0
  44. data/framework_components/room-places-interface/css/font-awesome/less/rotated-flipped.less +20 -0
  45. data/framework_components/room-places-interface/css/font-awesome/less/stacked.less +20 -0
  46. data/framework_components/room-places-interface/css/font-awesome/less/variables.less +606 -0
  47. data/framework_components/room-places-interface/css/font-awesome/scss/_animated.scss +34 -0
  48. data/framework_components/room-places-interface/css/font-awesome/scss/_bordered-pulled.scss +16 -0
  49. data/framework_components/room-places-interface/css/font-awesome/scss/_core.scss +13 -0
  50. data/framework_components/room-places-interface/css/font-awesome/scss/_fixed-width.scss +6 -0
  51. data/framework_components/room-places-interface/css/font-awesome/scss/_icons.scss +596 -0
  52. data/framework_components/room-places-interface/css/font-awesome/scss/_larger.scss +13 -0
  53. data/framework_components/room-places-interface/css/font-awesome/scss/_list.scss +19 -0
  54. data/framework_components/room-places-interface/css/font-awesome/scss/_mixins.scss +27 -0
  55. data/framework_components/room-places-interface/css/font-awesome/scss/_path.scss +15 -0
  56. data/framework_components/room-places-interface/css/font-awesome/scss/_rotated-flipped.scss +20 -0
  57. data/framework_components/room-places-interface/css/font-awesome/scss/_stacked.scss +20 -0
  58. data/framework_components/room-places-interface/css/font-awesome/scss/_variables.scss +606 -0
  59. data/framework_components/room-places-interface/css/font-awesome/scss/font-awesome.scss +17 -0
  60. data/framework_components/room-places-interface/css/icomoon.css +57 -0
  61. data/framework_components/room-places-interface/css/page_layout.css +82 -0
  62. data/framework_components/room-places-interface/fonts/icomoon.eot +0 -0
  63. data/framework_components/room-places-interface/fonts/icomoon.svg +17 -0
  64. data/framework_components/room-places-interface/fonts/icomoon.ttf +0 -0
  65. data/framework_components/room-places-interface/fonts/icomoon.woff +0 -0
  66. data/framework_components/room-places-interface/gulpfile.js +24 -0
  67. data/framework_components/room-places-interface/index.html +73 -0
  68. data/framework_components/room-places-interface/index2.html +1753 -0
  69. data/framework_components/room-places-interface/js/component.js +438 -0
  70. data/framework_components/room-places-interface/js/lib/JSXTransformer-0.12.2.js +15199 -0
  71. data/framework_components/room-places-interface/js/lib/bootstrap.min.js +7 -0
  72. data/framework_components/room-places-interface/js/lib/d3.v3.min.js +5 -0
  73. data/framework_components/room-places-interface/js/lib/jquery-1.10.0.min.js +6 -0
  74. data/framework_components/room-places-interface/js/lib/nutella_lib.js +4145 -0
  75. data/framework_components/room-places-interface/js/lib/react-with-addons-0.12.2.js +19822 -0
  76. data/framework_components/room-places-interface/js/lib/underscore.js +6 -0
  77. data/framework_components/room-places-interface/js/map.js +1593 -0
  78. data/framework_components/room-places-interface/js/position.js +6 -0
  79. data/framework_components/room-places-interface/js/react/dist/beacon.js +30 -0
  80. data/framework_components/room-places-interface/js/react/dist/discrete.js +282 -0
  81. data/framework_components/room-places-interface/js/react/dist/interactive-label.js +54 -0
  82. data/framework_components/room-places-interface/js/react/dist/resource-add.js +203 -0
  83. data/framework_components/room-places-interface/js/react/dist/resource-table.js +227 -0
  84. data/framework_components/room-places-interface/js/react/dist/resource.js +433 -0
  85. data/framework_components/room-places-interface/js/react/src/beacon.js +30 -0
  86. data/framework_components/room-places-interface/js/react/src/discrete.js +282 -0
  87. data/framework_components/room-places-interface/js/react/src/interactive-label.js +54 -0
  88. data/framework_components/room-places-interface/js/react/src/resource-add.js +203 -0
  89. data/framework_components/room-places-interface/js/react/src/resource-table.js +227 -0
  90. data/framework_components/room-places-interface/js/react/src/resource.js +433 -0
  91. data/framework_components/room-places-interface/js/room.js +65 -0
  92. data/framework_components/room-places-interface/nutella.json +6 -0
  93. data/nutella_framework.gemspec +93 -5
  94. metadata +91 -3
@@ -0,0 +1,438 @@
1
+ var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
2
+
3
+
4
+ var AddResource = React.createClass({
5
+ getInitialState: function() {
6
+ return {name: "", model: "IPAD", range: ""};
7
+ },
8
+ handleSubmit: function(e) {
9
+ e.preventDefault();
10
+
11
+ var name = this.refs.name.getDOMNode().value.trim();
12
+ var model = this.refs.model.getDOMNode().value.trim();
13
+ var range;
14
+ if(this.refs.range != undefined)
15
+ range = this.refs.range.getDOMNode().value.trim();
16
+ else
17
+ range = 0;
18
+
19
+ nutella.net.publish("location/resource/add", {rid: name, model: model, type: this.props.type, proximity_range: parseFloat(range)});
20
+
21
+ // Clean the form
22
+ this.setState({name: "", range: ""});
23
+ },
24
+ handleChangeName: function(e) {
25
+ this.setState({name: event.target.value});
26
+ },
27
+ handleChangeModel: function(e) {
28
+ this.setState({model: event.target.value});
29
+ },
30
+ handleChangeRange: function(e) {
31
+ this.setState({range: event.target.value});
32
+ },
33
+ render: function() {
34
+ var proxRange;
35
+ if(this.props.type == "STATIC")
36
+ proxRange = <input type="text" value={this.state.range} placeholder="Proximity range" onChange={this.handleChangeRange} ref="range"/>
37
+
38
+ return(
39
+ <tr>
40
+ <td>
41
+ <form onSubmit={this.handleSubmit}>
42
+ <input type="text" value={this.state.name} placeholder="Name" onChange={this.handleChangeName} ref="name"/>
43
+ {proxRange}
44
+ <select value={this.state.model} onChange={this.handleChangeModel} ref="model">
45
+ <option value="IMAC">iMac</option>
46
+ <option value="IPHONE">iPhone</option>
47
+ <option value="IPAD">iPad</option>
48
+ <option value="IBEACON">iBeacon</option>
49
+ </select>
50
+ <input type="submit" />
51
+ </form>
52
+ </td>
53
+ </tr>
54
+ );
55
+ }
56
+ });
57
+
58
+ var AddKeyValue = React.createClass({
59
+ getInitialState: function() {
60
+ return {key: "", value: ""};
61
+ },
62
+ handleChangeKey: function(e) {
63
+ this.setState({key: event.target.value});
64
+ },
65
+ handleChangeValue: function(e) {
66
+ this.setState({value: event.target.value});
67
+ },
68
+ handleSubmit: function(event) {
69
+ event.preventDefault();
70
+
71
+ var key = this.state.key;
72
+ var value = this.state.value;
73
+
74
+ if(key != "" && value != "") {
75
+ nutella.net.publish("location/resource/update", {rid: this.props.rid, parameters: [{key: key, value: value}]});
76
+ this.setState({key: "", value: ""});
77
+ }
78
+ },
79
+ render: function() {
80
+ return(
81
+ <tr>
82
+ <td>
83
+ <form onSubmit={this.handleSubmit}><input type="text" value={this.state.key} placeholder="Key" onChange={this.handleChangeKey} onBlur={this.handleSubmit} ref="key"/></form>
84
+ </td>
85
+ <td>
86
+ <form onSubmit={this.handleSubmit}><input type="text" value={this.state.value} placeholder="Value" onChange={this.handleChangeValue} onBlur={this.handleSubmit} ref="value"/></form>
87
+ </td>
88
+ </tr>
89
+ );
90
+ }
91
+ });
92
+
93
+ var KeyValue = React.createClass({
94
+ getInitialState: function() {
95
+ return {keyModification: false, valueModification: false, key: this.props._key, value: this.props.value, previousKey: this.props._key};
96
+ },
97
+ handleKeyChanged: function(event) {
98
+ this.setState({key: event.target.value});
99
+ },
100
+ handleValueChanged: function(event) {
101
+ this.setState({value: event.target.value});
102
+ },
103
+ handleKeyClicked: function() {
104
+ this.setState({keyModification: true}, function() {
105
+ this.refs.key.getDOMNode().focus();
106
+ });
107
+ },
108
+ handleValueClicked: function() {
109
+ this.setState({valueModification: true}, function() {
110
+ this.refs.value.getDOMNode().focus();
111
+ });
112
+ },
113
+ handleSubmit: function(event) {
114
+ event.preventDefault();
115
+
116
+ if(this.state.key == "" || this.state.value == "")
117
+ return;
118
+
119
+ if(this.state.key != this.state.previousKey) {
120
+ nutella.net.publish("location/resource/update", {rid: this.props.rid, parameters: [{key: this.state.previousKey, delete: true}]});
121
+ nutella.net.publish("location/resource/update", {rid: this.props.rid, parameters: [{key: this.state.key, value: this.state.value}]});
122
+ }
123
+ else {
124
+ nutella.net.publish("location/resource/update", {rid: this.props.rid, parameters: [{key: this.state.key, value: this.state.value}]});
125
+ }
126
+
127
+ this.setState({keyModification: false, valueModification: false, previousKey: this.state.key});
128
+ },
129
+ render: function() {
130
+ var key;
131
+ var value;
132
+ if(this.state.keyModification)
133
+ key = <form onSubmit={this.handleSubmit}><input type="text" placeholder="Key" ref="key" value={this.state.key} onChange={this.handleKeyChanged} onBlur={this.handleSubmit} /></form>
134
+ else
135
+ key = <div onClick={this.handleKeyClicked}>{this.state.key}</div>
136
+
137
+ if(this.state.valueModification)
138
+ value = <form onSubmit={this.handleSubmit}><input type="text" placeholder="Key" ref="value" value={this.state.value} onChange={this.handleValueChanged} onBlur={this.handleSubmit} /></form>
139
+ else
140
+ value = <div onClick={this.handleValueClicked}>{this.state.value}</div>
141
+
142
+ return(
143
+ <tr>
144
+ <td>{key}</td>
145
+ <td>{value}</td>
146
+ </tr>
147
+ );
148
+ }
149
+ });
150
+
151
+ var Resource = React.createClass({
152
+ getInitialState: function() {
153
+ return {collapse: false};
154
+ },
155
+ handleDelete: function() {
156
+ this.props.handleDelete(this.props.rid);
157
+ },
158
+ handleCollapse: function() {
159
+ this.setState({collapse: !this.state.collapse});
160
+ },
161
+ handleAddTrackingContinuous: function() {
162
+ this.props.handleAddTracking(this.props.resource, "continuous");
163
+ },
164
+ handleAddTrackingDiscrete: function() {
165
+ this.props.handleAddTracking(this.props.resource, "discrete");
166
+ },
167
+ handleAddTrackingNone: function() {
168
+ this.props.handleAddTracking(this.props.resource, "none");
169
+ },
170
+ render: function() {
171
+ var self = this;
172
+ var keyValues = this.props.keyValues.map(function (keyValue, index) {
173
+ return (
174
+ <KeyValue key={keyValue.key+"-"+keyValue.value} _key={keyValue.key} value={keyValue.value} rid={self.props.rid}/>
175
+ );
176
+ });
177
+
178
+ var _continuous = "";
179
+ var _discrete = "";
180
+ var _none = "";
181
+ if(this.props.resource.discrete != undefined) {
182
+ _discrete = " active";
183
+ }
184
+ else if(this.props.resource.continuous != undefined) {
185
+ _continuous = " active";
186
+ }
187
+ else {
188
+ _none = " active";
189
+ }
190
+
191
+ var addTracking = <div className="btn-group col-md-4 pull-right">
192
+ <button className={"col-md-4 btn btn-default" + _continuous} type="button" aria-label="Left Align" onClick={this.handleAddTrackingContinuous}>
193
+ <span className="glyphicon glyphicon-screenshot" aria-hidden="true" />
194
+ </button>
195
+ <button className={"col-md-4 btn btn-default" + _discrete} type="button" aria-label="Left Align" onClick={this.handleAddTrackingDiscrete}>
196
+ <span className="glyphicon glyphicon-th" aria-hidden="true" />
197
+ </button>
198
+ <button className={"col-md-4 btn btn-default" + _none} type="button" aria-label="Left Align" onClick={this.handleAddTrackingNone}>
199
+ <span className="glyphicon glyphicon-ban-circle" aria-hidden="true" />
200
+ </button>
201
+ </div>;
202
+
203
+ if(this.props.resource.type == "DYNAMIC")
204
+ addTracking = null;
205
+
206
+ return(
207
+ <tr>
208
+ <td>
209
+ <div className="col-md-4">{this.props.rid}</div>
210
+
211
+ <button className="col-md-1 btn btn-default pull-right" type="button" data-toggle="collapse" data-target={"#collapse_"+this.props.rid} aria-expanded="true" aria-controls={"collapse_"+this.props.rid} onClick={this.handleCollapse}>
212
+ <span className={this.state.collapse ? "glyphicon glyphicon-triangle-top" : "glyphicon glyphicon-triangle-bottom"} aria-hidden="true" />
213
+ </button>
214
+
215
+ <button className="col-md-1 btn btn-default pull-right" type="button" aria-label="Left Align" onClick={this.handleDelete}>
216
+ <span className="glyphicon glyphicon-remove" aria-hidden="true" />
217
+ </button>
218
+
219
+ {addTracking}
220
+ <div className="collapse" id={"collapse_"+this.props.rid}>
221
+ <table className="table table-bordered table-striped">
222
+ <ReactCSSTransitionGroup transitionName="example" component="tbody">
223
+ <tr><th>Key</th><th>Value</th></tr>
224
+ {keyValues}
225
+ <AddKeyValue rid={this.props.rid}/>
226
+ </ReactCSSTransitionGroup>
227
+ </table>
228
+ </div>
229
+ </td>
230
+ </tr>
231
+ );
232
+ }
233
+ });
234
+
235
+ var ResourceEstimote = React.createClass({
236
+ handleDynamicAdd: function() {
237
+ this.props.handleDynamicAdd(this.props.rid);
238
+ },
239
+ handleStaticAdd: function() {
240
+ this.props.handleStaticAdd(this.props.rid);
241
+ },
242
+ render: function() {
243
+ return(
244
+ <tr>
245
+ <td>
246
+ <div className="col-md-4">{this.props.rid}</div>
247
+ <button className="col-md-2 col-md-offset-4 btn btn-default" type="button" aria-label="Left Align" onClick={this.handleStaticAdd}>
248
+ <span className="glyphicon glyphicon-plus" aria-hidden="true" />
249
+ </button>
250
+ <button className="col-md-2 btn btn-default" type="button" aria-label="Left Align" onClick={this.handleDynamicAdd}>
251
+ <span className="glyphicon glyphicon-plus" aria-hidden="true" />
252
+ </button>
253
+ </td>
254
+ </tr>
255
+ );
256
+ }
257
+ });
258
+
259
+
260
+ var ResourceTable = React.createClass({
261
+ getInitialState: function() {
262
+ return {
263
+ resourceData: [],
264
+ estimoteData: []
265
+ };
266
+ },
267
+ componentDidMount: function() {
268
+ self = this;
269
+
270
+ // Download all resources
271
+ nutella.net.request("location/resources", {}, function(reply) {
272
+ self.setState({resourceData: reply.resources});
273
+ });
274
+
275
+ // Wait for new added resources
276
+ nutella.net.subscribe("location/resources/added", function(message) {
277
+ var data = self.state.resourceData;
278
+ data = data.concat(message.resources)
279
+
280
+ self.setState({resourceData: data});
281
+ });
282
+
283
+ // Wait for updated resources
284
+ nutella.net.subscribe("location/resources/updated", function(message) {
285
+ var data = self.state.resourceData;
286
+ data = data.filter(function(d) {
287
+ return $.inArray(d.rid, message.resources.map(function(r) {
288
+ return r.rid;
289
+ })) == -1;
290
+ });
291
+ data = data.concat(message.resources)
292
+ self.setState({resourceData: data});
293
+ });
294
+
295
+ // Wait for removed resources
296
+ nutella.net.subscribe("location/resources/removed", function(message) {
297
+ var data = self.state.resourceData;
298
+ data = data.filter(function(d) {
299
+ return $.inArray(d.rid, message.resources.map(function(r) {
300
+ return r.rid;
301
+ })) == -1;
302
+ });
303
+
304
+ self.setState({resourceData: data});
305
+ });
306
+
307
+ // Download estimote beacons data
308
+ nutella.net.request("location/estimote", {}, function(reply) {
309
+ self.setState({estimoteData: reply.resources});
310
+ });
311
+ },
312
+ handleResourceDelete: function(rid) {
313
+ nutella.net.publish("location/resource/remove", {rid: rid});
314
+
315
+ // Delete the corresponding row
316
+ var data = this.state.resourceData;
317
+ data = data.filter(function(d) { return d.rid != rid; });
318
+ this.setState({resourceData: data});
319
+ },
320
+ handleResourceEstimoteDynamicAdd: function(rid) {
321
+ nutella.net.publish("location/resource/add", {rid: rid,
322
+ model: "IBEACON",
323
+ type: "DYNAMIC"
324
+ });
325
+ },
326
+ handleResourceEstimoteStaticAdd: function(rid) {
327
+ nutella.net.publish("location/resource/add", {rid: rid,
328
+ model: "IBEACON",
329
+ type: "STATIC",
330
+ proximity_range: 1
331
+ });
332
+ },
333
+ handleAddTracking: function(resource, type) {
334
+ var x = this.props.room.x / 2;
335
+ var y = this.props.room.y / 2;
336
+
337
+ var message;
338
+
339
+ switch(type) {
340
+ case "continuous":
341
+ message = {rid: resource.rid,
342
+ continuous: {x: x, y: y}
343
+ };
344
+ break;
345
+
346
+ case "discrete":
347
+ message = {rid: resource.rid,
348
+ discrete: {x: 0, y: 0}
349
+ };
350
+ break;
351
+ default:
352
+ message = {rid: resource.rid};
353
+ break;
354
+ }
355
+
356
+ nutella.net.publish("location/resource/update", message);
357
+ },
358
+ render: function() {
359
+ var self = this;
360
+
361
+ // Order the resource list
362
+ var resources = this.state.resourceData;
363
+ resources = resources.sort(function(a, b) {return a.rid.localeCompare(b.rid)});
364
+
365
+ var staticResourcesData = resources.filter(function(resource) { return resource.type == "STATIC"});
366
+ var dynamicResourcesData = resources.filter(function(resource) { return resource.type == "DYNAMIC"});
367
+ var estimoteResourcesData = this.state.estimoteData.filter(function(resource) {
368
+ return $.inArray(resource.name, resources.map(function(r) {
369
+ return r.rid;
370
+ })) == -1;
371
+ });
372
+
373
+ var staticResources = staticResourcesData.map(function (resource, index) {
374
+ var keyValues = [];
375
+ for(key in resource.parameters) {
376
+ keyValues.push({key: key, value: resource.parameters[key]});
377
+ }
378
+ return (
379
+ <Resource key={resource.rid}
380
+ rid={resource.rid}
381
+ resource={resource}
382
+ room={self.props.room}
383
+ handleDelete={self.handleResourceDelete}
384
+ handleAddTracking={self.handleAddTracking}
385
+ keyValues={keyValues}/>
386
+ );
387
+ });
388
+
389
+ var dynamicResources = dynamicResourcesData.map(function (resource, index) {
390
+ var keyValues = [];
391
+ for(key in resource.parameters) {
392
+ keyValues.push({key: key, value: resource.parameters[key]});
393
+ }
394
+ return (
395
+ <Resource key={resource.rid}
396
+ rid={resource.rid}
397
+ resource={resource}
398
+ room={self.props.room}
399
+ handleDelete={self.handleResourceDelete}
400
+ handleAddTracking={self.handleAddTracking}
401
+ keyValues={keyValues}/>
402
+ );
403
+ });
404
+
405
+ var estimoteResources = estimoteResourcesData.map(function (resource, index) {
406
+ return (
407
+ <ResourceEstimote key={resource.name}
408
+ rid={resource.name}
409
+ handleDynamicAdd={self.handleResourceEstimoteDynamicAdd}
410
+ handleStaticAdd={self.handleResourceEstimoteStaticAdd}/>
411
+ );
412
+ });
413
+
414
+ return(
415
+ <div>
416
+ <table className="table table-bordered table-striped">
417
+ <ReactCSSTransitionGroup transitionName="example" component="tbody">
418
+ <tr><th>Static resources</th></tr>
419
+ {staticResources}
420
+ <AddResource type="STATIC"/>
421
+ </ReactCSSTransitionGroup>
422
+ </table>
423
+
424
+ <table className="table table-bordered table-striped">
425
+ <ReactCSSTransitionGroup transitionName="example" component="tbody">
426
+ <tr><th>Dynamic resources</th></tr>
427
+ {dynamicResources}
428
+ <AddResource type="DYNAMIC"/>
429
+
430
+ <tr><th>Estimote iBeacon</th></tr>
431
+ {estimoteResources}
432
+ </ReactCSSTransitionGroup>
433
+
434
+ </table>
435
+ </div>
436
+ );
437
+ }
438
+ });