+ {{#link-to "project.edit" model.id}}Edit project{{/link-to}}
+ {{#link-to "project.delete" model.id}}Delete project{{/link-to}}
+
diff --git a/app/templates/visualization/delete.hbs b/app/templates/visualization/delete.hbs
new file mode 100644
index 0000000..49e85ea
--- /dev/null
+++ b/app/templates/visualization/delete.hbs
@@ -0,0 +1 @@
+
+ {{#link-to "visualization.edit" model.id}}Edit visualization{{/link-to}}
+ {{#link-to "visualization.delete" model.id}}Delete visualization{{/link-to}}
+
diff --git a/app/templates/visualization/new.hbs b/app/templates/visualization/new.hbs
new file mode 100644
index 0000000..c9904d4
--- /dev/null
+++ b/app/templates/visualization/new.hbs
@@ -0,0 +1 @@
+
Date: Tue, 28 Jun 2016 14:23:49 +0200
Subject: [PATCH 006/556] Add visualizations and plots
Plots can be added via drag'n'drop.
---
app/components/draggable-dropzone.js | 26 +++++++++++
app/components/draggable-item.js | 13 ++++++
app/components/plot-chart.js | 4 ++
app/components/plot-container.js | 17 +++++++
app/components/plot-table.js | 5 ++
app/components/plot-value.js | 4 ++
app/controllers/visualization/index.js | 31 +++++++++++++
app/models/plot-table.js | 7 +++
app/models/plot.js | 9 ++--
app/styles/app.css | 46 ++++++++++++++++++-
.../components/draggable-dropzone.hbs | 1 +
app/templates/components/draggable-item.hbs | 1 +
app/templates/components/plot-chart.hbs | 1 +
app/templates/components/plot-container.hbs | 5 ++
app/templates/components/plot-table.hbs | 8 ++++
app/templates/components/plot-value.hbs | 1 +
app/templates/visualization/index.hbs | 23 ++++++++++
.../components/draggable-dropzone-test.js | 24 ++++++++++
.../components/draggable-item-test.js | 24 ++++++++++
.../integration/components/plot-chart-test.js | 24 ++++++++++
.../components/plot-container-test.js | 24 ++++++++++
.../integration/components/plot-table-test.js | 24 ++++++++++
.../integration/components/plot-value-test.js | 24 ++++++++++
.../controllers/visualization/index-test.js | 12 +++++
tests/unit/models/plot-table-test.js | 12 +++++
25 files changed, 365 insertions(+), 5 deletions(-)
create mode 100644 app/components/draggable-dropzone.js
create mode 100644 app/components/draggable-item.js
create mode 100644 app/components/plot-chart.js
create mode 100644 app/components/plot-container.js
create mode 100644 app/components/plot-table.js
create mode 100644 app/components/plot-value.js
create mode 100644 app/controllers/visualization/index.js
create mode 100644 app/models/plot-table.js
create mode 100644 app/templates/components/draggable-dropzone.hbs
create mode 100644 app/templates/components/draggable-item.hbs
create mode 100644 app/templates/components/plot-chart.hbs
create mode 100644 app/templates/components/plot-container.hbs
create mode 100644 app/templates/components/plot-table.hbs
create mode 100644 app/templates/components/plot-value.hbs
create mode 100644 tests/integration/components/draggable-dropzone-test.js
create mode 100644 tests/integration/components/draggable-item-test.js
create mode 100644 tests/integration/components/plot-chart-test.js
create mode 100644 tests/integration/components/plot-container-test.js
create mode 100644 tests/integration/components/plot-table-test.js
create mode 100644 tests/integration/components/plot-value-test.js
create mode 100644 tests/unit/controllers/visualization/index-test.js
create mode 100644 tests/unit/models/plot-table-test.js
diff --git a/app/components/draggable-dropzone.js b/app/components/draggable-dropzone.js
new file mode 100644
index 0000000..aa5c2f1
--- /dev/null
+++ b/app/components/draggable-dropzone.js
@@ -0,0 +1,26 @@
+import Ember from 'ember';
+
+var { set } = Ember;
+
+export default Ember.Component.extend({
+ classNames: [ 'draggableDropzone' ],
+ classNameBindings: [ 'dragClass' ],
+ dragClass: 'deactivated',
+
+ dragLeave(event) {
+ event.preventDefault();
+ set(this, 'dragClass', 'deactivated');
+ },
+
+ dragOver(event) {
+ event.preventDefault();
+ set(this, 'dragClass', 'activated');
+ },
+
+ drop(event) {
+ var data = event.dataTransfer.getData('text/data');
+ this.sendAction('dropped', data);
+
+ set(this, 'dragClass', 'deactivated');
+ }
+});
diff --git a/app/components/draggable-item.js b/app/components/draggable-item.js
new file mode 100644
index 0000000..841bd98
--- /dev/null
+++ b/app/components/draggable-item.js
@@ -0,0 +1,13 @@
+import Ember from 'ember';
+
+var { get } = Ember;
+
+export default Ember.Component.extend({
+ classNames: [ 'draggableItem' ],
+ attributeBindings: [ 'draggable' ],
+ draggable: 'true',
+
+ dragStart(event) {
+ return event.dataTransfer.setData('text/data', get(this, 'content'));
+ }
+});
diff --git a/app/components/plot-chart.js b/app/components/plot-chart.js
new file mode 100644
index 0000000..926b613
--- /dev/null
+++ b/app/components/plot-chart.js
@@ -0,0 +1,4 @@
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+});
diff --git a/app/components/plot-container.js b/app/components/plot-container.js
new file mode 100644
index 0000000..125d433
--- /dev/null
+++ b/app/components/plot-container.js
@@ -0,0 +1,17 @@
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+ tagName: 'div',
+ attributeBindings: [ 'style' ],
+
+ plot: null,
+
+ style: function() {
+ return 'width: ' + this.get('plot.width') + 'px; height: ' + this.get('plot.height') + 'px; border: 1px solid black;';
+ }.property('plot'),
+
+ isTable: function() {
+ var modelName = this.get('plot.constructor.modelName');
+ return modelName === 'plot-table';
+ }.property('plot.type')
+});
diff --git a/app/components/plot-table.js b/app/components/plot-table.js
new file mode 100644
index 0000000..e4b1f11
--- /dev/null
+++ b/app/components/plot-table.js
@@ -0,0 +1,5 @@
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+ tagName: 'table'
+});
diff --git a/app/components/plot-value.js b/app/components/plot-value.js
new file mode 100644
index 0000000..926b613
--- /dev/null
+++ b/app/components/plot-value.js
@@ -0,0 +1,4 @@
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+});
diff --git a/app/controllers/visualization/index.js b/app/controllers/visualization/index.js
new file mode 100644
index 0000000..a349f1c
--- /dev/null
+++ b/app/controllers/visualization/index.js
@@ -0,0 +1,31 @@
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ plots: [],
+
+ actions: {
+ addPlot(name) {
+ var plot = null;
+
+ if (name === 'chart') {
+ // create new chart plot
+ plot = this.store.createRecord('plot', { name: 'Chart 1', signal: 'Signal 1' });
+ } else if (name === 'table') {
+ plot = this.store.createRecord('plot-table', { name: 'Table 1', signal: 'Signal 1', width: 500 });
+ } else if (name === 'value') {
+ plot = this.store.createRecord('plot', { name: 'Value 1', signal: 'Signal 1' });
+ } else {
+ // DEBUG
+ console.log('Add plot: ' + name);
+ return;
+ }
+
+ if (plot != null) {
+ // add plot to visualization
+ this.plots.pushObject(plot);
+ } else {
+ console.error('Unknown plot type: ' + name);
+ }
+ }
+ }
+});
diff --git a/app/models/plot-table.js b/app/models/plot-table.js
new file mode 100644
index 0000000..8832e27
--- /dev/null
+++ b/app/models/plot-table.js
@@ -0,0 +1,7 @@
+import Plot from './plot';
+// import attr from 'ember-data/attr';
+// import { belongsTo, hasMany } from 'ember-data/relationships';
+
+export default Plot.extend({
+ type: 'table'
+});
diff --git a/app/models/plot.js b/app/models/plot.js
index 0f3204d..82cf15c 100644
--- a/app/models/plot.js
+++ b/app/models/plot.js
@@ -5,8 +5,9 @@ import attr from 'ember-data/attr';
export default Model.extend({
name: attr('string'),
signal: attr('string'),
- //position:
- //size:
- title: attr('string')
- //backgroundColor:
+ width: attr('number', { defaultValue: 100 }),
+ height: attr('number', { defaultValue: 100 }),
+ title: attr('string'),
+
+ type: 'plot'
});
diff --git a/app/styles/app.css b/app/styles/app.css
index c3f270c..9530318 100644
--- a/app/styles/app.css
+++ b/app/styles/app.css
@@ -98,9 +98,53 @@ footer {
}
#login {
-
+
}
#login-form {
padding: 20px 20px;
}
+
+/**
+ * Visualization
+ */
+.plots {
+ margin-top: 20px;
+ margin-bottom: 20px;
+}
+
+.plot-toolbox {
+ margin-top: 20px;
+}
+
+.draggableDropzone {
+ display: block;
+
+ min-height: 200px;
+
+ padding-top: 5px;
+ padding-left: 10px;
+
+ border: 3px dashed #aaa;
+
+ &.activated {
+ border-color: #2ecc71;
+ }
+ &.deactivated {
+ border-color: #e1e1e1;
+ }
+}
+
+.draggableItem[draggable=true] {
+ display: inline-block;
+ background: #e1e1e1;
+ cursor: move;
+
+ padding: 5px 10px;
+
+ border: 1px solid gray;
+
+ &:hover {
+ background-color: #aaa;
+ }
+}
diff --git a/app/templates/components/draggable-dropzone.hbs b/app/templates/components/draggable-dropzone.hbs
new file mode 100644
index 0000000..889d9ee
--- /dev/null
+++ b/app/templates/components/draggable-dropzone.hbs
@@ -0,0 +1 @@
+{{yield}}
diff --git a/app/templates/components/draggable-item.hbs b/app/templates/components/draggable-item.hbs
new file mode 100644
index 0000000..889d9ee
--- /dev/null
+++ b/app/templates/components/draggable-item.hbs
@@ -0,0 +1 @@
+{{yield}}
diff --git a/app/templates/components/plot-chart.hbs b/app/templates/components/plot-chart.hbs
new file mode 100644
index 0000000..889d9ee
--- /dev/null
+++ b/app/templates/components/plot-chart.hbs
@@ -0,0 +1 @@
+{{yield}}
diff --git a/app/templates/components/plot-container.hbs b/app/templates/components/plot-container.hbs
new file mode 100644
index 0000000..53fbc14
--- /dev/null
+++ b/app/templates/components/plot-container.hbs
@@ -0,0 +1,5 @@
+{{#if isTable}}
+ {{#plot-table plot=plot}}{{/plot-table}}
+{{else}}
+ Plot
+{{/if}}
diff --git a/app/templates/components/plot-table.hbs b/app/templates/components/plot-table.hbs
new file mode 100644
index 0000000..0a1d321
--- /dev/null
+++ b/app/templates/components/plot-table.hbs
@@ -0,0 +1,8 @@
+
+ Name
+ Value
+
+
+ Signal X
+ 1.234
+
diff --git a/app/templates/components/plot-value.hbs b/app/templates/components/plot-value.hbs
new file mode 100644
index 0000000..889d9ee
--- /dev/null
+++ b/app/templates/components/plot-value.hbs
@@ -0,0 +1 @@
+{{yield}}
diff --git a/app/templates/visualization/index.hbs b/app/templates/visualization/index.hbs
index 1156777..b11c764 100644
--- a/app/templates/visualization/index.hbs
+++ b/app/templates/visualization/index.hbs
@@ -1,5 +1,28 @@
{{model.name}}
+
+
Toolbox
+ {{#draggable-item content='chart'}}
+ Chart
+ {{/draggable-item}}
+
+ {{#draggable-item content='table'}}
+ Table
+ {{/draggable-item}}
+
+ {{#draggable-item content='value'}}
+ Value
+ {{/draggable-item}}
+
+
+
+ {{#draggable-dropzone dropped='addPlot'}}
+ {{#each plots as |plot|}}
+ {{#plot-container plot=plot}}{{/plot-container}}
+ {{/each}}
+ {{/draggable-dropzone}}
+
+
{{#link-to "visualization.edit" model.id}}Edit visualization{{/link-to}}
{{#link-to "visualization.delete" model.id}}Delete visualization{{/link-to}}
diff --git a/tests/integration/components/draggable-dropzone-test.js b/tests/integration/components/draggable-dropzone-test.js
new file mode 100644
index 0000000..68c8c69
--- /dev/null
+++ b/tests/integration/components/draggable-dropzone-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('draggable-dropzone', 'Integration | Component | draggable dropzone', {
+ integration: true
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{draggable-dropzone}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:
+ this.render(hbs`
+ {{#draggable-dropzone}}
+ template block text
+ {{/draggable-dropzone}}
+ `);
+
+ assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/tests/integration/components/draggable-item-test.js b/tests/integration/components/draggable-item-test.js
new file mode 100644
index 0000000..93830ba
--- /dev/null
+++ b/tests/integration/components/draggable-item-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('draggable-item', 'Integration | Component | draggable item', {
+ integration: true
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{draggable-item}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:
+ this.render(hbs`
+ {{#draggable-item}}
+ template block text
+ {{/draggable-item}}
+ `);
+
+ assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/tests/integration/components/plot-chart-test.js b/tests/integration/components/plot-chart-test.js
new file mode 100644
index 0000000..17234e4
--- /dev/null
+++ b/tests/integration/components/plot-chart-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('plot-chart', 'Integration | Component | plot chart', {
+ integration: true
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{plot-chart}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:
+ this.render(hbs`
+ {{#plot-chart}}
+ template block text
+ {{/plot-chart}}
+ `);
+
+ assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/tests/integration/components/plot-container-test.js b/tests/integration/components/plot-container-test.js
new file mode 100644
index 0000000..a929846
--- /dev/null
+++ b/tests/integration/components/plot-container-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('plot-container', 'Integration | Component | plot container', {
+ integration: true
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{plot-container}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:
+ this.render(hbs`
+ {{#plot-container}}
+ template block text
+ {{/plot-container}}
+ `);
+
+ assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/tests/integration/components/plot-table-test.js b/tests/integration/components/plot-table-test.js
new file mode 100644
index 0000000..927514e
--- /dev/null
+++ b/tests/integration/components/plot-table-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('plot-table', 'Integration | Component | plot table', {
+ integration: true
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{plot-table}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:
+ this.render(hbs`
+ {{#plot-table}}
+ template block text
+ {{/plot-table}}
+ `);
+
+ assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/tests/integration/components/plot-value-test.js b/tests/integration/components/plot-value-test.js
new file mode 100644
index 0000000..5a65558
--- /dev/null
+++ b/tests/integration/components/plot-value-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('plot-value', 'Integration | Component | plot value', {
+ integration: true
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{plot-value}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:
+ this.render(hbs`
+ {{#plot-value}}
+ template block text
+ {{/plot-value}}
+ `);
+
+ assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/tests/unit/controllers/visualization/index-test.js b/tests/unit/controllers/visualization/index-test.js
new file mode 100644
index 0000000..d2ee03f
--- /dev/null
+++ b/tests/unit/controllers/visualization/index-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:visualization/index', 'Unit | Controller | visualization/index', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/models/plot-table-test.js b/tests/unit/models/plot-table-test.js
new file mode 100644
index 0000000..d1406f5
--- /dev/null
+++ b/tests/unit/models/plot-table-test.js
@@ -0,0 +1,12 @@
+import { moduleForModel, test } from 'ember-qunit';
+
+moduleForModel('plot-table', 'Unit | Model | plot table', {
+ // Specify the other units that are required for this test.
+ needs: []
+});
+
+test('it exists', function(assert) {
+ let model = this.subject();
+ // let store = this.store();
+ assert.ok(!!model);
+});
From 480c90530d9243d484cab9b86aaa8d14fdaaf336 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Tue, 28 Jun 2016 22:05:54 +0200
Subject: [PATCH 007/556] Add visualization create, edit and delete
All plots will be saved in the plot model (no subclasses).
---
app/adapters/application.js | 4 +-
app/components/plot-container.js | 4 +-
app/controllers/project/delete.js | 20 ++++++++--
app/controllers/project/index.js | 22 +++++++++++
app/controllers/visualization/delete.js | 34 +++++++++++++++++
app/controllers/visualization/edit.js | 38 +++++++++++++++++++
app/controllers/visualization/index.js | 27 -------------
app/models/plot-table.js | 7 ----
app/models/plot.js | 3 +-
app/models/visualization.js | 5 ++-
app/serializers/project.js | 3 +-
app/serializers/visualization.js | 8 ++++
app/templates/project/index.hbs | 2 +-
app/templates/visualization/delete.hbs | 5 +++
app/templates/visualization/edit.hbs | 30 ++++++++++++++-
app/templates/visualization/index.hbs | 23 ++---------
tests/unit/controllers/project/index-test.js | 12 ++++++
.../controllers/visualization/delete-test.js | 12 ++++++
.../controllers/visualization/edit-test.js | 12 ++++++
tests/unit/models/plot-table-test.js | 12 ------
tests/unit/serializers/visualization-test.js | 15 ++++++++
21 files changed, 216 insertions(+), 82 deletions(-)
create mode 100644 app/controllers/project/index.js
create mode 100644 app/controllers/visualization/delete.js
create mode 100644 app/controllers/visualization/edit.js
delete mode 100644 app/models/plot-table.js
create mode 100644 app/serializers/visualization.js
create mode 100644 tests/unit/controllers/project/index-test.js
create mode 100644 tests/unit/controllers/visualization/delete-test.js
create mode 100644 tests/unit/controllers/visualization/edit-test.js
delete mode 100644 tests/unit/models/plot-table-test.js
create mode 100644 tests/unit/serializers/visualization-test.js
diff --git a/app/adapters/application.js b/app/adapters/application.js
index b24b25b..8eb0625 100644
--- a/app/adapters/application.js
+++ b/app/adapters/application.js
@@ -5,7 +5,5 @@ export default RESTAdapter.extend(DataAdapterMixin, {
host: 'http://192.168.99.100:3000',
namespace: 'api/v1',
authorizer: 'authorizer:custom',
- headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
-
-
+ headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }
});
diff --git a/app/components/plot-container.js b/app/components/plot-container.js
index 125d433..b4b402b 100644
--- a/app/components/plot-container.js
+++ b/app/components/plot-container.js
@@ -11,7 +11,7 @@ export default Ember.Component.extend({
}.property('plot'),
isTable: function() {
- var modelName = this.get('plot.constructor.modelName');
- return modelName === 'plot-table';
+ var type = this.get('plot.type');
+ return type === 'table';
}.property('plot.type')
});
diff --git a/app/controllers/project/delete.js b/app/controllers/project/delete.js
index 498cd53..6435bed 100644
--- a/app/controllers/project/delete.js
+++ b/app/controllers/project/delete.js
@@ -21,12 +21,24 @@ export default Ember.Controller.extend({
// delete the project and remove from user projects
user.get('projects').removeObject(projectId);
- user.save();
+ user.save().then(function() {
+ // destroy all visualizations
+ var visualizations = project.get('visualizations');
+ visualizations.forEach(function(visualization) {
+ // destroy all plots
+ var plots = visualization.get('plots');
+ plots.forEach(function(plot) {
+ plot.destroyRecord();
+ });
- project.destroyRecord();
+ visualization.destroyRecord();
+ });
- // go back to project list
- this.transitionToRoute('/projects');
+ project.destroyRecord();
+
+ // go back to project list
+ this.transitionToRoute('/projects');
+ });
}
}
});
diff --git a/app/controllers/project/index.js b/app/controllers/project/index.js
new file mode 100644
index 0000000..eb33367
--- /dev/null
+++ b/app/controllers/project/index.js
@@ -0,0 +1,22 @@
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ actions: {
+ newVisualization() {
+ // get the project
+ var project = this.get('model');
+ var projectId = this.get('model.id');
+
+ // create the visualization
+ var visualization = this.store.createRecord('visualization', { name: 'Visualization', project: projectId });
+
+ // the visualization must be added to the project before the project is saved, otherwise ember will set the projectId to null!
+ project.get('visualizations').pushObject(visualization);
+
+ // save the visualization and project
+ visualization.save().then(function() {
+ project.save();
+ });
+ }
+ }
+});
diff --git a/app/controllers/visualization/delete.js b/app/controllers/visualization/delete.js
new file mode 100644
index 0000000..6ceee2b
--- /dev/null
+++ b/app/controllers/visualization/delete.js
@@ -0,0 +1,34 @@
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ actions: {
+ cancelDelete() {
+ // go back to visualization edit view
+ let visualizationId = this.get('model.id');
+ this.transitionToRoute('/visualization/' + visualizationId);
+ },
+
+ confirmDelete() {
+ // get the objects
+ var visualization = this.get('model');
+ let visualizationId = this.get('model.id');
+
+ var projectId = this.get('model.project.id');
+ var project = this.store.peekRecord('project', projectId);
+
+ // delete the visualization and remove from the project
+ project.get('visualizations').removeObject(visualizationId);
+ project.save().then(function() {
+ // destroy all plots
+ var plots = visualization.get('plots');
+ plots.forEach(function(plot) {
+ plot.destroyRecord();
+ });
+
+ visualization.destroyRecord();
+
+ this.transitionToRoute('/project/' + projectId);
+ });
+ }
+ }
+});
diff --git a/app/controllers/visualization/edit.js b/app/controllers/visualization/edit.js
new file mode 100644
index 0000000..9dd113f
--- /dev/null
+++ b/app/controllers/visualization/edit.js
@@ -0,0 +1,38 @@
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ actions: {
+ addPlot(name) {
+ var plot = null;
+
+ if (name === 'chart') {
+ // create new chart plot
+ plot = this.store.createRecord('plot', { name: 'Chart 1', signal: 'Signal 1', type: 'chart' });
+ } else if (name === 'table') {
+ plot = this.store.createRecord('plot', { name: 'Table 1', signal: 'Signal 1', type: 'table', width: 500 });
+ } else if (name === 'value') {
+ plot = this.store.createRecord('plot', { name: 'Value 1', signal: 'Signal 1', type: 'value' });
+ } else {
+ // DEBUG
+ console.log('Add plot: ' + name);
+ return;
+ }
+
+ if (plot != null) {
+ // add plot to visualization
+ this.get('model.plots').pushObject(plot);
+
+ // save new plot
+ var visualization = this.get('model');
+
+ plot.save().then(function() {
+ // save the plot in the visualization
+ visualization.get('plots').pushObject(plot);
+ visualization.save();
+ });
+ } else {
+ console.error('Unknown plot type: ' + name);
+ }
+ }
+ }
+});
diff --git a/app/controllers/visualization/index.js b/app/controllers/visualization/index.js
index a349f1c..55ff9aa 100644
--- a/app/controllers/visualization/index.js
+++ b/app/controllers/visualization/index.js
@@ -1,31 +1,4 @@
import Ember from 'ember';
export default Ember.Controller.extend({
- plots: [],
-
- actions: {
- addPlot(name) {
- var plot = null;
-
- if (name === 'chart') {
- // create new chart plot
- plot = this.store.createRecord('plot', { name: 'Chart 1', signal: 'Signal 1' });
- } else if (name === 'table') {
- plot = this.store.createRecord('plot-table', { name: 'Table 1', signal: 'Signal 1', width: 500 });
- } else if (name === 'value') {
- plot = this.store.createRecord('plot', { name: 'Value 1', signal: 'Signal 1' });
- } else {
- // DEBUG
- console.log('Add plot: ' + name);
- return;
- }
-
- if (plot != null) {
- // add plot to visualization
- this.plots.pushObject(plot);
- } else {
- console.error('Unknown plot type: ' + name);
- }
- }
- }
});
diff --git a/app/models/plot-table.js b/app/models/plot-table.js
deleted file mode 100644
index 8832e27..0000000
--- a/app/models/plot-table.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Plot from './plot';
-// import attr from 'ember-data/attr';
-// import { belongsTo, hasMany } from 'ember-data/relationships';
-
-export default Plot.extend({
- type: 'table'
-});
diff --git a/app/models/plot.js b/app/models/plot.js
index 82cf15c..ec1bb8f 100644
--- a/app/models/plot.js
+++ b/app/models/plot.js
@@ -8,6 +8,5 @@ export default Model.extend({
width: attr('number', { defaultValue: 100 }),
height: attr('number', { defaultValue: 100 }),
title: attr('string'),
-
- type: 'plot'
+ type: attr('string')
});
diff --git a/app/models/visualization.js b/app/models/visualization.js
index 709e47c..3779d59 100644
--- a/app/models/visualization.js
+++ b/app/models/visualization.js
@@ -1,8 +1,9 @@
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
-import { hasMany } from 'ember-data/relationships';
+import { belongsTo, hasMany } from 'ember-data/relationships';
export default Model.extend({
name: attr('string'),
- plots: hasMany('plot', { async: true })
+ plots: hasMany('plot', { async: true }),
+ project: belongsTo('project', { async: true })
});
diff --git a/app/serializers/project.js b/app/serializers/project.js
index cf2bb44..afe8e13 100644
--- a/app/serializers/project.js
+++ b/app/serializers/project.js
@@ -2,6 +2,7 @@ import ApplicationSerializer from './application';
export default ApplicationSerializer.extend({
attrs: {
- owner: { serialize: 'ids' }
+ owner: { serialize: 'ids' },
+ visualizations: { serialize: 'ids' }
}
});
diff --git a/app/serializers/visualization.js b/app/serializers/visualization.js
new file mode 100644
index 0000000..eade34d
--- /dev/null
+++ b/app/serializers/visualization.js
@@ -0,0 +1,8 @@
+import ApplicationSerializer from './application';
+
+export default ApplicationSerializer.extend({
+ attrs: {
+ project: { serialize: 'ids' },
+ plots: { serialize: 'ids' }
+ }
+});
diff --git a/app/templates/project/index.hbs b/app/templates/project/index.hbs
index 2ecd482..d35cd7f 100644
--- a/app/templates/project/index.hbs
+++ b/app/templates/project/index.hbs
@@ -13,7 +13,7 @@
- {{#link-to 'visualization.new'}}New visualization{{/link-to}}
+ New visualization
diff --git a/app/templates/visualization/delete.hbs b/app/templates/visualization/delete.hbs
index 49e85ea..0be5279 100644
--- a/app/templates/visualization/delete.hbs
+++ b/app/templates/visualization/delete.hbs
@@ -1 +1,6 @@
Delete
+
+Are you sure you want to delete the visualization?
+
+Cancel
+Delete
diff --git a/app/templates/visualization/edit.hbs b/app/templates/visualization/edit.hbs
index a835e09..2a10125 100644
--- a/app/templates/visualization/edit.hbs
+++ b/app/templates/visualization/edit.hbs
@@ -1 +1,29 @@
-Edit
+{{model.name}}
+
+
+
Toolbox
+ {{#draggable-item content='chart'}}
+ Chart
+ {{/draggable-item}}
+
+ {{#draggable-item content='table'}}
+ Table
+ {{/draggable-item}}
+
+ {{#draggable-item content='value'}}
+ Value
+ {{/draggable-item}}
+
+
+
+ {{#draggable-dropzone dropped='addPlot'}}
+ {{#each model.plots as |plot|}}
+ {{#plot-container plot=plot}}{{/plot-container}}
+ {{/each}}
+ {{/draggable-dropzone}}
+
+
+
+ Cancel
+ Save
+
diff --git a/app/templates/visualization/index.hbs b/app/templates/visualization/index.hbs
index b11c764..b41cca6 100644
--- a/app/templates/visualization/index.hbs
+++ b/app/templates/visualization/index.hbs
@@ -1,26 +1,9 @@
{{model.name}}
-
-
Toolbox
- {{#draggable-item content='chart'}}
- Chart
- {{/draggable-item}}
-
- {{#draggable-item content='table'}}
- Table
- {{/draggable-item}}
-
- {{#draggable-item content='value'}}
- Value
- {{/draggable-item}}
-
-
- {{#draggable-dropzone dropped='addPlot'}}
- {{#each plots as |plot|}}
- {{#plot-container plot=plot}}{{/plot-container}}
- {{/each}}
- {{/draggable-dropzone}}
+ {{#each model.plots as |plot|}}
+ {{#plot-container plot=plot}}{{/plot-container}}
+ {{/each}}
diff --git a/tests/unit/controllers/project/index-test.js b/tests/unit/controllers/project/index-test.js
new file mode 100644
index 0000000..b72dc07
--- /dev/null
+++ b/tests/unit/controllers/project/index-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:project/index', 'Unit | Controller | project/index', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/controllers/visualization/delete-test.js b/tests/unit/controllers/visualization/delete-test.js
new file mode 100644
index 0000000..dc98464
--- /dev/null
+++ b/tests/unit/controllers/visualization/delete-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:visualization/delete', 'Unit | Controller | visualization/delete', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/controllers/visualization/edit-test.js b/tests/unit/controllers/visualization/edit-test.js
new file mode 100644
index 0000000..e0a5451
--- /dev/null
+++ b/tests/unit/controllers/visualization/edit-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:visualization/edit', 'Unit | Controller | visualization/edit', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/models/plot-table-test.js b/tests/unit/models/plot-table-test.js
deleted file mode 100644
index d1406f5..0000000
--- a/tests/unit/models/plot-table-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('plot-table', 'Unit | Model | plot table', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/serializers/visualization-test.js b/tests/unit/serializers/visualization-test.js
new file mode 100644
index 0000000..f31eeec
--- /dev/null
+++ b/tests/unit/serializers/visualization-test.js
@@ -0,0 +1,15 @@
+import { moduleForModel, test } from 'ember-qunit';
+
+moduleForModel('visualization', 'Unit | Serializer | visualization', {
+ // Specify the other units that are required for this test.
+ needs: ['serializer:visualization']
+});
+
+// Replace this with your real tests.
+test('it serializes records', function(assert) {
+ let record = this.subject();
+
+ let serializedRecord = record.serialize();
+
+ assert.ok(serializedRecord);
+});
From db993e2d2f8940fe8b13ee770c72c3ead23caa2a Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 29 Jun 2016 17:08:42 +0200
Subject: [PATCH 008/556] Add todo.md
Fix project and visualization delete
Start with plot styling
---
app/components/plot-container.js | 4 ++-
app/components/plot-table.js | 5 +++-
app/controllers/project/delete.js | 31 +++++++++++----------
app/controllers/visualization/delete.js | 20 +++++++------
app/router.js | 3 ++
app/routes/404.js | 4 +++
app/styles/app.css | 25 +++++++++++++++--
app/templates/404.hbs | 1 +
app/templates/components/plot-container.hbs | 2 +-
app/templates/components/plot-table.hbs | 24 ++++++++++------
app/templates/visualization/edit.hbs | 2 +-
tests/unit/routes/404-test.js | 11 ++++++++
todo.md | 8 ++++++
13 files changed, 101 insertions(+), 39 deletions(-)
create mode 100644 app/routes/404.js
create mode 100644 app/templates/404.hbs
create mode 100644 tests/unit/routes/404-test.js
create mode 100644 todo.md
diff --git a/app/components/plot-container.js b/app/components/plot-container.js
index b4b402b..2297b13 100644
--- a/app/components/plot-container.js
+++ b/app/components/plot-container.js
@@ -3,11 +3,13 @@ import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'div',
attributeBindings: [ 'style' ],
+ classNames: [ 'plotContainer' ],
plot: null,
+ editing: false,
style: function() {
- return 'width: ' + this.get('plot.width') + 'px; height: ' + this.get('plot.height') + 'px; border: 1px solid black;';
+ return 'width: ' + this.get('plot.width') + 'px; height: ' + this.get('plot.height') + 'px;';
}.property('plot'),
isTable: function() {
diff --git a/app/components/plot-table.js b/app/components/plot-table.js
index e4b1f11..7c66b4e 100644
--- a/app/components/plot-table.js
+++ b/app/components/plot-table.js
@@ -1,5 +1,8 @@
import Ember from 'ember';
export default Ember.Component.extend({
- tagName: 'table'
+ tagName: 'div',
+ classNames: [ '' ],
+
+ editing: false
});
diff --git a/app/controllers/project/delete.js b/app/controllers/project/delete.js
index 6435bed..dbc5cc7 100644
--- a/app/controllers/project/delete.js
+++ b/app/controllers/project/delete.js
@@ -20,24 +20,25 @@ export default Ember.Controller.extend({
let projectId = project.get('id');
// delete the project and remove from user projects
- user.get('projects').removeObject(projectId);
- user.save().then(function() {
- // destroy all visualizations
- var visualizations = project.get('visualizations');
- visualizations.forEach(function(visualization) {
- // destroy all plots
- var plots = visualization.get('plots');
- plots.forEach(function(plot) {
- plot.destroyRecord();
- });
-
- visualization.destroyRecord();
+ var visualizations = project.get('visualizations');
+ visualizations.forEach(function(visualization) {
+ // destroy all plots
+ var plots = visualization.get('plots');
+ plots.forEach(function(plot) {
+ plot.destroyRecord();
});
- project.destroyRecord();
+ visualization.destroyRecord();
+ });
- // go back to project list
- this.transitionToRoute('/projects');
+ project.destroyRecord();
+
+ // save the changes to project
+ var controller = this;
+
+ user.get('projects').removeObject(projectId);
+ user.save().then(function() {
+ controller.transitionToRoute('/projects');
});
}
}
diff --git a/app/controllers/visualization/delete.js b/app/controllers/visualization/delete.js
index 6ceee2b..37c2c9b 100644
--- a/app/controllers/visualization/delete.js
+++ b/app/controllers/visualization/delete.js
@@ -16,18 +16,20 @@ export default Ember.Controller.extend({
var projectId = this.get('model.project.id');
var project = this.store.peekRecord('project', projectId);
+ // destroy all plots
+ var plots = visualization.get('plots');
+ plots.forEach(function(plot) {
+ plot.destroyRecord();
+ });
+
+ visualization.destroyRecord();
+
// delete the visualization and remove from the project
+ var controller = this;
+
project.get('visualizations').removeObject(visualizationId);
project.save().then(function() {
- // destroy all plots
- var plots = visualization.get('plots');
- plots.forEach(function(plot) {
- plot.destroyRecord();
- });
-
- visualization.destroyRecord();
-
- this.transitionToRoute('/project/' + projectId);
+ controller.transitionToRoute('/project/' + projectId);
});
}
}
diff --git a/app/router.js b/app/router.js
index 3b52f3d..c8d5437 100644
--- a/app/router.js
+++ b/app/router.js
@@ -19,12 +19,15 @@ Router.map(function() {
this.route('user', function() {
this.route('edit');
});
+
this.route('visualization', function() {
this.route('index', { path: '/:visualizationid' });
this.route('new');
this.route('edit', { path: '/edit/:visualizationid' });
this.route('delete', { path: '/delete/:visualizationid' });
});
+
+ this.route('404', { path: '/*path' });
});
export default Router;
diff --git a/app/routes/404.js b/app/routes/404.js
new file mode 100644
index 0000000..26d9f31
--- /dev/null
+++ b/app/routes/404.js
@@ -0,0 +1,4 @@
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+});
diff --git a/app/styles/app.css b/app/styles/app.css
index 9530318..83d5df6 100644
--- a/app/styles/app.css
+++ b/app/styles/app.css
@@ -122,9 +122,6 @@ footer {
min-height: 200px;
- padding-top: 5px;
- padding-left: 10px;
-
border: 3px dashed #aaa;
&.activated {
@@ -148,3 +145,25 @@ footer {
background-color: #aaa;
}
}
+
+.plotContainer {
+ border: 1px solid lightgray;
+
+ margin: 10px;
+ padding: 5px 10px;
+}
+
+.plotTable {
+ width: 100%;
+ height: 100%;
+
+ border: 1px solid gray;
+
+ border-collapse: collapse;
+}
+
+.plotTable td, th {
+ border: 1px solid gray;
+
+ padding: 2px 5px;
+}
diff --git a/app/templates/404.hbs b/app/templates/404.hbs
new file mode 100644
index 0000000..9a83fd7
--- /dev/null
+++ b/app/templates/404.hbs
@@ -0,0 +1 @@
+404 - Not found
diff --git a/app/templates/components/plot-container.hbs b/app/templates/components/plot-container.hbs
index 53fbc14..b223224 100644
--- a/app/templates/components/plot-container.hbs
+++ b/app/templates/components/plot-container.hbs
@@ -1,5 +1,5 @@
{{#if isTable}}
- {{#plot-table plot=plot}}{{/plot-table}}
+ {{#plot-table plot=plot editing=editing}}{{/plot-table}}
{{else}}
Plot
{{/if}}
diff --git a/app/templates/components/plot-table.hbs b/app/templates/components/plot-table.hbs
index 0a1d321..6b2091a 100644
--- a/app/templates/components/plot-table.hbs
+++ b/app/templates/components/plot-table.hbs
@@ -1,8 +1,16 @@
-
- Name
- Value
-
-
- Signal X
- 1.234
-
+{{#if editing}}
+ {{input value=plot.title placeholder='Enter title'}}
+{{else}}
+ {{plot.title}}
+{{/if}}
+
+
+
+ Name
+ Value
+
+
+ Signal X
+ 1.234
+
+
diff --git a/app/templates/visualization/edit.hbs b/app/templates/visualization/edit.hbs
index 2a10125..d23a362 100644
--- a/app/templates/visualization/edit.hbs
+++ b/app/templates/visualization/edit.hbs
@@ -18,7 +18,7 @@
{{#draggable-dropzone dropped='addPlot'}}
{{#each model.plots as |plot|}}
- {{#plot-container plot=plot}}{{/plot-container}}
+ {{#plot-container plot=plot editing=true}}{{/plot-container}}
{{/each}}
{{/draggable-dropzone}}
diff --git a/tests/unit/routes/404-test.js b/tests/unit/routes/404-test.js
new file mode 100644
index 0000000..260a5bc
--- /dev/null
+++ b/tests/unit/routes/404-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:404', 'Unit | Route | 404', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/todo.md b/todo.md
new file mode 100644
index 0000000..a4fc8ca
--- /dev/null
+++ b/todo.md
@@ -0,0 +1,8 @@
+# To-Do
+ - Logout route
+ - Change password
+ - Create/register user
+ - User management
+ - Rename preferences into account
+ - ! Don't save user password
+ - ! Fix user logged-in on invalidate account (after account was deleted)
From 6b8223df430d5bccca65e020a1dd0cf6e00de0ab Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Tue, 5 Jul 2016 11:50:31 +0200
Subject: [PATCH 009/556] Fix user login/logout
Add logout route as buffer between logged-in state and login form
Fix setting current user in service
Fix message on invalid credentials in login form
Don't save the user password
---
app/models/user.js | 1 -
app/router.js | 1 +
app/routes/application.js | 11 ++++-------
app/routes/logout.js | 8 ++++++++
app/services/session-user.js | 11 ++++++++---
app/templates/application.hbs | 2 +-
app/templates/login.hbs | 2 +-
app/templates/logout.hbs | 1 +
tests/unit/routes/logout-test.js | 11 +++++++++++
todo.md | 3 ---
10 files changed, 35 insertions(+), 16 deletions(-)
create mode 100644 app/routes/logout.js
create mode 100644 app/templates/logout.hbs
create mode 100644 tests/unit/routes/logout-test.js
diff --git a/app/models/user.js b/app/models/user.js
index bc61b02..d343d10 100644
--- a/app/models/user.js
+++ b/app/models/user.js
@@ -4,7 +4,6 @@ import { hasMany } from 'ember-data/relationships';
export default Model.extend({
username: attr('string'),
- password: attr('string'),
adminLevel: attr('number'),
projects: hasMany('project', { async: true }),
mail: attr('string')
diff --git a/app/router.js b/app/router.js
index c8d5437..8f2875d 100644
--- a/app/router.js
+++ b/app/router.js
@@ -28,6 +28,7 @@ Router.map(function() {
});
this.route('404', { path: '/*path' });
+ this.route('logout');
});
export default Router;
diff --git a/app/routes/application.js b/app/routes/application.js
index 49d79a7..0596a73 100644
--- a/app/routes/application.js
+++ b/app/routes/application.js
@@ -13,16 +13,13 @@ export default Ember.Route.extend(ApplicationRouteMixin, {
sessionAuthenticated() {
this._loadCurrentUser().then(() => {
this.transitionTo('/');
- }).catch(() => this.get('session').invalidate());
+ }).catch(function(/* reason */) {
+ //console.log(reason);
+ this.get('session').invalidate();
+ });
},
_loadCurrentUser() {
return this.get('sessionUser').loadCurrentUser();
- },
-
- actions: {
- invalidateSession() {
- this.get('session').invalidate();
- }
}
});
diff --git a/app/routes/logout.js b/app/routes/logout.js
new file mode 100644
index 0000000..52daa5f
--- /dev/null
+++ b/app/routes/logout.js
@@ -0,0 +1,8 @@
+import Ember from 'ember';
+import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+
+export default Ember.Route.extend(AuthenticatedRouteMixin, {
+ beforeModel() {
+ this.get('session').invalidate();
+ }
+});
diff --git a/app/services/session-user.js b/app/services/session-user.js
index 86d4cd7..5f18491 100644
--- a/app/services/session-user.js
+++ b/app/services/session-user.js
@@ -10,13 +10,18 @@ export default Ember.Service.extend({
store: service(),
loadCurrentUser() {
+ var _this = this;
+
return new RSVP.Promise((resolve, reject) => {
const token = this.get('session.data.authenticated.token');
if (!Ember.isEmpty(token)) {
- return this.get('store').findRecord('user', 'me').then((user) => {
- this.set('user', user);
+ return this.get('store').findRecord('user', 'me').then(function(user) {
+ _this.set('user', user);
resolve();
- }, reject);
+ }, function() {
+ _this.get('session').invalidate();
+ reject();
+ });
} else {
resolve();
}
diff --git a/app/templates/application.hbs b/app/templates/application.hbs
index deb95e2..4621e6e 100644
--- a/app/templates/application.hbs
+++ b/app/templates/application.hbs
@@ -10,7 +10,7 @@
{{#link-to 'index'}}Home{{/link-to}}
{{#link-to 'projects'}}Projects{{/link-to}}
{{#link-to 'user.edit'}}Preferences{{/link-to}}
- Logout
+ {{#link-to 'logout'}}Logout{{/link-to}}
diff --git a/app/templates/login.hbs b/app/templates/login.hbs
index 498b585..734af5e 100644
--- a/app/templates/login.hbs
+++ b/app/templates/login.hbs
@@ -13,7 +13,7 @@
Login
{{#if errorMessage}}
- {{errorMessage.message}}
+ {{errorMessage}}
{{/if}}
diff --git a/app/templates/logout.hbs b/app/templates/logout.hbs
new file mode 100644
index 0000000..c24cd68
--- /dev/null
+++ b/app/templates/logout.hbs
@@ -0,0 +1 @@
+{{outlet}}
diff --git a/tests/unit/routes/logout-test.js b/tests/unit/routes/logout-test.js
new file mode 100644
index 0000000..64613a0
--- /dev/null
+++ b/tests/unit/routes/logout-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:logout', 'Unit | Route | logout', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/todo.md b/todo.md
index a4fc8ca..b83c6c3 100644
--- a/todo.md
+++ b/todo.md
@@ -1,8 +1,5 @@
# To-Do
- - Logout route
- Change password
- Create/register user
- User management
- Rename preferences into account
- - ! Don't save user password
- - ! Fix user logged-in on invalidate account (after account was deleted)
From ddd2680d0dc147017166de688d49eba8a7bb22b2 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Mon, 11 Jul 2016 22:03:47 +0200
Subject: [PATCH 010/556] Add user management. Move relationship building to
server side
Admins can create/edit and delete users (with all their projects etc.)
Deleting a user/project/visualization automatically deletes all its belonging
data (e.g. deleting a visualization deletes all plots).
When creating and deleting objects the relationship is (mostly) handled server
side. Only the first required relationship (e.g. when creating a new project,
the project's owner is set client-side, the rest is matched on the server).
---
app/controllers/me.js | 16 ++++++++++++
app/controllers/project/delete.js | 28 ++-------------------
app/controllers/project/index.js | 7 ++----
app/controllers/project/new.js | 13 +++-------
app/controllers/user/delete.js | 19 ++++++++++++++
app/controllers/user/edit.js | 12 +++++++--
app/controllers/user/index.js | 17 +++++++++++++
app/controllers/user/new.js | 21 ++++++++++++++++
app/controllers/visualization/delete.js | 19 ++------------
app/models/user.js | 1 +
app/router.js | 12 ++++++---
app/routes/me.js | 9 +++++++
app/routes/user/delete.js | 8 ++++++
app/routes/user/edit.js | 8 ++----
app/routes/user/index.js | 8 ++++++
app/routes/user/new.js | 5 ++++
app/templates/application.hbs | 2 +-
app/templates/me.hbs | 20 +++++++++++++++
app/templates/user/delete.hbs | 10 ++++++++
app/templates/user/edit.hbs | 8 +++---
app/templates/user/index.hbs | 11 ++++++++
app/templates/user/new.hbs | 21 ++++++++++++++++
package.json | 4 +--
tests/unit/controllers/users/delete-test.js | 12 +++++++++
tests/unit/controllers/users/edit-test.js | 12 +++++++++
tests/unit/controllers/users/index-test.js | 12 +++++++++
tests/unit/controllers/users/new-test.js | 12 +++++++++
tests/unit/routes/me-test.js | 11 ++++++++
tests/unit/routes/user/delete-test.js | 11 ++++++++
tests/unit/routes/user/index-test.js | 11 ++++++++
tests/unit/routes/user/new-test.js | 11 ++++++++
todo.md | 2 +-
32 files changed, 295 insertions(+), 78 deletions(-)
create mode 100644 app/controllers/me.js
create mode 100644 app/controllers/user/delete.js
create mode 100644 app/controllers/user/index.js
create mode 100644 app/controllers/user/new.js
create mode 100644 app/routes/me.js
create mode 100644 app/routes/user/delete.js
create mode 100644 app/routes/user/index.js
create mode 100644 app/routes/user/new.js
create mode 100644 app/templates/me.hbs
create mode 100644 app/templates/user/delete.hbs
create mode 100644 app/templates/user/index.hbs
create mode 100644 app/templates/user/new.hbs
create mode 100644 tests/unit/controllers/users/delete-test.js
create mode 100644 tests/unit/controllers/users/edit-test.js
create mode 100644 tests/unit/controllers/users/index-test.js
create mode 100644 tests/unit/controllers/users/new-test.js
create mode 100644 tests/unit/routes/me-test.js
create mode 100644 tests/unit/routes/user/delete-test.js
create mode 100644 tests/unit/routes/user/index-test.js
create mode 100644 tests/unit/routes/user/new-test.js
diff --git a/app/controllers/me.js b/app/controllers/me.js
new file mode 100644
index 0000000..eac3232
--- /dev/null
+++ b/app/controllers/me.js
@@ -0,0 +1,16 @@
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ isAdmin: function() {
+ var level = this.get('model.adminLevel');
+ return level >= 1;
+ }.property('model'),
+
+ actions: {
+ changeUser() {
+ // save the changes
+ var user = this.get('model');
+ user.save();
+ }
+ }
+});
diff --git a/app/controllers/project/delete.js b/app/controllers/project/delete.js
index dbc5cc7..212648b 100644
--- a/app/controllers/project/delete.js
+++ b/app/controllers/project/delete.js
@@ -11,35 +11,11 @@ export default Ember.Controller.extend({
},
confirmDelete() {
- // get current user object
- var userId = this.get('sessionUser.user.id');
- var user = this.store.peekRecord('user', userId);
-
- // get the project
+ // delete the project
var project = this.get('model');
- let projectId = project.get('id');
-
- // delete the project and remove from user projects
- var visualizations = project.get('visualizations');
- visualizations.forEach(function(visualization) {
- // destroy all plots
- var plots = visualization.get('plots');
- plots.forEach(function(plot) {
- plot.destroyRecord();
- });
-
- visualization.destroyRecord();
- });
-
project.destroyRecord();
- // save the changes to project
- var controller = this;
-
- user.get('projects').removeObject(projectId);
- user.save().then(function() {
- controller.transitionToRoute('/projects');
- });
+ this.transitionToRoute('/projects');
}
}
});
diff --git a/app/controllers/project/index.js b/app/controllers/project/index.js
index eb33367..e949d77 100644
--- a/app/controllers/project/index.js
+++ b/app/controllers/project/index.js
@@ -10,13 +10,10 @@ export default Ember.Controller.extend({
// create the visualization
var visualization = this.store.createRecord('visualization', { name: 'Visualization', project: projectId });
- // the visualization must be added to the project before the project is saved, otherwise ember will set the projectId to null!
+ // this change will not be saved, but it is nessecary otherwise ember will omit the project's id in the post request
project.get('visualizations').pushObject(visualization);
- // save the visualization and project
- visualization.save().then(function() {
- project.save();
- });
+ visualization.save();
}
}
});
diff --git a/app/controllers/project/new.js b/app/controllers/project/new.js
index 1834a47..c786f7e 100644
--- a/app/controllers/project/new.js
+++ b/app/controllers/project/new.js
@@ -5,9 +5,8 @@ export default Ember.Controller.extend({
actions: {
newProject() {
- // get current user object
- var userId = this.get('sessionUser.user.id');
- var user = this.store.peekRecord('user', userId);
+ // get current user
+ var user = this.get('sessionUser.user');
// create new project from properties
var properties = this.getProperties('name');
@@ -16,14 +15,8 @@ export default Ember.Controller.extend({
var project = this.store.createRecord('project', properties);
var controller = this;
- // save the project and user
project.save().then(function() {
- // add the project to the user
- user.get('projects').pushObject(project);
-
- user.save().then(function() {
- controller.transitionToRoute('/projects');
- });
+ controller.transitionToRoute('/projects');
});
},
diff --git a/app/controllers/user/delete.js b/app/controllers/user/delete.js
new file mode 100644
index 0000000..ef1e8a0
--- /dev/null
+++ b/app/controllers/user/delete.js
@@ -0,0 +1,19 @@
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ sessionUser: Ember.inject.service('session-user'),
+
+ actions: {
+ cancelDelete() {
+ this.transitionToRoute('/user/');
+ },
+
+ confirmDelete() {
+ // delete all projects
+ var user = this.get('model');
+ user.destroyRecord();
+
+ this.transitionToRoute('/user/');
+ }
+ }
+});
diff --git a/app/controllers/user/edit.js b/app/controllers/user/edit.js
index d66f684..e47d437 100644
--- a/app/controllers/user/edit.js
+++ b/app/controllers/user/edit.js
@@ -2,10 +2,18 @@ import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
- changeUser() {
+ saveEdit() {
// save the changes
var user = this.get('model');
- user.save();
+ var controller = this;
+
+ user.save().then(function() {
+ controller.transitionToRoute('/user/');
+ });
+ },
+
+ cancelEdit() {
+ this.transitionToRoute('/user/');
}
}
});
diff --git a/app/controllers/user/index.js b/app/controllers/user/index.js
new file mode 100644
index 0000000..0b0c945
--- /dev/null
+++ b/app/controllers/user/index.js
@@ -0,0 +1,17 @@
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ users: function() {
+ var filteredUsers = this.get('model');
+ filteredUsers.forEach(function(user) {
+ // catch undefined user
+ if (user) {
+ if (user.get('id') === 'me') {
+ filteredUsers.removeObject(user);
+ }
+ }
+ });
+
+ return filteredUsers;
+ }.property('model.@each')
+});
diff --git a/app/controllers/user/new.js b/app/controllers/user/new.js
new file mode 100644
index 0000000..3da5896
--- /dev/null
+++ b/app/controllers/user/new.js
@@ -0,0 +1,21 @@
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ actions: {
+ newUser() {
+ // create new user from properties
+ var properties = this.getProperties('username', 'password');
+
+ var user = this.store.createRecord('user', properties);
+ var controller = this;
+
+ user.save().then(function() {
+ controller.transitionToRoute('/user');
+ });
+ },
+
+ cancelNewUser() {
+ this.transitionToRoute('/user');
+ }
+ }
+});
diff --git a/app/controllers/visualization/delete.js b/app/controllers/visualization/delete.js
index 37c2c9b..14db97b 100644
--- a/app/controllers/visualization/delete.js
+++ b/app/controllers/visualization/delete.js
@@ -10,27 +10,12 @@ export default Ember.Controller.extend({
confirmDelete() {
// get the objects
- var visualization = this.get('model');
- let visualizationId = this.get('model.id');
-
var projectId = this.get('model.project.id');
- var project = this.store.peekRecord('project', projectId);
-
- // destroy all plots
- var plots = visualization.get('plots');
- plots.forEach(function(plot) {
- plot.destroyRecord();
- });
+ var visualization = this.get('model');
visualization.destroyRecord();
- // delete the visualization and remove from the project
- var controller = this;
-
- project.get('visualizations').removeObject(visualizationId);
- project.save().then(function() {
- controller.transitionToRoute('/project/' + projectId);
- });
+ this.transitionToRoute('/project/' + projectId);
}
}
});
diff --git a/app/models/user.js b/app/models/user.js
index d343d10..bc61b02 100644
--- a/app/models/user.js
+++ b/app/models/user.js
@@ -4,6 +4,7 @@ import { hasMany } from 'ember-data/relationships';
export default Model.extend({
username: attr('string'),
+ password: attr('string'),
adminLevel: attr('number'),
projects: hasMany('project', { async: true }),
mail: attr('string')
diff --git a/app/router.js b/app/router.js
index 8f2875d..03ad117 100644
--- a/app/router.js
+++ b/app/router.js
@@ -7,6 +7,7 @@ const Router = Ember.Router.extend({
Router.map(function() {
this.route('login');
+ this.route('logout');
this.route('projects');
this.route('project', function() {
@@ -16,9 +17,7 @@ Router.map(function() {
this.route('delete', { path: '/delete/:projectid' });
});
- this.route('user', function() {
- this.route('edit');
- });
+ this.route('me');
this.route('visualization', function() {
this.route('index', { path: '/:visualizationid' });
@@ -27,8 +26,13 @@ Router.map(function() {
this.route('delete', { path: '/delete/:visualizationid' });
});
+ this.route('user', function() {
+ this.route('edit', { path: '/edit/:userid' });
+ this.route('new');
+ this.route('delete', { path: '/delete/:userid' });
+ });
+
this.route('404', { path: '/*path' });
- this.route('logout');
});
export default Router;
diff --git a/app/routes/me.js b/app/routes/me.js
new file mode 100644
index 0000000..b8e23aa
--- /dev/null
+++ b/app/routes/me.js
@@ -0,0 +1,9 @@
+import Ember from 'ember';
+import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+
+export default Ember.Route.extend(AuthenticatedRouteMixin, {
+ model() {
+ // get session user
+ return this.store.findRecord('user', 'me');
+ }
+});
diff --git a/app/routes/user/delete.js b/app/routes/user/delete.js
new file mode 100644
index 0000000..7fa7c6a
--- /dev/null
+++ b/app/routes/user/delete.js
@@ -0,0 +1,8 @@
+import Ember from 'ember';
+import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+
+export default Ember.Route.extend(AuthenticatedRouteMixin, {
+ model(params) {
+ return this.store.findRecord('user', params.userid);
+ }
+});
diff --git a/app/routes/user/edit.js b/app/routes/user/edit.js
index 9def44d..7fa7c6a 100644
--- a/app/routes/user/edit.js
+++ b/app/routes/user/edit.js
@@ -2,11 +2,7 @@ import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin, {
- sessionUser: Ember.inject.service('session-user'),
-
- model() {
- // get session user
- var userId = this.get('sessionUser.user.id');
- return this.store.findRecord('user', userId);
+ model(params) {
+ return this.store.findRecord('user', params.userid);
}
});
diff --git a/app/routes/user/index.js b/app/routes/user/index.js
new file mode 100644
index 0000000..f4885a9
--- /dev/null
+++ b/app/routes/user/index.js
@@ -0,0 +1,8 @@
+import Ember from 'ember';
+import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+
+export default Ember.Route.extend(AuthenticatedRouteMixin, {
+ model() {
+ return this.store.findAll('user');
+ }
+});
diff --git a/app/routes/user/new.js b/app/routes/user/new.js
new file mode 100644
index 0000000..30e4e30
--- /dev/null
+++ b/app/routes/user/new.js
@@ -0,0 +1,5 @@
+import Ember from 'ember';
+import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+
+export default Ember.Route.extend(AuthenticatedRouteMixin, {
+});
diff --git a/app/templates/application.hbs b/app/templates/application.hbs
index 4621e6e..457586e 100644
--- a/app/templates/application.hbs
+++ b/app/templates/application.hbs
@@ -9,7 +9,7 @@
{{#link-to 'index'}}Home{{/link-to}}
{{#link-to 'projects'}}Projects{{/link-to}}
- {{#link-to 'user.edit'}}Preferences{{/link-to}}
+ {{#link-to 'me'}}Account{{/link-to}}
{{#link-to 'logout'}}Logout{{/link-to}}
diff --git a/app/templates/me.hbs b/app/templates/me.hbs
new file mode 100644
index 0000000..eeb3fb9
--- /dev/null
+++ b/app/templates/me.hbs
@@ -0,0 +1,20 @@
+Preferences
+
+
+
+{{#if isAdmin}}
+
+ {{#link-to 'user'}}Users{{/link-to}}
+
+{{/if}}
diff --git a/app/templates/user/delete.hbs b/app/templates/user/delete.hbs
new file mode 100644
index 0000000..b8173d5
--- /dev/null
+++ b/app/templates/user/delete.hbs
@@ -0,0 +1,10 @@
+Delete User
+
+
+ Are you sure you want to delete the user "{{model.username}}"?
+
+ This will also delete all projects belonging to this user!
+
+
+Cancel
+Delete
diff --git a/app/templates/user/edit.hbs b/app/templates/user/edit.hbs
index 55622f9..b44372f 100644
--- a/app/templates/user/edit.hbs
+++ b/app/templates/user/edit.hbs
@@ -1,14 +1,14 @@
-Preferences
+Edit
-
diff --git a/app/templates/user/index.hbs b/app/templates/user/index.hbs
new file mode 100644
index 0000000..9a7c1cb
--- /dev/null
+++ b/app/templates/user/index.hbs
@@ -0,0 +1,11 @@
+Users
+
+{{#link-to 'user.new'}}New user{{/link-to}}
+
+
+
+ {{#each users as |user|}}
+ {{#link-to 'user.edit' user.id}}{{user.username}}{{/link-to}} {{#link-to 'user.delete' user.id}}X{{/link-to}}
+ {{/each}}
+
+
diff --git a/app/templates/user/new.hbs b/app/templates/user/new.hbs
new file mode 100644
index 0000000..0e8598b
--- /dev/null
+++ b/app/templates/user/new.hbs
@@ -0,0 +1,21 @@
+New user
+
+
diff --git a/package.json b/package.json
index 7c3e27c..5e45d0c 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
"ember-export-application-global": "^1.0.5",
"ember-load-initializers": "^0.5.1",
"ember-resolver": "^2.0.3",
- "loader.js": "^4.0.1",
- "ember-simple-auth": "^1.1.0"
+ "ember-simple-auth": "^1.1.0",
+ "loader.js": "^4.0.1"
}
}
diff --git a/tests/unit/controllers/users/delete-test.js b/tests/unit/controllers/users/delete-test.js
new file mode 100644
index 0000000..68f802f
--- /dev/null
+++ b/tests/unit/controllers/users/delete-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:users/delete', 'Unit | Controller | users/delete', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/controllers/users/edit-test.js b/tests/unit/controllers/users/edit-test.js
new file mode 100644
index 0000000..debcf46
--- /dev/null
+++ b/tests/unit/controllers/users/edit-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:users/edit', 'Unit | Controller | users/edit', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/controllers/users/index-test.js b/tests/unit/controllers/users/index-test.js
new file mode 100644
index 0000000..2395bc6
--- /dev/null
+++ b/tests/unit/controllers/users/index-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:users/index', 'Unit | Controller | users/index', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/controllers/users/new-test.js b/tests/unit/controllers/users/new-test.js
new file mode 100644
index 0000000..113f11e
--- /dev/null
+++ b/tests/unit/controllers/users/new-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:users/new', 'Unit | Controller | users/new', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/routes/me-test.js b/tests/unit/routes/me-test.js
new file mode 100644
index 0000000..9719ac5
--- /dev/null
+++ b/tests/unit/routes/me-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:me', 'Unit | Route | me', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/routes/user/delete-test.js b/tests/unit/routes/user/delete-test.js
new file mode 100644
index 0000000..4be7323
--- /dev/null
+++ b/tests/unit/routes/user/delete-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:user/delete', 'Unit | Route | user/delete', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/routes/user/index-test.js b/tests/unit/routes/user/index-test.js
new file mode 100644
index 0000000..fe27105
--- /dev/null
+++ b/tests/unit/routes/user/index-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:user/index', 'Unit | Route | user/index', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/routes/user/new-test.js b/tests/unit/routes/user/new-test.js
new file mode 100644
index 0000000..5032fa8
--- /dev/null
+++ b/tests/unit/routes/user/new-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:user/new', 'Unit | Route | user/new', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/todo.md b/todo.md
index b83c6c3..020a1c8 100644
--- a/todo.md
+++ b/todo.md
@@ -2,4 +2,4 @@
- Change password
- Create/register user
- User management
- - Rename preferences into account
+ - Don't log out on unauthorized access (admin level lower than required)
From dbf95bc86259dafa4bff87e367d5223a7e90fec8 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Tue, 12 Jul 2016 00:03:20 +0200
Subject: [PATCH 011/556] Only save changes on project on save button
---
app/controllers/project/edit.js | 9 ++++++++-
app/templates/project/edit.hbs | 2 +-
todo.md | 2 --
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/app/controllers/project/edit.js b/app/controllers/project/edit.js
index 1cd1566..dc98e3f 100644
--- a/app/controllers/project/edit.js
+++ b/app/controllers/project/edit.js
@@ -1,10 +1,17 @@
import Ember from 'ember';
export default Ember.Controller.extend({
+ name: function() {
+ return this.get('model.name');
+ }.property('model.name'),
+
actions: {
saveEdit() {
- // save the changes
+ // apply the changes
var project = this.get('model');
+ project.set('name', this.get('name'));
+
+ // save the changes
let projectId = project.get('id');
var controller = this;
diff --git a/app/templates/project/edit.hbs b/app/templates/project/edit.hbs
index 064d830..1c42a97 100644
--- a/app/templates/project/edit.hbs
+++ b/app/templates/project/edit.hbs
@@ -3,7 +3,7 @@
diff --git a/app/templates/projects.hbs b/app/templates/projects.hbs
index 70aae57..c99113a 100644
--- a/app/templates/projects.hbs
+++ b/app/templates/projects.hbs
@@ -1,9 +1,27 @@
Projects
-
- {{#each model as |project|}}
- {{#link-to "project.index" project.id}}{{project.name}}{{/link-to}}
- {{/each}}
-
+
+
+
+ Name
+
+
+ {{#each model as |project|}}
+
+
+ {{#link-to "project.index" project.id}}{{project.name}}{{/link-to}}
+
+
+
+ {{#link-to "project.edit" project.id}}Edit{{/link-to}}
+ {{#link-to "project.delete" project.id}}Delete{{/link-to}}
+
+
+
+ {{/each}}
+
+
-{{#link-to "project.new"}}New project{{/link-to}}
+
+ {{#link-to "project.new"}}New project{{/link-to}}
+
diff --git a/app/templates/simulation-model/new.hbs b/app/templates/simulation-model/new.hbs
index 8056de7..7cb6197 100644
--- a/app/templates/simulation-model/new.hbs
+++ b/app/templates/simulation-model/new.hbs
@@ -1,11 +1,28 @@
New model
-
-
- Name
- {{input id='name' placeholder='Enter model name' value=name}}
-
-
- Cancel
- Create
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter model name' value=name}}
+
+
+
+
+ Simulator
+
+
+ {{input id='simulator' value=simulator type='number' min=1 max=255 step=1}}
+
+
+
+
+ Cancel
+ Create
+
+
+
diff --git a/app/templates/simulation/delete.hbs b/app/templates/simulation/delete.hbs
new file mode 100644
index 0000000..c24cd68
--- /dev/null
+++ b/app/templates/simulation/delete.hbs
@@ -0,0 +1 @@
+{{outlet}}
diff --git a/app/templates/simulation/edit.hbs b/app/templates/simulation/edit.hbs
new file mode 100644
index 0000000..c24cd68
--- /dev/null
+++ b/app/templates/simulation/edit.hbs
@@ -0,0 +1 @@
+{{outlet}}
diff --git a/app/templates/simulation/index.hbs b/app/templates/simulation/index.hbs
new file mode 100644
index 0000000..738ae2c
--- /dev/null
+++ b/app/templates/simulation/index.hbs
@@ -0,0 +1,31 @@
+{{model.name}}
+
+
+
+
+ Name
+ Simulator
+
+
+ {{#each model.models as |simulationModel|}}
+
+
+ {{#link-to "simulation-model.index" simulationModel.id}}{{simulationModel.name}}{{/link-to}}
+
+
+ {{simulationModel.simulator}}
+
+
+
+ {{#link-to "simulation-model.edit" simulationModel.id}}Edit{{/link-to}}
+ {{#link-to "simulation-model.delete" simulationModel.id}}Delete{{/link-to}}
+
+
+
+ {{/each}}
+
+
+
+
+ {{#link-to "simulation-model.new" model.id}}New model{{/link-to}}
+
diff --git a/app/templates/simulation/new.hbs b/app/templates/simulation/new.hbs
new file mode 100644
index 0000000..211149f
--- /dev/null
+++ b/app/templates/simulation/new.hbs
@@ -0,0 +1,20 @@
+New simulation
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter simulation name' value=name}}
+
+
+
+
+ Cancel
+ Create
+
+
+
+
diff --git a/app/templates/simulations.hbs b/app/templates/simulations.hbs
new file mode 100644
index 0000000..cac2d48
--- /dev/null
+++ b/app/templates/simulations.hbs
@@ -0,0 +1,27 @@
+Simulations
+
+
+
+
+ Name
+
+
+ {{#each model as |simulation|}}
+
+
+ {{#link-to "simulation.index" simulation.id}}{{simulation.name}}{{/link-to}}
+
+
+
+ {{#link-to "simulation.edit" simulation.id}}Edit{{/link-to}}
+ {{#link-to "simulation.delete" simulation.id}}Delete{{/link-to}}
+
+
+
+ {{/each}}
+
+
+
+
+ {{#link-to "simulation.new"}}New simulation{{/link-to}}
+
diff --git a/tests/unit/controllers/simulation/delete-test.js b/tests/unit/controllers/simulation/delete-test.js
new file mode 100644
index 0000000..97437e5
--- /dev/null
+++ b/tests/unit/controllers/simulation/delete-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:simulation/delete', 'Unit | Controller | simulation/delete', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/controllers/simulation/edit-test.js b/tests/unit/controllers/simulation/edit-test.js
new file mode 100644
index 0000000..814e36a
--- /dev/null
+++ b/tests/unit/controllers/simulation/edit-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:simulation/edit', 'Unit | Controller | simulation/edit', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/controllers/simulation/index-test.js b/tests/unit/controllers/simulation/index-test.js
new file mode 100644
index 0000000..c060398
--- /dev/null
+++ b/tests/unit/controllers/simulation/index-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:simulation/index', 'Unit | Controller | simulation/index', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/controllers/simulation/new-test.js b/tests/unit/controllers/simulation/new-test.js
new file mode 100644
index 0000000..1f75ab8
--- /dev/null
+++ b/tests/unit/controllers/simulation/new-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:simulation/new', 'Unit | Controller | simulation/new', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/models/simulation-test.js b/tests/unit/models/simulation-test.js
new file mode 100644
index 0000000..fa6a585
--- /dev/null
+++ b/tests/unit/models/simulation-test.js
@@ -0,0 +1,12 @@
+import { moduleForModel, test } from 'ember-qunit';
+
+moduleForModel('simulation', 'Unit | Model | simulation', {
+ // Specify the other units that are required for this test.
+ needs: []
+});
+
+test('it exists', function(assert) {
+ let model = this.subject();
+ // let store = this.store();
+ assert.ok(!!model);
+});
diff --git a/tests/unit/routes/simulation/delete-test.js b/tests/unit/routes/simulation/delete-test.js
new file mode 100644
index 0000000..582dca0
--- /dev/null
+++ b/tests/unit/routes/simulation/delete-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:simulation/delete', 'Unit | Route | simulation/delete', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/routes/simulation/edit-test.js b/tests/unit/routes/simulation/edit-test.js
new file mode 100644
index 0000000..9cb2ae5
--- /dev/null
+++ b/tests/unit/routes/simulation/edit-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:simulation/edit', 'Unit | Route | simulation/edit', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/routes/simulation/index-test.js b/tests/unit/routes/simulation/index-test.js
new file mode 100644
index 0000000..ba31a78
--- /dev/null
+++ b/tests/unit/routes/simulation/index-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:simulation/index', 'Unit | Route | simulation/index', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/routes/simulation/new-test.js b/tests/unit/routes/simulation/new-test.js
new file mode 100644
index 0000000..340a6bd
--- /dev/null
+++ b/tests/unit/routes/simulation/new-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:simulation/new', 'Unit | Route | simulation/new', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/routes/simulations-test.js b/tests/unit/routes/simulations-test.js
new file mode 100644
index 0000000..b72a094
--- /dev/null
+++ b/tests/unit/routes/simulations-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:simulations', 'Unit | Route | simulations', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/serializers/simulation-test.js b/tests/unit/serializers/simulation-test.js
new file mode 100644
index 0000000..40a61cd
--- /dev/null
+++ b/tests/unit/serializers/simulation-test.js
@@ -0,0 +1,15 @@
+import { moduleForModel, test } from 'ember-qunit';
+
+moduleForModel('simulation', 'Unit | Serializer | simulation', {
+ // Specify the other units that are required for this test.
+ needs: ['serializer:simulation']
+});
+
+// Replace this with your real tests.
+test('it serializes records', function(assert) {
+ let record = this.subject();
+
+ let serializedRecord = record.serialize();
+
+ assert.ok(serializedRecord);
+});
From b9d40a861e314ee0104a4af73fa0472886556169 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Tue, 26 Jul 2016 20:40:33 +0200
Subject: [PATCH 022/556] Add running-simulation service
Simulation-model index now shows correct simulator data if the selected
simulation is running.
running-simulation service can be used to get the running simulation anywhere
in the app.
---
app/controllers/simulation-model/index.js | 43 ++++++++++++++++
app/mixins/websocket-live-stream-mixin.js | 51 +++++++++++++++----
app/services/running-simulation.js | 41 +++++++++++++++
app/templates/simulation-model/index.hbs | 19 +++++--
app/templates/simulations.hbs | 4 ++
.../unit/services/running-simulation-test.js | 12 +++++
6 files changed, 155 insertions(+), 15 deletions(-)
create mode 100644 app/services/running-simulation.js
create mode 100644 tests/unit/services/running-simulation-test.js
diff --git a/app/controllers/simulation-model/index.js b/app/controllers/simulation-model/index.js
index 55ff9aa..74b0a77 100644
--- a/app/controllers/simulation-model/index.js
+++ b/app/controllers/simulation-model/index.js
@@ -1,4 +1,47 @@
+/**
+ * File: index.js
+ * Author: Markus Grigull
+ * Date: 20.07.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
import Ember from 'ember';
export default Ember.Controller.extend({
+ values: function() {
+ return this.get('simulationData.values');
+ }.property('simulationData.values.@each'),
+
+ _getData: function() {
+ if (this.get('model.simulation.running') == true) {
+ var simulator = this.get('model.simulator');
+ if (simulator == null) {
+ return;
+ }
+
+ var data = this.store.peekRecord('simulation-data', simulator);
+ this.set('simulationData', data);
+
+ // load model again if simulation data is null
+ // this prevents from simulation data not being loaded when the controller
+ // is loaded before the websocket connects
+ if (data === null) {
+ Ember.run.later(this, function() {
+ // trigger _getData
+ this.notifyPropertyChange('model');
+ }, 1000);
+ }
+ } else {
+ // clear simulation data
+ this.set('simulationData', null);
+
+ // check again if simulation is running now
+ Ember.run.later(this, function() {
+ // trigger _getData
+ this.notifyPropertyChange('model');
+ }, 1000);
+ }
+ }.observes('model').on('init')
});
diff --git a/app/mixins/websocket-live-stream-mixin.js b/app/mixins/websocket-live-stream-mixin.js
index eaaf392..bbf6ecf 100644
--- a/app/mixins/websocket-live-stream-mixin.js
+++ b/app/mixins/websocket-live-stream-mixin.js
@@ -1,25 +1,56 @@
+/**
+ * File: websocket-live-stream-mixin.js
+ * Author: Markus Grigull
+ * Date: 21.07.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
import Ember from 'ember';
import ENV from '../config/environment';
+const { service } = Ember.inject;
+
export default Ember.Mixin.create({
host: 'ws://' + ENV.APP.LIVE_HOST,
namespace: '',
+ runningSimulation: service('running-simulation'),
+
+ socket: null,
init() {
this._super(...arguments);
- // create socket
- var socket = new WebSocket(this.host + this.namespace);
- socket.binaryType = 'arraybuffer';
-
- // register event callbacks
- var self = this;
- socket.onopen = function(event) { self.onopen.apply(self, [event]); };
- socket.onclose = function(event) { self.onclose.apply(self, [event]); };
- socket.onmessage = function(event) { self.onmessage.apply(self, [event]); };
- socket.onerror = function(event) { self.onerror.apply(self, [event]); };
+ // start simulation service
+ this.get('runningSimulation').loadRunningSimulation();
},
+ _runningSimulationChanged: function() {
+ // called each time running simulation did change
+ var simulation = this.get('runningSimulation.simulation');
+ if (simulation !== null) {
+ if (this.socket === null) {
+ // create new socket connection
+ this.socket = new WebSocket(this.host + this.namespace);
+ this.socket.binaryType = 'arraybuffer';
+
+ // register callbacks
+ var self = this;
+ this.socket.onopen = function(event) { self.onopen.apply(self, [event]); };
+ this.socket.onclose = function(event) { self.onclose.apply(self, [event]); };
+ this.socket.onmessage = function(event) { self.onmessage.apply(self, [event]); };
+ this.socket.onerror = function(event) { self.onerror.apply(self, [event]); };
+ }
+ } else {
+ // stop stream if still opened
+ if (this.socket !== null) {
+ this.socket.close();
+ this.socket = null;
+ }
+ }
+ }.observes('runningSimulation.simulation'),
+
onopen(event) {
Ember.debug('websocket opened');
},
diff --git a/app/services/running-simulation.js b/app/services/running-simulation.js
new file mode 100644
index 0000000..ca8ff7b
--- /dev/null
+++ b/app/services/running-simulation.js
@@ -0,0 +1,41 @@
+/**
+ * File: running-simulation.js
+ * Author: Markus Grigull
+ * Date: 26.07.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import Ember from 'ember';
+
+const {
+ inject: { service }
+} = Ember;
+
+export default Ember.Service.extend({
+ session: service('session'),
+ store: service(),
+
+ loadRunningSimulation: function() {
+ var self = this;
+
+ // check every second for running simulation
+ setInterval(function() {
+ // check if running simulation did changed
+ self.get('store').findAll('simulation').then(function(simulations) {
+ var newSimulation = null;
+
+ simulations.forEach(function(simulation) {
+ if (simulation.get('running') == true) {
+ newSimulation = simulation;
+ }
+ });
+
+ if (newSimulation != self.get('simulation')) {
+ self.set('simulation', newSimulation);
+ }
+ });
+ }, 1000);
+ }
+});
diff --git a/app/templates/simulation-model/index.hbs b/app/templates/simulation-model/index.hbs
index 2c69e6f..d993484 100644
--- a/app/templates/simulation-model/index.hbs
+++ b/app/templates/simulation-model/index.hbs
@@ -1,9 +1,18 @@
{{model.name}}
- Running: {{#if model.running}}
- true
- {{else}}
- false
- {{/if}}
+ Running: {{model.simulation.running}}
+
+
+ Simulator: {{model.simulator}}
+
+
+
+ Data:
+
+
+{{#each values as |value|}}
+ {{value}}
+
+{{/each}}
diff --git a/app/templates/simulations.hbs b/app/templates/simulations.hbs
index cac2d48..40fa4a6 100644
--- a/app/templates/simulations.hbs
+++ b/app/templates/simulations.hbs
@@ -4,6 +4,7 @@
Name
+ Running
{{#each model as |simulation|}}
@@ -11,6 +12,9 @@
{{#link-to "simulation.index" simulation.id}}{{simulation.name}}{{/link-to}}
+
+ {{simulation.running}}
+
{{#link-to "simulation.edit" simulation.id}}Edit{{/link-to}}
diff --git a/tests/unit/services/running-simulation-test.js b/tests/unit/services/running-simulation-test.js
new file mode 100644
index 0000000..f74cde8
--- /dev/null
+++ b/tests/unit/services/running-simulation-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('service:running-simulation', 'Unit | Service | running simulation', {
+ // Specify the other units that are required for this test.
+ // needs: ['service:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let service = this.subject();
+ assert.ok(service);
+});
From dc421c43057b350b99326125ff9e3d143facdb9f Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 27 Jul 2016 13:43:10 +0200
Subject: [PATCH 023/556] Add bootstrap popover to plots
---
app/components/plot-abstract.js | 55 ++++++++++++++++++++++-
app/components/plot-container.js | 7 ++-
app/controllers/simulation-model/index.js | 2 +-
app/mixins/websocket-live-stream-mixin.js | 4 +-
app/models/plot.js | 1 +
app/models/simulation-model.js | 2 +-
app/services/running-simulation.js | 4 +-
app/styles/app.css | 20 +++++++++
app/styles/plots.css | 12 +++++
app/styles/projects.css | 19 ++++++++
app/styles/simulations.css | 1 -
app/templates/components/plot-value.hbs | 30 +++++++++++++
app/templates/project/index.hbs | 39 ++++++++--------
bower.json | 6 ++-
ember-cli-build.js | 2 +
package.json | 3 +-
16 files changed, 178 insertions(+), 29 deletions(-)
diff --git a/app/components/plot-abstract.js b/app/components/plot-abstract.js
index 47f1dd7..f8a7b51 100644
--- a/app/components/plot-abstract.js
+++ b/app/components/plot-abstract.js
@@ -20,6 +20,8 @@ export default Ember.Component.extend(Resizable, Draggable, {
editing: false,
grid: false,
+ simulator: 0,
+
disabled_resize: false,
autoHide_resize: false,
grid_resize: [ 10, 10 ],
@@ -29,6 +31,39 @@ export default Ember.Component.extend(Resizable, Draggable, {
grid_drag: [ 10, 10 ],
scroll_drag: true,
+ _popoverDisplayed: false,
+
+ didInsertElement() {
+ this._super();
+
+ if (this.get('editing') === true) {
+ // create popover
+ var self = this;
+
+ this.$().popover({
+ html: true,
+ placement: 'auto right',
+ content: function () {
+ return self.$('.popover-content').html();
+ },
+ viewport: { selector: '.plots', padding: 10 }
+ });
+
+ // register popover events
+ this.$().on('show.bs.popover', function() {
+
+ });
+
+ this.$().on('shown.bs.popover', function() {
+ self._popoverDisplayed = true;
+ });
+
+ this.$().on('hide.bs.popover', function() {
+ self._popoverDisplayed = false;
+ });
+ }
+ },
+
style: function() {
return Ember.String.htmlSafe('width: ' + this.get('plot.width') + 'px; height: ' + this.get('plot.height') + 'px; left: ' + this.get('plot.x') + 'px; top: ' + this.get('plot.y') + 'px;');
}.property('plot'),
@@ -41,11 +76,23 @@ export default Ember.Component.extend(Resizable, Draggable, {
this.set('plot.height', height);
},
+ resize_resize(event, ui) {
+ if (this._popoverDisplayed === true) {
+ this.$().popover('show');
+ }
+ },
+
stop_drag(event, ui) {
this.set('plot.x', ui.position.left);
this.set('plot.y', ui.position.top);
},
+ drag_drag(event, ui) {
+ if (this._popoverDisplayed === true) {
+ this.$().popover('show');
+ }
+ },
+
_updateUI: function() {
if (this.get('editing') === true) {
this.set('disabled_resize', false);
@@ -64,5 +111,11 @@ export default Ember.Component.extend(Resizable, Draggable, {
this.set('grid_resize', false);
this.set('grid_drag', false);
}
- }.observes('editing', 'grid').on('init')
+ }.observes('editing', 'grid').on('init'),
+
+ actions: {
+ savePlot() {
+ this.$().popover('hide');
+ }
+ }
});
diff --git a/app/components/plot-container.js b/app/components/plot-container.js
index de61a77..9556975 100644
--- a/app/components/plot-container.js
+++ b/app/components/plot-container.js
@@ -19,7 +19,12 @@ export default Ember.Component.extend({
grid: true,
style: function() {
- return Ember.String.htmlSafe('height: ' + this._calculateHeight() + 'px;');
+ var height = this._calculateHeight();
+ if (this.get('editing') === true && height < 400) {
+ height = 400;
+ }
+
+ return Ember.String.htmlSafe('height: ' + height + 'px;');
}.property('plots.@each.height', 'plots.@each.y'),
_calculateHeight() {
diff --git a/app/controllers/simulation-model/index.js b/app/controllers/simulation-model/index.js
index 74b0a77..3481e21 100644
--- a/app/controllers/simulation-model/index.js
+++ b/app/controllers/simulation-model/index.js
@@ -15,7 +15,7 @@ export default Ember.Controller.extend({
}.property('simulationData.values.@each'),
_getData: function() {
- if (this.get('model.simulation.running') == true) {
+ if (this.get('model.simulation.running') === true) {
var simulator = this.get('model.simulator');
if (simulator == null) {
return;
diff --git a/app/mixins/websocket-live-stream-mixin.js b/app/mixins/websocket-live-stream-mixin.js
index bbf6ecf..c225d6a 100644
--- a/app/mixins/websocket-live-stream-mixin.js
+++ b/app/mixins/websocket-live-stream-mixin.js
@@ -51,7 +51,7 @@ export default Ember.Mixin.create({
}
}.observes('runningSimulation.simulation'),
- onopen(event) {
+ onopen(/*event*/) {
Ember.debug('websocket opened');
},
@@ -76,7 +76,7 @@ export default Ember.Mixin.create({
}
},
- onerror(event) {
+ onerror(/*event*/) {
Ember.debug('websocket error');
},
diff --git a/app/models/plot.js b/app/models/plot.js
index e7dd0ba..17ab769 100644
--- a/app/models/plot.js
+++ b/app/models/plot.js
@@ -14,6 +14,7 @@ import { belongsTo } from 'ember-data/relationships';
export default Model.extend({
name: attr('string'),
signal: attr('string'),
+ simulator: attr('number', { defaultValue: 1 }),
width: attr('number', { defaultValue: 100 }),
height: attr('number', { defaultValue: 100 }),
title: attr('string'),
diff --git a/app/models/simulation-model.js b/app/models/simulation-model.js
index 4a4b445..9493dd9 100644
--- a/app/models/simulation-model.js
+++ b/app/models/simulation-model.js
@@ -9,7 +9,7 @@
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
-import { belongsTo, hasMany } from 'ember-data/relationships';
+import { belongsTo/*, hasMany*/ } from 'ember-data/relationships';
export default Model.extend({
name: attr('string'),
diff --git a/app/services/running-simulation.js b/app/services/running-simulation.js
index ca8ff7b..40aa46b 100644
--- a/app/services/running-simulation.js
+++ b/app/services/running-simulation.js
@@ -27,12 +27,12 @@ export default Ember.Service.extend({
var newSimulation = null;
simulations.forEach(function(simulation) {
- if (simulation.get('running') == true) {
+ if (simulation.get('running') === true) {
newSimulation = simulation;
}
});
- if (newSimulation != self.get('simulation')) {
+ if (newSimulation !== self.get('simulation')) {
self.set('simulation', newSimulation);
}
});
diff --git a/app/styles/app.css b/app/styles/app.css
index 9aa9008..575e542 100644
--- a/app/styles/app.css
+++ b/app/styles/app.css
@@ -168,6 +168,8 @@ footer {
border: 0;
border-collapse: collapse;
+
+ background-color: #f6f6f6;
}
.table-full-width th, td {
@@ -232,3 +234,21 @@ footer {
.form-create-record button:hover {
background: #373;
}
+
+/**
+ *
+ */
+.popover {
+ z-index: 1010;
+
+ width: 120px;
+ height: 100px;
+}
+
+.arrow {
+ border-right-color: red !important;
+}
+
+.hidden {
+ visibility: hidden;
+}
diff --git a/app/styles/plots.css b/app/styles/plots.css
index 34ee417..a3807eb 100644
--- a/app/styles/plots.css
+++ b/app/styles/plots.css
@@ -42,6 +42,18 @@
}
+.plot-edit-container {
+ width: 200px !important;
+
+ background-color: #ddd;
+
+ border: 1px dotted black;
+}
+
+.plot-edit-form {
+
+}
+
/**
* Component: plot-table
*/
diff --git a/app/styles/projects.css b/app/styles/projects.css
index 5bc1e13..43f0f1b 100644
--- a/app/styles/projects.css
+++ b/app/styles/projects.css
@@ -25,3 +25,22 @@
.projects-new-container {
margin-top: 20px;
}
+
+/**
+ * Route: project.index
+ */
+.project-index-container {
+ margin-top: 20px;
+}
+
+.project-index-row-controls {
+ float: right;
+}
+
+.project-index-row-controls a {
+ margin:left: 10px;
+}
+
+.project-index-new-visualization {
+ margin-top: 20px;
+}
diff --git a/app/styles/simulations.css b/app/styles/simulations.css
index 9c6a94f..0580e36 100644
--- a/app/styles/simulations.css
+++ b/app/styles/simulations.css
@@ -29,7 +29,6 @@
/**
* Route: simulation/index
*/
-
.simulation-index-models-container {
margin-top: 20px;
}
diff --git a/app/templates/components/plot-value.hbs b/app/templates/components/plot-value.hbs
index af53c9c..74d6f2a 100644
--- a/app/templates/components/plot-value.hbs
+++ b/app/templates/components/plot-value.hbs
@@ -1 +1,31 @@
Value
+
+
+
+
+
+
+
+ Simulator
+
+
+ {{input id='simulator' type='number' value=plot.simulator min=1 max=255 width='60px'}}
+
+
+
+
+ Signal
+
+
+ {{input id='signal' value=plot.signal}}
+
+
+
+
+ Save
+
+
+
+
+
+
diff --git a/app/templates/project/index.hbs b/app/templates/project/index.hbs
index d35cd7f..93dcedb 100644
--- a/app/templates/project/index.hbs
+++ b/app/templates/project/index.hbs
@@ -1,24 +1,27 @@
{{model.name}}
-
-
-
-
Visualizations
-
-
diff --git a/app/templates/simulation-model/new.hbs b/app/templates/simulation-model/new.hbs
index 7cb6197..5fa523d 100644
--- a/app/templates/simulation-model/new.hbs
+++ b/app/templates/simulation-model/new.hbs
@@ -15,7 +15,11 @@
Simulator
- {{input id='simulator' value=simulator type='number' min=1 max=255 step=1}}
+
+ {{#each model.simulators as |simulator|}}
+ {{simulator.name}}
+ {{/each}}
+
diff --git a/app/templates/simulators.hbs b/app/templates/simulators.hbs
new file mode 100644
index 0000000..e860e7b
--- /dev/null
+++ b/app/templates/simulators.hbs
@@ -0,0 +1,143 @@
+Simulators
+
+
+
+
+ Name
+ ID
+ Running
+ Endpoint
+
+
+ {{#each model as |simulator|}}
+
+
+
+ {{simulator.name}}
+
+
+ {{simulator.simulatorid}}
+
+
+ {{simulator.running}}
+
+
+ {{simulator.endpoint}}
+
+
+
+
+
+ {{/each}}
+
+
+
+
+ New Simulator
+
+
+{{#if isShowingNewModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New simulator
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter simulator name' value=name}}
+
+
+
+
+ Simulator ID
+
+
+ {{input id='simulatorid' type='number' value=simulatorid min='1' max='255'}}
+
+
+
+
+ Endpoint
+
+
+ {{input id='endpoint' placeholder='Enter endpoint' value=endpoint}}
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingDeleteModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Delete simulator
+
+ Are you sure you want to delete the simulator {{simulator.name}} ?
+
+ Cancel
+ Delete
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingEditModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New simulator
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter simulator name' value=simulatorName}}
+
+
+
+
+ Simulator ID
+
+
+ {{input id='simulatorid' type='number' value=simulatorid min='1' max='255'}}
+
+
+
+
+ Endpoint
+
+
+ {{input id='endpoint' placeholder='Enter endpoint' value=simulatorEndpoint}}
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
diff --git a/package.json b/package.json
index 0eb3da4..bea92e8 100644
--- a/package.json
+++ b/package.json
@@ -32,13 +32,16 @@
"ember-cli-jshint": "^1.0.0",
"ember-cli-qunit": "^1.4.0",
"ember-cli-release": "0.2.8",
+ "ember-cli-sass": "5.5.2",
"ember-cli-sri": "^2.1.0",
"ember-cli-uglify": "^1.2.0",
"ember-data": "^2.5.0",
"ember-export-application-global": "^1.0.5",
"ember-load-initializers": "^0.5.1",
+ "ember-modal-dialog": "^0.9.0",
"ember-resolver": "^2.0.3",
"ember-simple-auth": "^1.1.0",
+ "ember-tether": "0.3.1",
"loader.js": "^4.0.1"
},
"dependencies": {}
diff --git a/tests/unit/controllers/simulators-test.js b/tests/unit/controllers/simulators-test.js
new file mode 100644
index 0000000..285361d
--- /dev/null
+++ b/tests/unit/controllers/simulators-test.js
@@ -0,0 +1,12 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:simulators', 'Unit | Controller | simulators', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+// Replace this with your real tests.
+test('it exists', function(assert) {
+ let controller = this.subject();
+ assert.ok(controller);
+});
diff --git a/tests/unit/models/simulator-test.js b/tests/unit/models/simulator-test.js
new file mode 100644
index 0000000..8a6206a
--- /dev/null
+++ b/tests/unit/models/simulator-test.js
@@ -0,0 +1,12 @@
+import { moduleForModel, test } from 'ember-qunit';
+
+moduleForModel('simulator', 'Unit | Model | simulator', {
+ // Specify the other units that are required for this test.
+ needs: []
+});
+
+test('it exists', function(assert) {
+ let model = this.subject();
+ // let store = this.store();
+ assert.ok(!!model);
+});
diff --git a/tests/unit/routes/simulators-test.js b/tests/unit/routes/simulators-test.js
new file mode 100644
index 0000000..8dbfe46
--- /dev/null
+++ b/tests/unit/routes/simulators-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:simulators', 'Unit | Route | simulators', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/routes/simulators/delete-test.js b/tests/unit/routes/simulators/delete-test.js
new file mode 100644
index 0000000..98ca109
--- /dev/null
+++ b/tests/unit/routes/simulators/delete-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:simulators/delete', 'Unit | Route | simulators/delete', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/routes/simulators/edit-test.js b/tests/unit/routes/simulators/edit-test.js
new file mode 100644
index 0000000..be49ba0
--- /dev/null
+++ b/tests/unit/routes/simulators/edit-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:simulators/edit', 'Unit | Route | simulators/edit', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
diff --git a/tests/unit/routes/simulators/index-test.js b/tests/unit/routes/simulators/index-test.js
new file mode 100644
index 0000000..dfccfba
--- /dev/null
+++ b/tests/unit/routes/simulators/index-test.js
@@ -0,0 +1,11 @@
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:simulators/index', 'Unit | Route | simulators/index', {
+ // Specify the other units that are required for this test.
+ // needs: ['controller:foo']
+});
+
+test('it exists', function(assert) {
+ let route = this.subject();
+ assert.ok(route);
+});
From 35b885f19b48f25f38201d50ac056ac79148cfb4 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Sat, 1 Oct 2016 11:11:35 +0200
Subject: [PATCH 025/556] Add modal dialogs to projects and simulation-models
---
app/controllers/project/delete.js | 30 ---
app/controllers/project/edit.js | 37 ----
app/controllers/project/index.js | 104 +++++++++-
app/controllers/project/new.js | 36 ----
app/controllers/projects.js | 115 ++++++++++++
app/controllers/simulation-model/delete.js | 4 -
app/controllers/simulation-model/edit.js | 21 ---
app/controllers/simulation-model/new.js | 55 ------
app/controllers/simulation/delete.js | 4 -
app/controllers/simulation/edit.js | 4 -
app/controllers/simulation/index.js | 177 ++++++++++++++++++
app/controllers/simulation/new.js | 38 ----
app/controllers/simulations.js | 115 ++++++++++++
app/router.js | 10 -
app/routes/project/delete.js | 17 --
app/routes/project/edit.js | 17 --
app/routes/project/new.js | 14 --
app/routes/projects.js | 6 +-
app/routes/simulation-model/delete.js | 4 -
app/routes/simulation-model/edit.js | 7 -
app/routes/simulation-model/new.js | 20 --
app/routes/simulation-models.js | 14 --
app/routes/simulation/delete.js | 4 -
app/routes/simulation/edit.js | 4 -
app/routes/simulation/index.js | 5 +-
app/routes/simulation/new.js | 14 --
app/services/running-simulation.js | 3 +-
app/templates/project/delete.hbs | 6 -
app/templates/project/edit.hbs | 15 --
app/templates/project/index.hbs | 77 +++++++-
app/templates/project/new.hbs | 24 ---
app/templates/projects.hbs | 75 +++++++-
app/templates/simulation-model/delete.hbs | 1 -
app/templates/simulation-model/edit.hbs | 8 -
app/templates/simulation-model/new.hbs | 32 ----
app/templates/simulation-models.hbs | 24 ---
app/templates/simulation/delete.hbs | 1 -
app/templates/simulation/edit.hbs | 1 -
app/templates/simulation/index.hbs | 105 ++++++++++-
app/templates/simulation/new.hbs | 20 --
app/templates/simulations.hbs | 77 +++++++-
app/templates/simulators.hbs | 2 +-
package.json | 1 +
tests/unit/controllers/project/delete-test.js | 12 --
.../edit-test.js => projects-test.js} | 2 +-
.../simulation-model/delete-test.js | 12 --
.../controllers/simulation-model/edit-test.js | 12 --
.../controllers/simulation-model/new-test.js | 12 --
.../controllers/simulation/delete-test.js | 12 --
.../unit/controllers/simulation/edit-test.js | 12 --
.../new-test.js => simulations-test.js} | 2 +-
.../routes/simulation-model/delete-test.js | 11 --
.../unit/routes/simulation-model/edit-test.js | 11 --
.../unit/routes/simulation-model/new-test.js | 11 --
tests/unit/routes/simulation/delete-test.js | 11 --
tests/unit/routes/simulation/edit-test.js | 11 --
tests/unit/routes/simulation/new-test.js | 11 --
57 files changed, 835 insertions(+), 655 deletions(-)
delete mode 100644 app/controllers/project/delete.js
delete mode 100644 app/controllers/project/edit.js
delete mode 100644 app/controllers/project/new.js
create mode 100644 app/controllers/projects.js
delete mode 100644 app/controllers/simulation-model/delete.js
delete mode 100644 app/controllers/simulation-model/edit.js
delete mode 100644 app/controllers/simulation-model/new.js
delete mode 100644 app/controllers/simulation/delete.js
delete mode 100644 app/controllers/simulation/edit.js
delete mode 100644 app/controllers/simulation/new.js
create mode 100644 app/controllers/simulations.js
delete mode 100644 app/routes/project/delete.js
delete mode 100644 app/routes/project/edit.js
delete mode 100644 app/routes/project/new.js
delete mode 100644 app/routes/simulation-model/delete.js
delete mode 100644 app/routes/simulation-model/edit.js
delete mode 100644 app/routes/simulation-model/new.js
delete mode 100644 app/routes/simulation-models.js
delete mode 100644 app/routes/simulation/delete.js
delete mode 100644 app/routes/simulation/edit.js
delete mode 100644 app/routes/simulation/new.js
delete mode 100644 app/templates/project/delete.hbs
delete mode 100644 app/templates/project/edit.hbs
delete mode 100644 app/templates/project/new.hbs
delete mode 100644 app/templates/simulation-model/delete.hbs
delete mode 100644 app/templates/simulation-model/edit.hbs
delete mode 100644 app/templates/simulation-model/new.hbs
delete mode 100644 app/templates/simulation-models.hbs
delete mode 100644 app/templates/simulation/delete.hbs
delete mode 100644 app/templates/simulation/edit.hbs
delete mode 100644 app/templates/simulation/new.hbs
delete mode 100644 tests/unit/controllers/project/delete-test.js
rename tests/unit/controllers/{project/edit-test.js => projects-test.js} (79%)
delete mode 100644 tests/unit/controllers/simulation-model/delete-test.js
delete mode 100644 tests/unit/controllers/simulation-model/edit-test.js
delete mode 100644 tests/unit/controllers/simulation-model/new-test.js
delete mode 100644 tests/unit/controllers/simulation/delete-test.js
delete mode 100644 tests/unit/controllers/simulation/edit-test.js
rename tests/unit/controllers/{simulation/new-test.js => simulations-test.js} (78%)
delete mode 100644 tests/unit/routes/simulation-model/delete-test.js
delete mode 100644 tests/unit/routes/simulation-model/edit-test.js
delete mode 100644 tests/unit/routes/simulation-model/new-test.js
delete mode 100644 tests/unit/routes/simulation/delete-test.js
delete mode 100644 tests/unit/routes/simulation/edit-test.js
delete mode 100644 tests/unit/routes/simulation/new-test.js
diff --git a/app/controllers/project/delete.js b/app/controllers/project/delete.js
deleted file mode 100644
index b9b6c96..0000000
--- a/app/controllers/project/delete.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * File: delete.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- sessionUser: Ember.inject.service('session-user'),
-
- actions: {
- cancelDelete() {
- // go back to project view
- let projectId = this.get('model.id');
- this.transitionToRoute('/project/' + projectId);
- },
-
- confirmDelete() {
- // delete the project
- var project = this.get('model');
- project.destroyRecord();
-
- this.transitionToRoute('/projects');
- }
- }
-});
diff --git a/app/controllers/project/edit.js b/app/controllers/project/edit.js
deleted file mode 100644
index 574a5ff..0000000
--- a/app/controllers/project/edit.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * File: edit.js
- * Author: Markus Grigull
- * Date: 11.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- name: function() {
- return this.get('model.name');
- }.property('model.name'),
-
- actions: {
- saveEdit() {
- // apply the changes
- var project = this.get('model');
- project.set('name', this.get('name'));
-
- // save the changes
- let projectId = project.get('id');
- var controller = this;
-
- project.save().then(function() {
- controller.transitionToRoute('/project/' + projectId);
- });
- },
-
- cancelEdit() {
- let projectId = this.get('model.id');
- this.transitionToRoute('/project/' + projectId);
- }
- }
-});
diff --git a/app/controllers/project/index.js b/app/controllers/project/index.js
index 1437734..4f457cd 100644
--- a/app/controllers/project/index.js
+++ b/app/controllers/project/index.js
@@ -10,19 +10,107 @@
import Ember from 'ember';
export default Ember.Controller.extend({
- actions: {
- newVisualization() {
- // get the project
- var project = this.get('model');
- var projectId = this.get('model.id');
+ isShowingNewModal: false,
+ isShowingEditModal: false,
+ isShowingDeleteModal: false,
- // create the visualization
- var visualization = this.store.createRecord('visualization', { name: 'Visualization', project: projectId });
+ errorMessage: null,
+
+ visualization: null,
+
+ actions: {
+ showNewModal() {
+ // reset properties
+ this.set('errorMessage', null);
+ this.set('name', null);
+
+ // show the dialog
+ this.set('isShowingNewModal', true);
+ },
+
+ showEditModal(visualization) {
+ // set properties
+ this.set('errorMessage', null);
+ this.set('visualization', visualization);
+ this.set('name', visualization.get('name'));
+
+ // show the dialog
+ this.set('isShowingEditModal', true);
+ },
+
+ showDeleteModal(visualization) {
+ // set properties
+ this.set('visualization', visualization);
+
+ // show the dialog
+ this.set('isShowingDeleteModal', true);
+ },
+
+ submitNew() {
+ // verify properties
+ var properties = this.getProperties('name');
+ if (properties['name'] == null || properties['name'] == "") {
+ this.set('errorMessage', 'Visualization name is missing');
+ return;
+ }
+
+ // set project property
+ properties['project'] = this.get('model.id');
+
+ // create new project
+ var visualization = this.store.createRecord('visualization', properties);
+ var controller = this;
// this change will not be saved, but it is nessecary otherwise ember will omit the project's id in the post request
+ var project = this.get('model');
project.get('visualizations').pushObject(visualization);
- visualization.save();
+ visualization.save().then(function() {
+ controller.set('isShowingNewModal', false);
+ }, function() {
+ Ember.debug('Error saving new visualization');
+ });
+ },
+
+ cancelNew() {
+ this.set('isShowingNewModal', false);
+ },
+
+ submitEdit() {
+ // verify properties
+ var properties = this.getProperties('name');
+ if (properties['name'] == null || properties['name'] == "") {
+ this.set('errorMessage', 'Visualization name is missing');
+ return;
+ }
+
+ // save properties
+ this.get('visualization').setProperties(properties);
+
+ var controller = this;
+
+ this.get('visualization').save().then(function() {
+ controller.set('isShowingEditModal', false);
+ }, function() {
+ Ember.debug('Error saving edit visualization');
+ });
+ },
+
+ cancelEdit() {
+ this.set('isShowingEditModal', false);
+ },
+
+ confirmDelete() {
+ // delete the visualization
+ var visualization = this.get('visualization');
+ visualization.destroyRecord();
+
+ // hide the dialog
+ this.set('isShowingDeleteModal', false);
+ },
+
+ cancelDelete() {
+ this.set('isShowingDeleteModal', false);
}
}
});
diff --git a/app/controllers/project/new.js b/app/controllers/project/new.js
deleted file mode 100644
index 500e75e..0000000
--- a/app/controllers/project/new.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * File: new.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- sessionUser: Ember.inject.service('session-user'),
-
- actions: {
- newProject() {
- // get current user
- var user = this.get('sessionUser.user');
-
- // create new project from properties
- var properties = this.getProperties('name');
- properties['owner'] = user;
-
- var project = this.store.createRecord('project', properties);
- var controller = this;
-
- project.save().then(function() {
- controller.transitionToRoute('/projects');
- });
- },
-
- cancelNewProject() {
- this.transitionToRoute('/projects');
- }
- }
-});
diff --git a/app/controllers/projects.js b/app/controllers/projects.js
new file mode 100644
index 0000000..1a5dcfd
--- /dev/null
+++ b/app/controllers/projects.js
@@ -0,0 +1,115 @@
+/**
+ * File: projects.js
+ * Author: Markus Grigull
+ * Date: 01.10.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ sessionUser: Ember.inject.service('session-user'),
+
+ isShowingNewModal: false,
+ isShowingEditModal: false,
+ isShowingDeleteModal: false,
+
+ errorMessage: null,
+
+ project: null,
+
+ actions: {
+ showNewModal() {
+ // reset properties
+ this.set('errorMessage', null);
+ this.set('name', null);
+
+ // show the dialog
+ this.set('isShowingNewModal', true);
+ },
+
+ showEditModal(project) {
+ // set properties
+ this.set('errorMessage', null);
+ this.set('project', project);
+ this.set('name', project.get('name'));
+
+ // show the dialog
+ this.set('isShowingEditModal', true);
+ },
+
+ showDeleteModal(project) {
+ // set properties
+ this.set('project', project);
+
+ // show the dialog
+ this.set('isShowingDeleteModal', true);
+ },
+
+ submitNew() {
+ // verify properties
+ var properties = this.getProperties('name');
+ if (properties['name'] == null || properties['name'] == "") {
+ this.set('errorMessage', 'Project name is missing');
+ return;
+ }
+
+ // set owner properties
+ var user = this.get('sessionUser.user');
+ properties['owner'] = user;
+
+ // create new project
+ var project = this.store.createRecord('project', properties);
+ var controller = this;
+
+ project.save().then(function() {
+ controller.set('isShowingNewModal', false);
+ }, function() {
+ Ember.debug('Error saving new project');
+ });
+ },
+
+ cancelNew() {
+ this.set('isShowingNewModal', false);
+ },
+
+ submitEdit() {
+ // verify properties
+ var properties = this.getProperties('name');
+ if (properties['name'] == null || properties['name'] == "") {
+ this.set('errorMessage', 'Project name is missing');
+ return;
+ }
+
+ // save properties
+ this.get('project').setProperties(properties);
+
+ var controller = this;
+
+ this.get('project').save().then(function() {
+ controller.set('isShowingEditModal', false);
+ }, function() {
+ Ember.debug('Error saving edit project');
+ });
+ },
+
+ cancelEdit() {
+ this.set('isShowingEditModal', false);
+ },
+
+ confirmDelete() {
+ // delete the project
+ var project = this.get('project');
+ project.destroyRecord();
+
+ // hide the dialog
+ this.set('isShowingDeleteModal', false);
+ },
+
+ cancelDelete() {
+ this.set('isShowingDeleteModal', false);
+ }
+ }
+});
diff --git a/app/controllers/simulation-model/delete.js b/app/controllers/simulation-model/delete.js
deleted file mode 100644
index 55ff9aa..0000000
--- a/app/controllers/simulation-model/delete.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
-});
diff --git a/app/controllers/simulation-model/edit.js b/app/controllers/simulation-model/edit.js
deleted file mode 100644
index e38e81d..0000000
--- a/app/controllers/simulation-model/edit.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- sequence: function() {
- return this.get('model.sequence');
- }.property('model.sequence'),
-
- values: function() {
- return this.get('model.values');
- }.property('model.values.@each'),
-
- _updateModel: function() {
- if (this.get('model') === null) {
- Ember.run.later(this, function() {
- var simulationData = this.store.peekRecord('simulation-data', 1);
- this.set('model', simulationData);
- this.notifyPropertyChange('model');
- }, 500);
- }
- }.observes('model').on('init')
-});
diff --git a/app/controllers/simulation-model/new.js b/app/controllers/simulation-model/new.js
deleted file mode 100644
index b72bc7f..0000000
--- a/app/controllers/simulation-model/new.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * File: new.js
- * Author: Markus Grigull
- * Date: 20.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- simulator: null,
-
- actions: {
- newModel() {
- // get the simulation
- var simulation = this.get('model.simulation');
- var simulationId = this.get('model.simulation.id');
-
- // create new model from properties
- var properties = this.getProperties('name');
- properties['simulation'] = simulationId;
-
- // get the simulator id by simulator name
- if (this.get('simulator') == null) {
- this.set('simulator', this.get('model.simulators')[0]);
- }
-
- console.log(this.get('model.simulators')[0]);
-
- /*var simulationModel = this.store.createRecord('simulation-model', properties);
-
- // this change will not be saved, but it is nessecary otherwise ember will omit the simulation's id in the post request
- simulation.get('models').pushObject(simulationModel);
-
- var controller = this;
-
- simulationModel.save().then(function() {
- controller.transitionToRoute('/simulation/' + simulationId);
- }, function() {
- Ember.debug('Error saving new model');
- });*/
- },
-
- cancelNewModel() {
- var simulationId = this.get('model.simulation.id');
- this.transitionToRoute('/simulation/' + simulationId);
- },
-
- selectSimulator(simulator) {
- this.set('simulator', simulator);
- }
- }
-});
diff --git a/app/controllers/simulation/delete.js b/app/controllers/simulation/delete.js
deleted file mode 100644
index 55ff9aa..0000000
--- a/app/controllers/simulation/delete.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
-});
diff --git a/app/controllers/simulation/edit.js b/app/controllers/simulation/edit.js
deleted file mode 100644
index 55ff9aa..0000000
--- a/app/controllers/simulation/edit.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
-});
diff --git a/app/controllers/simulation/index.js b/app/controllers/simulation/index.js
index 55ff9aa..2208780 100644
--- a/app/controllers/simulation/index.js
+++ b/app/controllers/simulation/index.js
@@ -1,4 +1,181 @@
+/**
+ * File: index.js
+ * Author: Markus Grigull
+ * Date: 30.09.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
import Ember from 'ember';
export default Ember.Controller.extend({
+ isShowingNewModal: false,
+ isShowingEditModal: false,
+ isShowingDeleteModal: false,
+
+ errorMessage: null,
+
+ simulationModel: null,
+ simulatorName: null,
+
+ _updateSimulators: function() {
+ if (this.get('model.simulators') != null && this.get('model.simulators.length') > 0) {
+ var simulators = this.get('model.simulators');
+ this.set('simulatorName', simulators.toArray()[0].get('name'));
+ }
+ }.observes('model'),
+
+ actions: {
+ showNewModal() {
+ // reset properties
+ this.set('errorMessage', null);
+ this.set('name', null);
+
+ // show the dialog
+ this.set('isShowingNewModal', true);
+ },
+
+ showEditModal(simulationModel) {
+ // set properties
+ this.set('errorMessage', null);
+ this.set('simulationModel', simulationModel);
+ this.set('name', simulationModel.get('name'));
+
+ var simulators = this.get('model.simulators');
+ var simulatorId = simulationModel.get('simulator');
+ var simulatorName = null;
+
+ simulators.forEach(function(simulator) {
+ if (simulator.get('simulatorid') == simulatorId) {
+ simulatorName = simulator.get('name');
+ }
+ });
+
+ this.set('simulatorName', simulatorName);
+
+ // show the dialog
+ this.set('isShowingEditModal', true);
+ },
+
+ showDeleteModal(simulationModel) {
+ // set properties
+ this.set('simulationModel', simulationModel);
+
+ // show the dialog
+ this.set('isShowingDeleteModal', true);
+ },
+
+ submitNew() {
+ // verify properties
+ var properties = this.getProperties('name');
+ if (properties['name'] == null || properties['name'] == "") {
+ this.set('errorMessage', 'Simulation model name is missing');
+ return;
+ }
+
+ // set simuatlion properties
+ var simulation = this.get('model.simulation');
+ properties['simulation'] = simulation.get('id');;
+
+ // get the simulator id by simulator name
+ var simulators = this.get('model.simulators');
+ var simulatorId = null;
+ var simulatorName = this.get('simulatorName');
+
+ simulators.forEach(function(simulator) {
+ if (simulator.get('name') === simulatorName) {
+ simulatorId = simulator.get('simulatorid');
+ }
+ });
+
+ if (simulatorId == null) {
+ Ember.debug('Unable to find simulator by name');
+ return;
+ }
+
+ properties['simulator'] = simulatorId;
+
+ // create new model
+ var simulationModel = this.store.createRecord('simulation-model', properties);
+
+ // this change will not be saved, but it is nessecary otherwise ember will omit the simulation's id in the post request
+ simulation.get('models').pushObject(simulationModel);
+
+ var controller = this;
+
+ simulationModel.save().then(function() {
+ controller.set('isShowingNewModal', false);
+ }, function() {
+ Ember.debug('Error saving new model');
+ });
+ },
+
+ cancelNew() {
+ this.set('isShowingNewModal', false);
+ },
+
+ submitEdit() {
+ // verify properties
+ var properties = this.getProperties('name');
+ if (properties['name'] == null || properties['name'] == "") {
+ this.set('errorMessage', 'Simulation model name is missing');
+ return;
+ }
+
+ // set simuatlion properties
+ var simulation = this.get('model.simulation');
+ properties['simulation'] = simulation.get('id');;
+
+ // get the simulator id by simulator name
+ var simulators = this.get('model.simulators');
+ var simulatorId = null;
+ var simulatorName = this.get('simulatorName');
+
+ simulators.forEach(function(simulator) {
+ if (simulator.get('name') === simulatorName) {
+ simulatorId = simulator.get('simulatorid');
+ }
+ });
+
+ if (simulatorId == null) {
+ Ember.debug('Unable to find simulator by name');
+ return;
+ }
+
+ properties['simulator'] = simulatorId;
+
+ // save properties
+ var controller = this;
+
+ this.get('simulationModel').setProperties(properties);
+
+ this.get('simulationModel').save().then(function() {
+ controller.set('isShowingEditModal', false);
+ }, function() {
+ Ember.debug('Error saving edit simulation model');
+ });
+ },
+
+ cancelEdit() {
+ this.set('isShowingEditModal', false);
+ },
+
+ confirmDelete() {
+ // delete the model
+ var simulationModel = this.get('simulationModel');
+ simulationModel.destroyRecord();
+
+ // hide the dialog
+ this.set('isShowingDeleteModal', false);
+ },
+
+ cancelDelete() {
+ this.set('isShowingDeleteModal', false);
+ },
+
+ selectSimulator(simulator) {
+ this.set('simulatorName', simulator);
+ }
+ }
});
diff --git a/app/controllers/simulation/new.js b/app/controllers/simulation/new.js
deleted file mode 100644
index bf6255d..0000000
--- a/app/controllers/simulation/new.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * File: new.js
- * Author: Markus Grigull
- * Date: 26.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- sessionUser: Ember.inject.service('session-user'),
-
- actions: {
- newSimulation() {
- // get current user
- var user = this.get('sessionUser.user');
-
- // create new simulation from properties
- var properties = this.getProperties('name');
- properties['owner'] = user;
-
- var simulation = this.store.createRecord('simulation', properties);
- var controller = this;
-
- simulation.save().then(function() {
- controller.transitionToRoute('/simulations');
- }, function() {
- Ember.debug('Error saving new simulation');
- });
- },
-
- cancelNewSimulation() {
- this.transitionToRoute('/simulations');
- }
- }
-});
diff --git a/app/controllers/simulations.js b/app/controllers/simulations.js
new file mode 100644
index 0000000..9eaea92
--- /dev/null
+++ b/app/controllers/simulations.js
@@ -0,0 +1,115 @@
+/**
+ * File: simulation.js
+ * Author: Markus Grigull
+ * Date: 30.09.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+ sessionUser: Ember.inject.service('session-user'),
+
+ isShowingNewModal: false,
+ isShowingEditModal: false,
+ isShowingEditModal: false,
+
+ errorMessage: null,
+
+ simulation: null,
+
+ actions: {
+ showNewModal() {
+ // reset properties
+ this.set('errorMessage', null);
+ this.set('name', null);
+
+ // show the dialog
+ this.set('isShowingNewModal', true);
+ },
+
+ showEditModal(simulation) {
+ // set properties
+ this.set('errorMessage', null);
+ this.set('simulation', simulation);
+ this.set('name', simulation.get('name'));
+
+ // show the dialog
+ this.set('isShowingEditModal', true);
+ },
+
+ showDeleteModal(simulation) {
+ // set properties
+ this.set('simulation', simulation);
+
+ // show the dialog
+ this.set('isShowingDeleteModal', true);
+ },
+
+ submitNew() {
+ // verify properties
+ var properties = this.getProperties('name');
+ if (properties['name'] == null || properties['name'] == "") {
+ this.set('errorMessage', 'Simulation name is missing');
+ return;
+ }
+
+ // set owner properties
+ var user = this.get('sessionUser.user');
+ properties['owner'] = user;
+
+ // create new simulation
+ var simulation = this.store.createRecord('simulation', properties);
+ var controller = this;
+
+ simulation.save().then(function() {
+ controller.set('isShowingNewModal', false);
+ }, function() {
+ Ember.debug('Error saving new simulation');
+ });
+ },
+
+ cancelNew() {
+ this.set('isShowingNewModal', false);
+ },
+
+ submitEdit() {
+ // verify properties
+ var properties = this.getProperties('name');
+ if (properties['name'] == null || properties['name'] == "") {
+ this.set('errorMessage', 'Simulation name is missing');
+ return;
+ }
+
+ // save properties
+ this.get('simulation').set('name', properties['name']);
+
+ var controller = this;
+
+ this.get('simulation').save().then(function() {
+ controller.set('isShowingEditModal', false);
+ }, function() {
+ Ember.debug('Error saving edit simulation');
+ });
+ },
+
+ cancelEdit() {
+ this.set('isShowingEditModal', false);
+ },
+
+ confirmDelete() {
+ // delete the simulation
+ var simulation = this.get('simulation');
+ simulation.destroyRecord();
+
+ // hide the dialog
+ this.set('isShowingDeleteModal', false);
+ },
+
+ cancelDelete() {
+ this.set('isShowingDeleteModal', false);
+ }
+ }
+});
diff --git a/app/router.js b/app/router.js
index 513436f..4f52379 100644
--- a/app/router.js
+++ b/app/router.js
@@ -21,9 +21,6 @@ Router.map(function() {
this.route('projects');
this.route('project', function() {
this.route('index', { path: '/:projectid' });
- this.route('new');
- this.route('edit', { path: '/edit/:projectid' });
- this.route('delete', { path: '/delete/:projectid' });
});
this.route('me');
@@ -45,18 +42,11 @@ Router.map(function() {
this.route('simulation-model', function() {
this.route('index', { path: '/:modelid' });
- this.route('new', { path: '/new/:simulationid' });
- this.route('delete', { path: '/delete/:modelid' });
- this.route('edit', { path: '/edit/:modelid' });
});
- this.route('simulation-models');
this.route('simulations');
this.route('simulation', function() {
this.route('index', { path: '/:simulationid' });
- this.route('delete', { path: '/delete/:simulationid' });
- this.route('new');
- this.route('edit', { path: '/edit/:simulationid' });
});
this.route('simulators');
diff --git a/app/routes/project/delete.js b/app/routes/project/delete.js
deleted file mode 100644
index ec3a964..0000000
--- a/app/routes/project/delete.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: delete.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return this.store.findRecord('project', params.projectid);
- }
-});
diff --git a/app/routes/project/edit.js b/app/routes/project/edit.js
deleted file mode 100644
index 6e52fe9..0000000
--- a/app/routes/project/edit.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: edit.js
- * Author: Markus Grigull
- * Date: 05.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return this.store.findRecord('project', params.projectid);
- }
-});
diff --git a/app/routes/project/new.js b/app/routes/project/new.js
deleted file mode 100644
index 38e760a..0000000
--- a/app/routes/project/new.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * File: new.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
-});
diff --git a/app/routes/projects.js b/app/routes/projects.js
index 2908aa4..cf7f030 100644
--- a/app/routes/projects.js
+++ b/app/routes/projects.js
@@ -14,10 +14,8 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
sessionUser: Ember.inject.service('session-user'),
model() {
- // get session user
- var userId = this.get('sessionUser.user.id');
- let user = this.store.peekRecord('user', userId);
-
+ // get projects for current user
+ var user = this.get('sessionUser.user');
return user.get('projects');
}
});
diff --git a/app/routes/simulation-model/delete.js b/app/routes/simulation-model/delete.js
deleted file mode 100644
index 26d9f31..0000000
--- a/app/routes/simulation-model/delete.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Route.extend({
-});
diff --git a/app/routes/simulation-model/edit.js b/app/routes/simulation-model/edit.js
deleted file mode 100644
index 992b1b1..0000000
--- a/app/routes/simulation-model/edit.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Route.extend({
- model() {
- return this.store.peekRecord('simulation-data', 1);
- }
-});
diff --git a/app/routes/simulation-model/new.js b/app/routes/simulation-model/new.js
deleted file mode 100644
index fc60ffc..0000000
--- a/app/routes/simulation-model/new.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * File: new.js
- * Author: Markus Grigull
- * Date: 20.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return Ember.RSVP.hash({
- simulation: this.store.findRecord('simulation', params.simulationid),
- simulators: this.store.findAll('simulator')
- });
- }
-});
diff --git a/app/routes/simulation-models.js b/app/routes/simulation-models.js
deleted file mode 100644
index e80ebbb..0000000
--- a/app/routes/simulation-models.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * File: simulation-models.js
- * Author: Markus Grigull
- * Date: 20.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
-});
diff --git a/app/routes/simulation/delete.js b/app/routes/simulation/delete.js
deleted file mode 100644
index 26d9f31..0000000
--- a/app/routes/simulation/delete.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Route.extend({
-});
diff --git a/app/routes/simulation/edit.js b/app/routes/simulation/edit.js
deleted file mode 100644
index 26d9f31..0000000
--- a/app/routes/simulation/edit.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Route.extend({
-});
diff --git a/app/routes/simulation/index.js b/app/routes/simulation/index.js
index 05b1b84..567b7e3 100644
--- a/app/routes/simulation/index.js
+++ b/app/routes/simulation/index.js
@@ -12,6 +12,9 @@ import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-rout
export default Ember.Route.extend(AuthenticatedRouteMixin, {
model(params) {
- return this.store.findRecord('simulation', params.simulationid);
+ return Ember.RSVP.hash({
+ simulation: this.store.findRecord('simulation', params.simulationid),
+ simulators: this.store.findAll('simulator')
+ });
}
});
diff --git a/app/routes/simulation/new.js b/app/routes/simulation/new.js
deleted file mode 100644
index 8f8de75..0000000
--- a/app/routes/simulation/new.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * File: new.js
- * Author: Markus Grigull
- * Date: 26.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
-});
diff --git a/app/services/running-simulation.js b/app/services/running-simulation.js
index 40aa46b..2d97597 100644
--- a/app/services/running-simulation.js
+++ b/app/services/running-simulation.js
@@ -21,6 +21,7 @@ export default Ember.Service.extend({
var self = this;
// check every second for running simulation
+ /*
setInterval(function() {
// check if running simulation did changed
self.get('store').findAll('simulation').then(function(simulations) {
@@ -36,6 +37,6 @@ export default Ember.Service.extend({
self.set('simulation', newSimulation);
}
});
- }, 1000);
+ }, 1000);*/
}
});
diff --git a/app/templates/project/delete.hbs b/app/templates/project/delete.hbs
deleted file mode 100644
index 2aa92ae..0000000
--- a/app/templates/project/delete.hbs
+++ /dev/null
@@ -1,6 +0,0 @@
-Delete Project
-
-Are you sure you want to delete the project?
-
-Cancel
-Delete
diff --git a/app/templates/project/edit.hbs b/app/templates/project/edit.hbs
deleted file mode 100644
index 1c42a97..0000000
--- a/app/templates/project/edit.hbs
+++ /dev/null
@@ -1,15 +0,0 @@
-Edit project
-
-
-
- Name
- {{input id='name' placeholder='Enter project name' value=name}}
-
-
- Cancel
- Save
-
- {{#if errorMessage}}
- {{errorMessage.message}}
- {{/if}}
-
diff --git a/app/templates/project/index.hbs b/app/templates/project/index.hbs
index 93dcedb..b94ec9d 100644
--- a/app/templates/project/index.hbs
+++ b/app/templates/project/index.hbs
@@ -1,3 +1,5 @@
+{{#link-to 'projects'}}Back to projects{{/link-to}}
+
{{model.name}}
@@ -13,8 +15,8 @@
- {{#link-to "visualization.edit" visualization.id}}Edit{{/link-to}}
- {{#link-to "visualization.delete" visualization.id}}Delete{{/link-to}}
+
Edit
+
Delete
@@ -23,5 +25,74 @@
+
+{{#if isShowingNewModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New visualization
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter visualization name' value=name}}
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingEditModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Edit visualization
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter visualization name' value=name}}
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingDeleteModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Delete visualization
+
+ Are you sure you want to delete the visualization {{visualization.name}} ?
+
+ Cancel
+ Delete
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/project/new.hbs b/app/templates/project/new.hbs
deleted file mode 100644
index a2d56d2..0000000
--- a/app/templates/project/new.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-New project
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter project name' value=name}}
-
-
-
-
- Cancel
- Create
-
-
-
-
- {{#if errorMessage}}
- {{errorMessage.message}}
- {{/if}}
-
diff --git a/app/templates/projects.hbs b/app/templates/projects.hbs
index c99113a..b4346fd 100644
--- a/app/templates/projects.hbs
+++ b/app/templates/projects.hbs
@@ -13,8 +13,8 @@
- {{#link-to "project.edit" project.id}}Edit{{/link-to}}
- {{#link-to "project.delete" project.id}}Delete{{/link-to}}
+
Edit
+
Delete
@@ -23,5 +23,74 @@
- {{#link-to "project.new"}}New project{{/link-to}}
+ New Project
+
+{{#if isShowingNewModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New project
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter project name' value=name}}
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingEditModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Edit project
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter project name' value=name}}
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingDeleteModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Delete project
+
+ Are you sure you want to delete the project {{project.name}} ?
+
+ Cancel
+ Delete
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/simulation-model/delete.hbs b/app/templates/simulation-model/delete.hbs
deleted file mode 100644
index c24cd68..0000000
--- a/app/templates/simulation-model/delete.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{outlet}}
diff --git a/app/templates/simulation-model/edit.hbs b/app/templates/simulation-model/edit.hbs
deleted file mode 100644
index 5db3453..0000000
--- a/app/templates/simulation-model/edit.hbs
+++ /dev/null
@@ -1,8 +0,0 @@
-{{sequence}}
-
-
-
-{{#each values as |value|}}
- {{value}}
-
-{{/each}}
diff --git a/app/templates/simulation-model/new.hbs b/app/templates/simulation-model/new.hbs
deleted file mode 100644
index 5fa523d..0000000
--- a/app/templates/simulation-model/new.hbs
+++ /dev/null
@@ -1,32 +0,0 @@
-New model
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter model name' value=name}}
-
-
-
-
- Simulator
-
-
-
- {{#each model.simulators as |simulator|}}
- {{simulator.name}}
- {{/each}}
-
-
-
-
-
- Cancel
- Create
-
-
-
-
diff --git a/app/templates/simulation-models.hbs b/app/templates/simulation-models.hbs
deleted file mode 100644
index ca7dd24..0000000
--- a/app/templates/simulation-models.hbs
+++ /dev/null
@@ -1,24 +0,0 @@
-Models
-
-
-
-
- Name
-
- {{#each model as |simulationModel|}}
-
-
- {{#link-to "simulation-model.index" simulationModel.id}}{{simulationModel.name}}{{/link-to}}
-
- {{#link-to "simulation-model.edit" simulationModel.id}}Edit{{/link-to}}
- {{#link-to "simulation-model.delete" simulationModel.id}}Delete{{/link-to}}
-
-
-
- {{/each}}
-
-
-
-
- {{#link-to "simulation-model.new"}}New model{{/link-to}}
-
diff --git a/app/templates/simulation/delete.hbs b/app/templates/simulation/delete.hbs
deleted file mode 100644
index c24cd68..0000000
--- a/app/templates/simulation/delete.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{outlet}}
diff --git a/app/templates/simulation/edit.hbs b/app/templates/simulation/edit.hbs
deleted file mode 100644
index c24cd68..0000000
--- a/app/templates/simulation/edit.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{outlet}}
diff --git a/app/templates/simulation/index.hbs b/app/templates/simulation/index.hbs
index 738ae2c..6a2efd5 100644
--- a/app/templates/simulation/index.hbs
+++ b/app/templates/simulation/index.hbs
@@ -1,4 +1,6 @@
-{{model.name}}
+{{#link-to 'simulations'}}Back to simulations{{/link-to}}
+
+{{model.simulation.name}}
@@ -7,7 +9,7 @@
Simulator
- {{#each model.models as |simulationModel|}}
+ {{#each model.simulation.models as |simulationModel|}}
{{#link-to "simulation-model.index" simulationModel.id}}{{simulationModel.name}}{{/link-to}}
@@ -17,8 +19,8 @@
- {{#link-to "simulation-model.edit" simulationModel.id}}Edit{{/link-to}}
- {{#link-to "simulation-model.delete" simulationModel.id}}Delete{{/link-to}}
+
Edit
+
Delete
@@ -27,5 +29,98 @@
- {{#link-to "simulation-model.new" model.id}}New model{{/link-to}}
+ New model
+
+{{#if isShowingNewModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New model
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter model name' value=name}}
+
+
+
+
+ Simulator
+
+
+
+ {{#each model.simulators as |simulator|}}
+ {{simulator.name}}
+ {{/each}}
+
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingEditModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Edit model
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter model name' value=name}}
+
+
+
+
+ Simulator
+
+
+
+ {{#each model.simulators as |simulator|}}
+ {{simulator.name}}
+ {{/each}}
+
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingDeleteModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Delete simulation-model
+
+ Are you sure you want to delete the simulation-model {{simulationModel.name}} ?
+
+ Cancel
+ Delete
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/simulation/new.hbs b/app/templates/simulation/new.hbs
deleted file mode 100644
index 211149f..0000000
--- a/app/templates/simulation/new.hbs
+++ /dev/null
@@ -1,20 +0,0 @@
-New simulation
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter simulation name' value=name}}
-
-
-
-
- Cancel
- Create
-
-
-
-
diff --git a/app/templates/simulations.hbs b/app/templates/simulations.hbs
index 40fa4a6..d94b085 100644
--- a/app/templates/simulations.hbs
+++ b/app/templates/simulations.hbs
@@ -17,8 +17,10 @@
- {{#link-to "simulation.edit" simulation.id}}Edit{{/link-to}}
- {{#link-to "simulation.delete" simulation.id}}Delete{{/link-to}}
+
+
+
Edit
+
Delete
@@ -27,5 +29,74 @@
- {{#link-to "simulation.new"}}New simulation{{/link-to}}
+ New Simulation
+
+{{#if isShowingNewModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New simulation
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter simulation name' value=name}}
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingEditModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Edit simulator
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter simulation name' value=name}}
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingDeleteModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Delete simulation
+
+ Are you sure you want to delete the simulation {{simulation.name}} ?
+
+ Cancel
+ Delete
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/simulators.hbs b/app/templates/simulators.hbs
index e860e7b..ed099fd 100644
--- a/app/templates/simulators.hbs
+++ b/app/templates/simulators.hbs
@@ -130,7 +130,7 @@
Cancel
- Create
+ Save
diff --git a/package.json b/package.json
index bea92e8..45b186e 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
"ember-resolver": "^2.0.3",
"ember-simple-auth": "^1.1.0",
"ember-tether": "0.3.1",
+ "ember-truth-helpers": "1.2.0",
"loader.js": "^4.0.1"
},
"dependencies": {}
diff --git a/tests/unit/controllers/project/delete-test.js b/tests/unit/controllers/project/delete-test.js
deleted file mode 100644
index 8b10820..0000000
--- a/tests/unit/controllers/project/delete-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:project/delete', 'Unit | Controller | project/delete', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/project/edit-test.js b/tests/unit/controllers/projects-test.js
similarity index 79%
rename from tests/unit/controllers/project/edit-test.js
rename to tests/unit/controllers/projects-test.js
index 9100007..174083b 100644
--- a/tests/unit/controllers/project/edit-test.js
+++ b/tests/unit/controllers/projects-test.js
@@ -1,6 +1,6 @@
import { moduleFor, test } from 'ember-qunit';
-moduleFor('controller:project/edit', 'Unit | Controller | project/edit', {
+moduleFor('controller:projects', 'Unit | Controller | projects', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
diff --git a/tests/unit/controllers/simulation-model/delete-test.js b/tests/unit/controllers/simulation-model/delete-test.js
deleted file mode 100644
index b8ccc6b..0000000
--- a/tests/unit/controllers/simulation-model/delete-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:simulation-model/delete', 'Unit | Controller | simulation-model/delete', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/simulation-model/edit-test.js b/tests/unit/controllers/simulation-model/edit-test.js
deleted file mode 100644
index 252b107..0000000
--- a/tests/unit/controllers/simulation-model/edit-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:simulation-model/edit', 'Unit | Controller | simulation-model/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/simulation-model/new-test.js b/tests/unit/controllers/simulation-model/new-test.js
deleted file mode 100644
index ae144f9..0000000
--- a/tests/unit/controllers/simulation-model/new-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:simulation-model/new', 'Unit | Controller | simulation-model/new', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/simulation/delete-test.js b/tests/unit/controllers/simulation/delete-test.js
deleted file mode 100644
index 97437e5..0000000
--- a/tests/unit/controllers/simulation/delete-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:simulation/delete', 'Unit | Controller | simulation/delete', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/simulation/edit-test.js b/tests/unit/controllers/simulation/edit-test.js
deleted file mode 100644
index 814e36a..0000000
--- a/tests/unit/controllers/simulation/edit-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:simulation/edit', 'Unit | Controller | simulation/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/simulation/new-test.js b/tests/unit/controllers/simulations-test.js
similarity index 78%
rename from tests/unit/controllers/simulation/new-test.js
rename to tests/unit/controllers/simulations-test.js
index 1f75ab8..9b64642 100644
--- a/tests/unit/controllers/simulation/new-test.js
+++ b/tests/unit/controllers/simulations-test.js
@@ -1,6 +1,6 @@
import { moduleFor, test } from 'ember-qunit';
-moduleFor('controller:simulation/new', 'Unit | Controller | simulation/new', {
+moduleFor('controller:simulations', 'Unit | Controller | simulations', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
diff --git a/tests/unit/routes/simulation-model/delete-test.js b/tests/unit/routes/simulation-model/delete-test.js
deleted file mode 100644
index b333a4a..0000000
--- a/tests/unit/routes/simulation-model/delete-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulation-model/delete', 'Unit | Route | simulation-model/delete', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulation-model/edit-test.js b/tests/unit/routes/simulation-model/edit-test.js
deleted file mode 100644
index 8da4968..0000000
--- a/tests/unit/routes/simulation-model/edit-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulation-model/edit', 'Unit | Route | simulation-model/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulation-model/new-test.js b/tests/unit/routes/simulation-model/new-test.js
deleted file mode 100644
index 67f77f4..0000000
--- a/tests/unit/routes/simulation-model/new-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulation-model/new', 'Unit | Route | simulation-model/new', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulation/delete-test.js b/tests/unit/routes/simulation/delete-test.js
deleted file mode 100644
index 582dca0..0000000
--- a/tests/unit/routes/simulation/delete-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulation/delete', 'Unit | Route | simulation/delete', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulation/edit-test.js b/tests/unit/routes/simulation/edit-test.js
deleted file mode 100644
index 9cb2ae5..0000000
--- a/tests/unit/routes/simulation/edit-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulation/edit', 'Unit | Route | simulation/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulation/new-test.js b/tests/unit/routes/simulation/new-test.js
deleted file mode 100644
index 340a6bd..0000000
--- a/tests/unit/routes/simulation/new-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulation/new', 'Unit | Route | simulation/new', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
From f3d10d83407c03b807a54a011fda172f7c1a31d5 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Thu, 6 Oct 2016 16:56:08 +0200
Subject: [PATCH 026/556] Add simulation-model to simulator relationship
Add simulation to projects
Add running dialog to simulations
Remove running dialog from simulators (simulator should be auto-detected)
Change running-simulation to simulation-models based
---
app/controllers/project/index.js | 4 +-
app/controllers/projects.js | 42 ++++++++-
app/controllers/simulation/index.js | 22 ++---
app/controllers/simulations.js | 44 ++++++++-
app/controllers/simulators.js | 39 ++++++++
app/mixins/websocket-live-stream-mixin.js | 104 ++++++++++++++++------
app/models/simulation-model.js | 2 +-
app/routes/projects.js | 8 +-
app/routes/visualization/index.js | 5 +-
app/services/running-simulation.js | 42 ---------
app/services/running-simulations.js | 64 +++++++++++++
app/templates/projects.hbs | 30 ++++++-
app/templates/simulation/index.hbs | 6 +-
app/templates/simulations.hbs | 23 ++++-
app/templates/simulators.hbs | 23 ++++-
app/templates/visualization/index.hbs | 9 +-
todo.md | 6 +-
17 files changed, 361 insertions(+), 112 deletions(-)
delete mode 100644 app/services/running-simulation.js
create mode 100644 app/services/running-simulations.js
diff --git a/app/controllers/project/index.js b/app/controllers/project/index.js
index 4f457cd..80f931b 100644
--- a/app/controllers/project/index.js
+++ b/app/controllers/project/index.js
@@ -49,7 +49,7 @@ export default Ember.Controller.extend({
submitNew() {
// verify properties
var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] == "") {
+ if (properties['name'] == null || properties['name'] === "") {
this.set('errorMessage', 'Visualization name is missing');
return;
}
@@ -79,7 +79,7 @@ export default Ember.Controller.extend({
submitEdit() {
// verify properties
var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] == "") {
+ if (properties['name'] == null || properties['name'] === "") {
this.set('errorMessage', 'Visualization name is missing');
return;
}
diff --git a/app/controllers/projects.js b/app/controllers/projects.js
index 1a5dcfd..c77ae2e 100644
--- a/app/controllers/projects.js
+++ b/app/controllers/projects.js
@@ -19,6 +19,14 @@ export default Ember.Controller.extend({
errorMessage: null,
project: null,
+ projectSimulation: null,
+
+ _updateSimulations: function() {
+ if (this.get('model.simulations') != null && this.get('model.simulations.length') > 0) {
+ var simulations = this.get('model.simulations');
+ this.set('projectSimulation', simulations.toArray()[0]);
+ }
+ }.observes('model'),
actions: {
showNewModal() {
@@ -35,6 +43,7 @@ export default Ember.Controller.extend({
this.set('errorMessage', null);
this.set('project', project);
this.set('name', project.get('name'));
+ this.set('projectSimulation', project.get('simulation'));
// show the dialog
this.set('isShowingEditModal', true);
@@ -51,17 +60,24 @@ export default Ember.Controller.extend({
submitNew() {
// verify properties
var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] == "") {
+ if (properties['name'] == null || properties['name'] === "") {
this.set('errorMessage', 'Project name is missing');
return;
}
- // set owner properties
+ // set owner property
var user = this.get('sessionUser.user');
properties['owner'] = user;
+ // set simulation property
+ properties['simulation'] = this.get('projectSimulation.id');
+
// create new project
var project = this.store.createRecord('project', properties);
+
+ // this change will not be saved, but it is nessecary otherwise ember will omit the simulation's id in the post request
+ this.get('projectSimulation.projects').pushObject(project);
+
var controller = this;
project.save().then(function() {
@@ -78,14 +94,22 @@ export default Ember.Controller.extend({
submitEdit() {
// verify properties
var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] == "") {
+ if (properties['name'] == null || properties['name'] === "") {
this.set('errorMessage', 'Project name is missing');
return;
}
+ // remove from old simulation
+
+
// save properties
+ properties['simulation'] = this.get('projectSimulation.id');
+
this.get('project').setProperties(properties);
+ // this change will not be saved, but it is nessecary otherwise ember will omit the simulation's id in the post request
+ this.get('projectSimulation.projects').pushObject(this.get('project'));
+
var controller = this;
this.get('project').save().then(function() {
@@ -110,6 +134,18 @@ export default Ember.Controller.extend({
cancelDelete() {
this.set('isShowingDeleteModal', false);
+ },
+
+ selectSimulation(simulationName) {
+ // get simulation by name
+ var simulations = this.get('model.simulations');
+ var controller = this;
+
+ simulations.forEach(function(simulation) {
+ if (simulation.get('name') === simulationName) {
+ controller.set('projectSimulation', simulation);
+ }
+ });
}
}
});
diff --git a/app/controllers/simulation/index.js b/app/controllers/simulation/index.js
index 2208780..d201f3a 100644
--- a/app/controllers/simulation/index.js
+++ b/app/controllers/simulation/index.js
@@ -43,11 +43,11 @@ export default Ember.Controller.extend({
this.set('name', simulationModel.get('name'));
var simulators = this.get('model.simulators');
- var simulatorId = simulationModel.get('simulator');
+ var simulatorId = simulationModel.get('simulator.id');
var simulatorName = null;
simulators.forEach(function(simulator) {
- if (simulator.get('simulatorid') == simulatorId) {
+ if (simulator.get('id') === simulatorId) {
simulatorName = simulator.get('name');
}
});
@@ -69,33 +69,25 @@ export default Ember.Controller.extend({
submitNew() {
// verify properties
var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] == "") {
+ if (properties['name'] == null || properties['name'] === "") {
this.set('errorMessage', 'Simulation model name is missing');
return;
}
// set simuatlion properties
var simulation = this.get('model.simulation');
- properties['simulation'] = simulation.get('id');;
+ properties['simulation'] = simulation;
// get the simulator id by simulator name
var simulators = this.get('model.simulators');
- var simulatorId = null;
var simulatorName = this.get('simulatorName');
simulators.forEach(function(simulator) {
if (simulator.get('name') === simulatorName) {
- simulatorId = simulator.get('simulatorid');
+ properties['simulator'] = simulator;
}
});
- if (simulatorId == null) {
- Ember.debug('Unable to find simulator by name');
- return;
- }
-
- properties['simulator'] = simulatorId;
-
// create new model
var simulationModel = this.store.createRecord('simulation-model', properties);
@@ -118,14 +110,14 @@ export default Ember.Controller.extend({
submitEdit() {
// verify properties
var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] == "") {
+ if (properties['name'] == null || properties['name'] === "") {
this.set('errorMessage', 'Simulation model name is missing');
return;
}
// set simuatlion properties
var simulation = this.get('model.simulation');
- properties['simulation'] = simulation.get('id');;
+ properties['simulation'] = simulation.get('id');
// get the simulator id by simulator name
var simulators = this.get('model.simulators');
diff --git a/app/controllers/simulations.js b/app/controllers/simulations.js
index 9eaea92..0be9ecf 100644
--- a/app/controllers/simulations.js
+++ b/app/controllers/simulations.js
@@ -14,11 +14,12 @@ export default Ember.Controller.extend({
isShowingNewModal: false,
isShowingEditModal: false,
- isShowingEditModal: false,
+ isShowingDeleteModal: false,
errorMessage: null,
simulation: null,
+ simulationRunning: true,
actions: {
showNewModal() {
@@ -48,10 +49,19 @@ export default Ember.Controller.extend({
this.set('isShowingDeleteModal', true);
},
+ showRunningModal(simulation) {
+ // set properties
+ this.set('simulation', simulation);
+ this.set('simulationRunning', simulation.get('running'));
+
+ // show the dialog
+ this.set('isShowingRunningModal', true);
+ },
+
submitNew() {
// verify properties
var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] == "") {
+ if (properties['name'] == null || properties['name'] === "") {
this.set('errorMessage', 'Simulation name is missing');
return;
}
@@ -78,7 +88,7 @@ export default Ember.Controller.extend({
submitEdit() {
// verify properties
var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] == "") {
+ if (properties['name'] == null || properties['name'] === "") {
this.set('errorMessage', 'Simulation name is missing');
return;
}
@@ -110,6 +120,34 @@ export default Ember.Controller.extend({
cancelDelete() {
this.set('isShowingDeleteModal', false);
+ },
+
+ confirmRunningSimulation() {
+ // set the property
+ var simulation = this.get('simulation');
+ simulation.set('running', this.get('simulationRunning'));
+
+ // save property
+ var controller = this;
+
+ simulation.save().then(function() {
+ controller.set('isShowingRunningModal', false);
+ }, function() {
+ Ember.debug('Error saving running simulation');
+ });
+ },
+
+ cancelRunningSimulation() {
+ this.set('isShowingRunningModal', false);
+ },
+
+ selectRunning(running) {
+ // NOTE: running is a string and not a boolean value
+ if (running === 'true') {
+ this.set('simulationRunning', true);
+ } else {
+ this.set('simulationRunning', false);
+ }
}
}
});
diff --git a/app/controllers/simulators.js b/app/controllers/simulators.js
index af9cb28..2163e3c 100644
--- a/app/controllers/simulators.js
+++ b/app/controllers/simulators.js
@@ -13,12 +13,14 @@ export default Ember.Controller.extend({
isShowingNewModal: false,
isShowingDeleteModal: false,
isShowingEditModal: false,
+ isShowingRunningModal: false,
simulatorid: 1,
errorMessage: null,
simulator: null,
simulatorName: null,
simulatorEdit: null,
+ simulatorRunning: true,
actions: {
showNewModal() {
@@ -49,6 +51,15 @@ export default Ember.Controller.extend({
this.set('isShowingEditModal', true);
},
+ showRunningModal(simulator) {
+ // set properties
+ this.set('simulator', simulator);
+ this.set('simulatorRunning', simulator.get('running'));
+
+ // show the dialog
+ this.set('isShowingRunningModal', true);
+ },
+
newSimulator() {
// verify properties
var properties = this.getProperties('name', 'simulatorid', 'endpoint');
@@ -114,6 +125,34 @@ export default Ember.Controller.extend({
cancelEditSimulator() {
this.set('isShowingEditModal', false);
+ },
+
+ confirmRunningSimulation() {
+ // set the property
+ var simulator = this.get('simulator');
+ simulator.set('running', this.get('simulatorRunning'));
+
+ // save property
+ var controller = this;
+
+ simulator.save().then(function() {
+ controller.set('isShowingRunningModal', false);
+ }, function() {
+ Ember.debug('Error saving running simulator');
+ });
+ },
+
+ cancelRunningSimulation() {
+ this.set('isShowingRunningModal', false);
+ },
+
+ selectRunning(running) {
+ // NOTE: running is a string and not a boolean value
+ if (running === 'true') {
+ this.set('simulatorRunning', true);
+ } else {
+ this.set('simulatorRunning', false);
+ }
}
}
});
diff --git a/app/mixins/websocket-live-stream-mixin.js b/app/mixins/websocket-live-stream-mixin.js
index c225d6a..72d2200 100644
--- a/app/mixins/websocket-live-stream-mixin.js
+++ b/app/mixins/websocket-live-stream-mixin.js
@@ -13,43 +13,95 @@ import ENV from '../config/environment';
const { service } = Ember.inject;
export default Ember.Mixin.create({
- host: 'ws://' + ENV.APP.LIVE_HOST,
- namespace: '',
- runningSimulation: service('running-simulation'),
+ runningSimulations: service('running-simulations'),
+ store: service(),
- socket: null,
+ sockets: [],
init() {
this._super(...arguments);
- // start simulation service
- this.get('runningSimulation').loadRunningSimulation();
+ // load simulators
+ var self = this;
+
+ this.store.findAll('simulator').then(function() {
+ // start simulators service
+ self.get('runningSimulations').loadRunningSimulations();
+ });
},
- _runningSimulationChanged: function() {
- // called each time running simulation did change
- var simulation = this.get('runningSimulation.simulation');
- if (simulation !== null) {
- if (this.socket === null) {
- // create new socket connection
- this.socket = new WebSocket(this.host + this.namespace);
- this.socket.binaryType = 'arraybuffer';
+ _runningSimulationsChanged: function() {
+ // called each time running simulations did change
+ var self = this;
- // register callbacks
- var self = this;
- this.socket.onopen = function(event) { self.onopen.apply(self, [event]); };
- this.socket.onclose = function(event) { self.onclose.apply(self, [event]); };
- this.socket.onmessage = function(event) { self.onmessage.apply(self, [event]); };
- this.socket.onerror = function(event) { self.onerror.apply(self, [event]); };
+ this.get('runningSimulations.simulationModels').forEach(function(simulationModel) {
+ //console.log('Model: ' + simulationModel.get('name') + ' (' + simulationModel.get('simulator.name') + ')');
+
+ // get socket for simulation model
+ let modelid = simulationModel.get('id');
+ var socket = self._socketForSimulationModel(modelid);
+
+ // create new socket for simulation model if not running yet
+ if (socket == null) {
+ // try to create new socket
+ socket = new WebSocket('ws://' + simulationModel.get('simulator.endpoint'));
+ console.log('opened ' + simulationModel.get('simulator.endpoint'));
+
+ if (socket != null) {
+ socket.binaryType = 'arraybuffer';
+
+ // register callbacks
+ socket.onopen = function(event) { self.onopen.apply(self, [event]); };
+ socket.onclose = function(event) { self.onclose.apply(self, [event]); };
+ socket.onmessage = function(event) { self.onmessage.apply(self, [event]); };
+ socket.onerror = function(event) { self.onerror.apply(self, [event]); };
+
+ // save socket
+ self._addSocketForSimulationModel(socket, modelid);
+
+ console.log('simulation model \'' + simulationModel.get('name') + '\' started');
+ }
}
- } else {
- // stop stream if still opened
- if (this.socket !== null) {
- this.socket.close();
- this.socket = null;
+ });
+ }.observes('runningSimulations.simulationModels.@each.mod'),
+
+ _socketForSimulationModel(modelid) {
+ this.get('sockets').forEach(function(s) {
+ if (s.id === modelid) {
+ return s.socket;
+ }
+ });
+
+ return null;
+ },
+
+ _addSocketForSimulationModel(socket, modelid) {
+ // search for existing socket to replace
+ this.get('sockets').forEach(function(s) {
+ if (s.id === modelid) {
+ s.socket = socket;
+ return;
+ }
+ });
+
+ // add new socket
+ this.get('sockets').pushObject({ id: modelid, socket: socket });
+ },
+
+ _removeSocketForSimulationModel(modelid) {
+ var sockets = this.get('sockets');
+ var i = 0;
+
+ while (i < sockets.get('length')) {
+ if (sockets[i].id === modelid) {
+ // remove object from array
+ sockets.slice(i, 1);
+ } else {
+ // only increase index if no object was removed
+ i++;
}
}
- }.observes('runningSimulation.simulation'),
+ },
onopen(/*event*/) {
Ember.debug('websocket opened');
diff --git a/app/models/simulation-model.js b/app/models/simulation-model.js
index 9493dd9..199991a 100644
--- a/app/models/simulation-model.js
+++ b/app/models/simulation-model.js
@@ -13,7 +13,7 @@ import { belongsTo/*, hasMany*/ } from 'ember-data/relationships';
export default Model.extend({
name: attr('string'),
- simulator: attr('number'),
+ simulator: belongsTo('simulator', { async: true }),
length: attr('number'),
mapping: attr('array'),
simulation: belongsTo('simulation', { async: true })
diff --git a/app/routes/projects.js b/app/routes/projects.js
index cf7f030..9c31feb 100644
--- a/app/routes/projects.js
+++ b/app/routes/projects.js
@@ -14,8 +14,12 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
sessionUser: Ember.inject.service('session-user'),
model() {
- // get projects for current user
+ // get projects for current user, simulations are needed for the simulation picker
var user = this.get('sessionUser.user');
- return user.get('projects');
+
+ return Ember.RSVP.hash({
+ projects: user.get('projects'),
+ simulations: this.store.findAll('simulation')
+ });
}
});
diff --git a/app/routes/visualization/index.js b/app/routes/visualization/index.js
index 35a7beb..346c076 100644
--- a/app/routes/visualization/index.js
+++ b/app/routes/visualization/index.js
@@ -12,6 +12,9 @@ import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-rout
export default Ember.Route.extend(AuthenticatedRouteMixin, {
model(params) {
- return this.store.findRecord('visualization', params.visualizationid);
+ return Ember.RSVP.hash({
+ /*simulation: this.store.findRecord('simulation', params.simulationid),*/
+ visualization: this.store.findRecord('visualization', params.visualizationid)
+ });
}
});
diff --git a/app/services/running-simulation.js b/app/services/running-simulation.js
deleted file mode 100644
index 2d97597..0000000
--- a/app/services/running-simulation.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * File: running-simulation.js
- * Author: Markus Grigull
- * Date: 26.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-const {
- inject: { service }
-} = Ember;
-
-export default Ember.Service.extend({
- session: service('session'),
- store: service(),
-
- loadRunningSimulation: function() {
- var self = this;
-
- // check every second for running simulation
- /*
- setInterval(function() {
- // check if running simulation did changed
- self.get('store').findAll('simulation').then(function(simulations) {
- var newSimulation = null;
-
- simulations.forEach(function(simulation) {
- if (simulation.get('running') === true) {
- newSimulation = simulation;
- }
- });
-
- if (newSimulation !== self.get('simulation')) {
- self.set('simulation', newSimulation);
- }
- });
- }, 1000);*/
- }
-});
diff --git a/app/services/running-simulations.js b/app/services/running-simulations.js
new file mode 100644
index 0000000..8aef65c
--- /dev/null
+++ b/app/services/running-simulations.js
@@ -0,0 +1,64 @@
+/**
+ * File: running-simulations.js
+ * Author: Markus Grigull
+ * Date: 26.07.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import Ember from 'ember';
+
+const {
+ inject: { service }
+} = Ember;
+
+export default Ember.Service.extend({
+ session: service('session'),
+ sessionUser: Ember.inject.service('session-user'),
+ store: service(),
+
+ simulationModels: [],
+
+ loadRunningSimulations: function() {
+ var self = this;
+
+ // check for running simulations
+ setInterval(function() {
+ if (self.get('sessionUser.user') != null) {
+ // check if running simulations did changed
+ self.get('store').findAll('simulation').then(function(simulations) {
+ // search for running simulations
+ simulations.forEach(function(simulation) {
+ if (simulation.get('running') === true) {
+ // get all models of the simulation
+ simulation.get('models').forEach(function(model) {
+ self.get('store').findRecord('simulation-model', model.get('id')).then(function(m) {
+ // add to array
+ self._addSimulationModel(m);
+ });
+ });
+ } else {
+ // clear all models of the simulation
+ }
+ });
+ });
+ }
+ }, 3000);
+ },
+
+ _addSimulationModel(simulationModel) {
+ // check if the model is already in the array
+ var models = this.get('simulationModels');
+ var length = models.get('length');
+
+ for (var i = 0; i < length; i++) {
+ if (models[i].get('id') === simulationModel.get('id')) {
+ return;
+ }
+ }
+
+ // not found, so add to the array
+ this.get('simulationModels').pushObject(simulationModel);
+ }
+});
diff --git a/app/templates/projects.hbs b/app/templates/projects.hbs
index b4346fd..f544a78 100644
--- a/app/templates/projects.hbs
+++ b/app/templates/projects.hbs
@@ -4,13 +4,17 @@
Name
+ Simulation
- {{#each model as |project|}}
+ {{#each model.projects as |project|}}
{{#link-to "project.index" project.id}}{{project.name}}{{/link-to}}
+
+ {{project.simulation.name}}
+
Edit
@@ -40,6 +44,18 @@
{{input id='name' placeholder='Enter project name' value=name}}
+
+
+ Simulation
+
+
+
+ {{#each model.simulations as |simulation|}}
+ {{simulation.name}}
+ {{/each}}
+
+
+
Cancel
@@ -69,6 +85,18 @@
{{input id='name' placeholder='Enter project name' value=name}}
+
+
+ Simulation
+
+
+
+ {{#each model.simulations as |simulation|}}
+ {{simulation.name}}
+ {{/each}}
+
+
+
Cancel
diff --git a/app/templates/simulation/index.hbs b/app/templates/simulation/index.hbs
index 6a2efd5..3804575 100644
--- a/app/templates/simulation/index.hbs
+++ b/app/templates/simulation/index.hbs
@@ -6,7 +6,7 @@
Name
- Simulator
+ Simulator
{{#each model.simulation.models as |simulationModel|}}
@@ -14,8 +14,8 @@
{{#link-to "simulation-model.index" simulationModel.id}}{{simulationModel.name}}{{/link-to}}
-
- {{simulationModel.simulator}}
+
+ {{simulationModel.simulator.name}}
diff --git a/app/templates/simulations.hbs b/app/templates/simulations.hbs
index d94b085..fee2ede 100644
--- a/app/templates/simulations.hbs
+++ b/app/templates/simulations.hbs
@@ -5,7 +5,7 @@
Name
Running
-
+
{{#each model as |simulation|}}
@@ -17,8 +17,7 @@
@@ -100,3 +99,21 @@
Delete
{{/modal-dialog}}
{{/if}}
+
+{{#if isShowingRunningModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Simulation running
+
+ {{simulation.name}}:
+
+
+ running
+ not running
+
+
+
+
+ Cancel
+ Save
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/simulators.hbs b/app/templates/simulators.hbs
index ed099fd..d610d92 100644
--- a/app/templates/simulators.hbs
+++ b/app/templates/simulators.hbs
@@ -7,12 +7,12 @@
ID
Running
Endpoint
+
{{#each model as |simulator|}}
-
{{simulator.name}}
@@ -26,8 +26,7 @@
@@ -141,3 +140,21 @@
{{/if}}
{{/modal-dialog}}
{{/if}}
+
+{{#if isShowingRunningModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Simulator running
+
+ {{simulator.name}}:
+
+
+ running
+ not running
+
+
+
+
+ Cancel
+ Save
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/visualization/index.hbs b/app/templates/visualization/index.hbs
index b85b398..e7ff8f8 100644
--- a/app/templates/visualization/index.hbs
+++ b/app/templates/visualization/index.hbs
@@ -1,8 +1,9 @@
-{{model.name}}
+{{#link-to 'project.index' project.id}}Back to {{model.project.name}}{{/link-to}}
-{{plot-container plots=model.plots}}
+{{model.visualization.name}}
+
+{{plot-container plots=model.visualization.plots}}
- {{#link-to "visualization.edit" model.id}}Edit visualization{{/link-to}}
- {{#link-to "visualization.delete" model.id}}Delete visualization{{/link-to}}
+ {{#link-to "visualization.edit" model.visualization.id}}Edit layout{{/link-to}}
diff --git a/todo.md b/todo.md
index b0982cf..f730b0e 100644
--- a/todo.md
+++ b/todo.md
@@ -3,10 +3,10 @@
- Don't log out on unauthorized access (admin level lower than required)
- Move plot attributes/styling from plot-container into actual plots
- Move drag-n-drop to mixins
- - Websocket node is working in develop branch
- - Add API host to config/environment.js
- - Empty visualization after delete
- Go into edit mode if visualization is empty
+ - Auto-detect if simulators are running
+ - Remove running socket if it's not in the updated list
+ - Real relationship between simulation-model and simulator
websocketserverip/config.json
websocketserverip/nodes.json
From f2d494a1b0fbe2e529758540bffb6972cea31345 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Fri, 7 Oct 2016 10:21:32 +0200
Subject: [PATCH 027/556] Merge running-simulations and websocket mixin into
live-data mixin
---
app/mixins/live-data.js | 166 ++++++++++++++++++
app/mixins/websocket-live-stream-mixin.js | 160 -----------------
app/routes/index.js | 4 +-
app/services/running-simulations.js | 64 -------
tests/unit/mixins/live-data-test.js | 12 ++
.../websocket-live-stream-mixin-test.js | 12 --
.../unit/services/running-simulation-test.js | 12 --
7 files changed, 180 insertions(+), 250 deletions(-)
create mode 100644 app/mixins/live-data.js
delete mode 100644 app/mixins/websocket-live-stream-mixin.js
delete mode 100644 app/services/running-simulations.js
create mode 100644 tests/unit/mixins/live-data-test.js
delete mode 100644 tests/unit/mixins/websocket-live-stream-mixin-test.js
delete mode 100644 tests/unit/services/running-simulation-test.js
diff --git a/app/mixins/live-data.js b/app/mixins/live-data.js
new file mode 100644
index 0000000..4f28247
--- /dev/null
+++ b/app/mixins/live-data.js
@@ -0,0 +1,166 @@
+/**
+ * File: live-data.js
+ * Author: Markus Grigull
+ * Date: 06.10.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import Ember from 'ember';
+
+const { service } = Ember.inject;
+
+export default Ember.Mixin.create({
+ store: service(),
+ sessionUser: service('session-user'),
+
+ INTERVAL: 5000,
+
+ _sockets: [],
+
+ init: function() {
+ this._super();
+
+ // fetch the simulations for the first time
+ this._fetchRunningSimulations();
+
+ // start the polling loop
+ setInterval((function(self) {
+ return function() {
+ self._fetchRunningSimulations();
+ }
+ })(this), this.INTERVAL);
+ },
+
+ _fetchRunningSimulations: function() {
+ // check if the user is logged in
+ if (this.get('sessionUser.user') != null) {
+ // load simulators
+ var self = this;
+
+ this.get('store').findAll('simulator').then(function() {
+ // get all simulations to find all running ones
+ self.get('store').findAll('simulation').then(function(simulations) {
+ simulations.forEach(function(simulation) {
+ // check if the simulation is running
+ if (simulation.get('running')) {
+ // get all models
+ simulation.get('models').forEach(function(model) {
+ self.get('store').findRecord('simulation-model', model.get('id')).then(function(m) {
+ self._addSocket(m);
+ });
+ });
+ }
+ });
+ });
+ });
+ }
+ },
+
+ _addSocket(simulationModel) {
+ // search for existing socket
+ var length = this.get('_sockets').length;
+
+ for (var i = 0; i < length; i++) {
+ if (this.get('_sockets')[i].id === simulationModel.get('id')) {
+ // dont do anything
+ return;
+ }
+ }
+
+ // add new socket
+ var socket = new WebSocket('ws://' + simulationModel.get('simulator.endpoint'));
+ socket.binaryType = 'arraybuffer';
+
+ // register callbacks
+ var self = this;
+
+ socket.onopen = function(event) { self._onSocketOpen.apply(self, [event]); };
+ socket.onclose = function(event) { self._onSocketClose.apply(self, [event]); };
+ socket.onmessage = function(event) { self._onSocketMessage.apply(self, [event]); };
+ socket.onerror = function(event) { self._onSocketError.apply(self, [event]); };
+
+ this.get('_sockets').pushObject({ id: simulationModel.get('id'), socket: socket });
+
+ console.log('Socket created for ' + simulationModel.get('name') + ': ws://' + simulationModel.get('simulator.endpoint'));
+ },
+
+ _removeSocket(socket) {
+ var length = this.get('_sockets').length;
+ var i = 0;
+
+ while (i < length) {
+ if (this.get('_sockets')[i].socket === socket) {
+ // remove object from array
+ this.get('_sockets').slice(i, 1);
+ console.log('socket removed');
+ } else {
+ // increase index if no object was removed
+ i++;
+ }
+ }
+ },
+
+ _onSocketOpen(/* event */) {
+ Ember.debug('websocket opened');
+ },
+
+ _onSocketClose(event) {
+ if (event.wasClean) {
+
+ } else {
+ Ember.debug('websocket closed: ' + event.code);
+ }
+
+ // remove socket from array
+ this._removeSocket(event.target);
+ },
+
+ _onSocketMessage(event) {
+ // read the message into JSON
+ var message = this._messageToJSON(event.data);
+
+ var simulationData = this.store.peekRecord('simulation-data', message.simulator);
+ if (simulationData != null) {
+ simulationData.set('sequence', message.sequence);
+ simulationData.set('values', message.values);
+ } else {
+ this.store.createRecord('simulation-data', {
+ sequence: message.sequence,
+ values: message.values,
+ id: message.simulator
+ });
+ }
+ },
+
+ _onSocketError(/* event */) {
+ Ember.debug('websocket error');
+ },
+
+ _messageToJSON(blob) {
+ var data = new DataView(blob);
+
+ let OFFSET_ENDIAN = 1;
+ let OFFSET_TYPE = 2;
+ let OFFSET_VERSION = 4;
+
+ var bits = data.getUint8(0);
+ var simulator = data.getUint8(0x01);
+ var endian = (bits >> OFFSET_ENDIAN) & 0x1 ? 0 : 1;
+ var length = data.getUint16(0x02, endian);
+
+ var values = new Float32Array(data.buffer, data.byteOffset + 0x10, length);
+
+ return {
+ endian: endian,
+ version: (bits >> OFFSET_VERSION) & 0xF,
+ type: (bits >> OFFSET_TYPE) & 0x3,
+ length: length,
+ sequence: data.getUint32(0x04, endian),
+ timestamp: data.getUint32(0x08, endian) * 1e3 + data.getUint32(0x0C, endian) * 1e-6,
+ values: values,
+ simulator: simulator
+ };
+ }
+});
diff --git a/app/mixins/websocket-live-stream-mixin.js b/app/mixins/websocket-live-stream-mixin.js
deleted file mode 100644
index 72d2200..0000000
--- a/app/mixins/websocket-live-stream-mixin.js
+++ /dev/null
@@ -1,160 +0,0 @@
-/**
- * File: websocket-live-stream-mixin.js
- * Author: Markus Grigull
- * Date: 21.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import ENV from '../config/environment';
-
-const { service } = Ember.inject;
-
-export default Ember.Mixin.create({
- runningSimulations: service('running-simulations'),
- store: service(),
-
- sockets: [],
-
- init() {
- this._super(...arguments);
-
- // load simulators
- var self = this;
-
- this.store.findAll('simulator').then(function() {
- // start simulators service
- self.get('runningSimulations').loadRunningSimulations();
- });
- },
-
- _runningSimulationsChanged: function() {
- // called each time running simulations did change
- var self = this;
-
- this.get('runningSimulations.simulationModels').forEach(function(simulationModel) {
- //console.log('Model: ' + simulationModel.get('name') + ' (' + simulationModel.get('simulator.name') + ')');
-
- // get socket for simulation model
- let modelid = simulationModel.get('id');
- var socket = self._socketForSimulationModel(modelid);
-
- // create new socket for simulation model if not running yet
- if (socket == null) {
- // try to create new socket
- socket = new WebSocket('ws://' + simulationModel.get('simulator.endpoint'));
- console.log('opened ' + simulationModel.get('simulator.endpoint'));
-
- if (socket != null) {
- socket.binaryType = 'arraybuffer';
-
- // register callbacks
- socket.onopen = function(event) { self.onopen.apply(self, [event]); };
- socket.onclose = function(event) { self.onclose.apply(self, [event]); };
- socket.onmessage = function(event) { self.onmessage.apply(self, [event]); };
- socket.onerror = function(event) { self.onerror.apply(self, [event]); };
-
- // save socket
- self._addSocketForSimulationModel(socket, modelid);
-
- console.log('simulation model \'' + simulationModel.get('name') + '\' started');
- }
- }
- });
- }.observes('runningSimulations.simulationModels.@each.mod'),
-
- _socketForSimulationModel(modelid) {
- this.get('sockets').forEach(function(s) {
- if (s.id === modelid) {
- return s.socket;
- }
- });
-
- return null;
- },
-
- _addSocketForSimulationModel(socket, modelid) {
- // search for existing socket to replace
- this.get('sockets').forEach(function(s) {
- if (s.id === modelid) {
- s.socket = socket;
- return;
- }
- });
-
- // add new socket
- this.get('sockets').pushObject({ id: modelid, socket: socket });
- },
-
- _removeSocketForSimulationModel(modelid) {
- var sockets = this.get('sockets');
- var i = 0;
-
- while (i < sockets.get('length')) {
- if (sockets[i].id === modelid) {
- // remove object from array
- sockets.slice(i, 1);
- } else {
- // only increase index if no object was removed
- i++;
- }
- }
- },
-
- onopen(/*event*/) {
- Ember.debug('websocket opened');
- },
-
- onclose(event) {
- Ember.debug('websocket closed: ' + event.code);
- },
-
- onmessage(event) {
- // read the message into JSON
- var message = this._messageToJSON(event.data);
-
- var simulationData = this.store.peekRecord('simulation-data', message.simulator);
- if (simulationData != null) {
- simulationData.set('sequence', message.sequence);
- simulationData.set('values', message.values);
- } else {
- this.store.createRecord('simulation-data', {
- sequence: message.sequence,
- values: message.values,
- id: message.simulator
- });
- }
- },
-
- onerror(/*event*/) {
- Ember.debug('websocket error');
- },
-
- _messageToJSON(blob) {
- var data = new DataView(blob);
-
- let OFFSET_ENDIAN = 1;
- let OFFSET_TYPE = 2;
- let OFFSET_VERSION = 4;
-
- var bits = data.getUint8(0);
- var simulator = data.getUint8(0x01);
- var endian = (bits >> OFFSET_ENDIAN) & 0x1 ? 0 : 1;
- var length = data.getUint16(0x02, endian);
-
- var values = new Float32Array(data.buffer, data.byteOffset + 0x10, length);
-
- return {
- endian: endian,
- version: (bits >> OFFSET_VERSION) & 0xF,
- type: (bits >> OFFSET_TYPE) & 0x3,
- length: length,
- sequence: data.getUint32(0x04, endian),
- timestamp: data.getUint32(0x08, endian) * 1e3 + data.getUint32(0x0C, endian) * 1e-6,
- values: values,
- simulator: simulator
- };
- }
-});
diff --git a/app/routes/index.js b/app/routes/index.js
index ab4ab0a..ca13931 100644
--- a/app/routes/index.js
+++ b/app/routes/index.js
@@ -9,7 +9,7 @@
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-import WebsocketLiveStreamMixin from '../mixins/websocket-live-stream-mixin';
+import LiveDataMixin from '../mixins/live-data';
-export default Ember.Route.extend(AuthenticatedRouteMixin, WebsocketLiveStreamMixin, {
+export default Ember.Route.extend(AuthenticatedRouteMixin, LiveDataMixin, {
});
diff --git a/app/services/running-simulations.js b/app/services/running-simulations.js
deleted file mode 100644
index 8aef65c..0000000
--- a/app/services/running-simulations.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * File: running-simulations.js
- * Author: Markus Grigull
- * Date: 26.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-const {
- inject: { service }
-} = Ember;
-
-export default Ember.Service.extend({
- session: service('session'),
- sessionUser: Ember.inject.service('session-user'),
- store: service(),
-
- simulationModels: [],
-
- loadRunningSimulations: function() {
- var self = this;
-
- // check for running simulations
- setInterval(function() {
- if (self.get('sessionUser.user') != null) {
- // check if running simulations did changed
- self.get('store').findAll('simulation').then(function(simulations) {
- // search for running simulations
- simulations.forEach(function(simulation) {
- if (simulation.get('running') === true) {
- // get all models of the simulation
- simulation.get('models').forEach(function(model) {
- self.get('store').findRecord('simulation-model', model.get('id')).then(function(m) {
- // add to array
- self._addSimulationModel(m);
- });
- });
- } else {
- // clear all models of the simulation
- }
- });
- });
- }
- }, 3000);
- },
-
- _addSimulationModel(simulationModel) {
- // check if the model is already in the array
- var models = this.get('simulationModels');
- var length = models.get('length');
-
- for (var i = 0; i < length; i++) {
- if (models[i].get('id') === simulationModel.get('id')) {
- return;
- }
- }
-
- // not found, so add to the array
- this.get('simulationModels').pushObject(simulationModel);
- }
-});
diff --git a/tests/unit/mixins/live-data-test.js b/tests/unit/mixins/live-data-test.js
new file mode 100644
index 0000000..804897f
--- /dev/null
+++ b/tests/unit/mixins/live-data-test.js
@@ -0,0 +1,12 @@
+import Ember from 'ember';
+import LiveDataMixin from 'villasweb-frontend/mixins/live-data';
+import { module, test } from 'qunit';
+
+module('Unit | Mixin | live data');
+
+// Replace this with your real tests.
+test('it works', function(assert) {
+ let LiveDataObject = Ember.Object.extend(LiveDataMixin);
+ let subject = LiveDataObject.create();
+ assert.ok(subject);
+});
diff --git a/tests/unit/mixins/websocket-live-stream-mixin-test.js b/tests/unit/mixins/websocket-live-stream-mixin-test.js
deleted file mode 100644
index 7cc9580..0000000
--- a/tests/unit/mixins/websocket-live-stream-mixin-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Ember from 'ember';
-import WebsocketLiveStreamMixinMixin from 'villasweb-frontend/mixins/websocket-live-stream-mixin';
-import { module, test } from 'qunit';
-
-module('Unit | Mixin | websocket live stream mixin');
-
-// Replace this with your real tests.
-test('it works', function(assert) {
- let WebsocketLiveStreamMixinObject = Ember.Object.extend(WebsocketLiveStreamMixinMixin);
- let subject = WebsocketLiveStreamMixinObject.create();
- assert.ok(subject);
-});
diff --git a/tests/unit/services/running-simulation-test.js b/tests/unit/services/running-simulation-test.js
deleted file mode 100644
index f74cde8..0000000
--- a/tests/unit/services/running-simulation-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('service:running-simulation', 'Unit | Service | running simulation', {
- // Specify the other units that are required for this test.
- // needs: ['service:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let service = this.subject();
- assert.ok(service);
-});
From 59c9438ce13e6f83b37826ddb16d37a54676b03d Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 12 Oct 2016 08:30:15 +0200
Subject: [PATCH 028/556] Add live data flow from visualization to plots
Fix live-data mixin
---
app/components/plot-abstract.js | 3 +-
app/components/plot-container.js | 5 ++
app/components/plot-value.js | 18 +++-
app/controllers/visualization/index.js | 61 ++++++++++++++
app/mixins/live-data.js | 93 +++++++++++----------
app/routes/visualization/index.js | 5 +-
app/templates/components/plot-container.hbs | 2 +-
app/templates/components/plot-value.hbs | 32 +------
app/templates/visualization/index.hbs | 8 +-
config/environment.js | 3 +-
10 files changed, 140 insertions(+), 90 deletions(-)
diff --git a/app/components/plot-abstract.js b/app/components/plot-abstract.js
index f8a7b51..9192ef8 100644
--- a/app/components/plot-abstract.js
+++ b/app/components/plot-abstract.js
@@ -19,8 +19,9 @@ export default Ember.Component.extend(Resizable, Draggable, {
plot: null,
editing: false,
grid: false,
+ data: null,
- simulator: 0,
+ simulator: 0
disabled_resize: false,
autoHide_resize: false,
diff --git a/app/components/plot-container.js b/app/components/plot-container.js
index 9556975..df4d908 100644
--- a/app/components/plot-container.js
+++ b/app/components/plot-container.js
@@ -17,6 +17,7 @@ export default Ember.Component.extend({
plots: null,
editing: false,
grid: true,
+ data: null,
style: function() {
var height = this._calculateHeight();
@@ -27,6 +28,10 @@ export default Ember.Component.extend({
return Ember.String.htmlSafe('height: ' + height + 'px;');
}.property('plots.@each.height', 'plots.@each.y'),
+ _value: function() {
+ console.log(this.get('data'));
+ }.property('data.2.values.@each'),
+
_calculateHeight() {
var maxHeight = 0;
var plots = this.get('plots');
diff --git a/app/components/plot-value.js b/app/components/plot-value.js
index 2c91b59..09bb9d1 100644
--- a/app/components/plot-value.js
+++ b/app/components/plot-value.js
@@ -13,5 +13,21 @@ export default PlotAbstract.extend({
classNames: [ 'plotValue' ],
minWidth_resize: 50,
- minHeight_resize: 20
+ minHeight_resize: 20,
+
+ simulator: 2,
+ signal: 1,
+
+ value: function() {
+ // get all values for the choosen simulator
+ let values = this.get('data.' + this.get('simulator') + '.values');
+ if (values) {
+ return values[this.get('signal')];
+ }
+
+ // values is null, try to reload later
+ Ember.run.later(this, function() {
+ this.notifyPropertyChange('data.' + this.get('simulator') + '.values');
+ }, 1000);
+ }.property('data.2.values')
});
diff --git a/app/controllers/visualization/index.js b/app/controllers/visualization/index.js
index bfe1beb..9da9763 100644
--- a/app/controllers/visualization/index.js
+++ b/app/controllers/visualization/index.js
@@ -10,4 +10,65 @@
import Ember from 'ember';
export default Ember.Controller.extend({
+ data: {},
+
+ /*values: function() {
+ console.log('update');
+ return this.get('data');
+ }.property('data.2.values'),*/
+
+ _getData: function() {
+ // check if simulation is running
+ let self = this;
+
+ this.get('model.project').then((project) => {
+ project.get('simulation').then((simulation) => {
+ if (simulation.get('running')) {
+ // get all models to access data
+ simulation.get('models').then((simulationModels) => {
+ simulationModels.forEach(function(simulationModel) {
+ // get simulator
+ simulationModel.get('simulator').then((simulator) => {
+ let simulatorID = simulator.get('simulatorid');
+ if (simulatorID) {
+ // add simulation data to list
+ self._loadDataForSimulator(simulatorID);
+ } else {
+ Ember.debug('undefined simulator id');
+ }
+ });
+ });
+ });
+ } else {
+ // clear simulation data
+ this.set('data', {});
+
+ //Ember.debug('Simulation not running');
+
+ // check again if simulation is running
+ Ember.run.later(this, function() {
+ // trigger _getData observer
+ this.notifyPropertyChange('model');
+ }, 1000);
+ }
+ });
+ });
+ }.observes('model'),
+
+ _loadDataForSimulator(simulatorID) {
+ // get data by simulator id
+ let simulationData = this.store.peekRecord('simulation-data', simulatorID);
+ if (simulationData) {
+ // add data to list
+ this.get('data')[simulatorID] = simulationData;
+
+ // notify object for property changes
+ this.notifyPropertyChange('data.' + simulatorID + '.values');
+ } else {
+ // try to load data later
+ Ember.run.later(this, function() {
+ this._loadDataForSimulator(simulatorID);
+ }, 1000);
+ }
+ }
});
diff --git a/app/mixins/live-data.js b/app/mixins/live-data.js
index 4f28247..54d9323 100644
--- a/app/mixins/live-data.js
+++ b/app/mixins/live-data.js
@@ -17,7 +17,7 @@ export default Ember.Mixin.create({
INTERVAL: 5000,
- _sockets: [],
+ _sockets: {},
init: function() {
this._super();
@@ -36,79 +36,79 @@ export default Ember.Mixin.create({
_fetchRunningSimulations: function() {
// check if the user is logged in
if (this.get('sessionUser.user') != null) {
- // load simulators
+ // get all simulations to find all running ones
var self = this;
- this.get('store').findAll('simulator').then(function() {
- // get all simulations to find all running ones
- self.get('store').findAll('simulation').then(function(simulations) {
- simulations.forEach(function(simulation) {
- // check if the simulation is running
- if (simulation.get('running')) {
- // get all models
- simulation.get('models').forEach(function(model) {
- self.get('store').findRecord('simulation-model', model.get('id')).then(function(m) {
- self._addSocket(m);
- });
+ this.get('store').findAll('simulation').then(function(simulations) {
+ simulations.forEach(function(simulation) {
+ // check if the simulation is running
+ if (simulation.get('running')) {
+ // get all models for this simulation
+ simulation.get('models').then((models) => {
+ models.forEach(function(simulationModel) {
+ self._addSocket(simulationModel);
});
- }
- });
+ });
+ }
});
});
}
},
_addSocket(simulationModel) {
- // search for existing socket
- var length = this.get('_sockets').length;
-
- for (var i = 0; i < length; i++) {
- if (this.get('_sockets')[i].id === simulationModel.get('id')) {
- // dont do anything
- return;
- }
+ // check if socket is already open
+ let id = simulationModel.get('id');
+ if (this.get('_sockets')[id] !== undefined) {
+ //Ember.debug('skip ' + simulationModel.get('name'));
+ return;
}
- // add new socket
- var socket = new WebSocket('ws://' + simulationModel.get('simulator.endpoint'));
- socket.binaryType = 'arraybuffer';
+ // get simulator endpoint
+ simulationModel.get('simulator').then((simulator) => {
+ // get simulator endpoint
+ let endpoint = simulator.get('endpoint');
+ if (endpoint) {
+ // add new socket
+ let socket = new WebSocket('ws://' + endpoint);
+ socket.binaryType = 'arraybuffer';
- // register callbacks
- var self = this;
+ // register callbacks
+ let self = this;
- socket.onopen = function(event) { self._onSocketOpen.apply(self, [event]); };
- socket.onclose = function(event) { self._onSocketClose.apply(self, [event]); };
- socket.onmessage = function(event) { self._onSocketMessage.apply(self, [event]); };
- socket.onerror = function(event) { self._onSocketError.apply(self, [event]); };
+ socket.onopen = function(event) { self._onSocketOpen.apply(self, [event]); };
+ socket.onclose = function(event) { self._onSocketClose.apply(self, [event]); };
+ socket.onmessage = function(event) { self._onSocketMessage.apply(self, [event]); };
+ socket.onerror = function(event) { self._onSocketError.apply(self, [event]); };
- this.get('_sockets').pushObject({ id: simulationModel.get('id'), socket: socket });
+ // add socket to list of known sockets
+ this.get('_sockets')[id] = socket;
- console.log('Socket created for ' + simulationModel.get('name') + ': ws://' + simulationModel.get('simulator.endpoint'));
+ //Ember.debug('Socket created for ' + simulationModel.get('name') + ': ws://' + endpoint);
+ } else {
+ Ember.debug('Undefined endpoint for ' + simulationModel.get('name'));
+ }
+ });
},
_removeSocket(socket) {
- var length = this.get('_sockets').length;
- var i = 0;
+ // search through all sockets
+ let sockets = this.get('_sockets');
- while (i < length) {
- if (this.get('_sockets')[i].socket === socket) {
- // remove object from array
- this.get('_sockets').slice(i, 1);
- console.log('socket removed');
- } else {
- // increase index if no object was removed
- i++;
+ for (let id in sockets) {
+ if (sockets[id] === socket) {
+ // remove socket from list
+ delete sockets[id];
}
}
},
_onSocketOpen(/* event */) {
- Ember.debug('websocket opened');
+ //Ember.debug('websocket opened');
},
_onSocketClose(event) {
if (event.wasClean) {
-
+ Ember.debug('websocket closed');
} else {
Ember.debug('websocket closed: ' + event.code);
}
@@ -139,6 +139,7 @@ export default Ember.Mixin.create({
},
_messageToJSON(blob) {
+ // parse incoming message into usable data
var data = new DataView(blob);
let OFFSET_ENDIAN = 1;
diff --git a/app/routes/visualization/index.js b/app/routes/visualization/index.js
index 346c076..35a7beb 100644
--- a/app/routes/visualization/index.js
+++ b/app/routes/visualization/index.js
@@ -12,9 +12,6 @@ import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-rout
export default Ember.Route.extend(AuthenticatedRouteMixin, {
model(params) {
- return Ember.RSVP.hash({
- /*simulation: this.store.findRecord('simulation', params.simulationid),*/
- visualization: this.store.findRecord('visualization', params.visualizationid)
- });
+ return this.store.findRecord('visualization', params.visualizationid);
}
});
diff --git a/app/templates/components/plot-container.hbs b/app/templates/components/plot-container.hbs
index 2c29da4..110a95e 100644
--- a/app/templates/components/plot-container.hbs
+++ b/app/templates/components/plot-container.hbs
@@ -1,3 +1,3 @@
{{#each plots as |plot|}}
- {{component plot.type plot=plot editing=editing grid=grid}}
+ {{component plot.type plot=plot editing=editing grid=grid data=data}}
{{/each}}
diff --git a/app/templates/components/plot-value.hbs b/app/templates/components/plot-value.hbs
index 74d6f2a..9ad31d4 100644
--- a/app/templates/components/plot-value.hbs
+++ b/app/templates/components/plot-value.hbs
@@ -1,31 +1 @@
-Value
-
-
-
-
-
-
-
- Simulator
-
-
- {{input id='simulator' type='number' value=plot.simulator min=1 max=255 width='60px'}}
-
-
-
-
- Signal
-
-
- {{input id='signal' value=plot.signal}}
-
-
-
-
- Save
-
-
-
-
-
-
+Value: {{value}}
diff --git a/app/templates/visualization/index.hbs b/app/templates/visualization/index.hbs
index e7ff8f8..64334da 100644
--- a/app/templates/visualization/index.hbs
+++ b/app/templates/visualization/index.hbs
@@ -1,9 +1,9 @@
-{{#link-to 'project.index' project.id}}Back to {{model.project.name}}{{/link-to}}
+{{#link-to 'project.index' model.project.id}}Back to {{model.project.name}}{{/link-to}}
-{{model.visualization.name}}
+{{model.name}}
-{{plot-container plots=model.visualization.plots}}
+{{plot-container plots=model.plots data=data}}
- {{#link-to "visualization.edit" model.visualization.id}}Edit layout{{/link-to}}
+ {{#link-to "visualization.edit" model.id}}Edit layout{{/link-to}}
diff --git a/config/environment.js b/config/environment.js
index b440274..f359e20 100644
--- a/config/environment.js
+++ b/config/environment.js
@@ -14,8 +14,7 @@ module.exports = function(environment) {
},
APP: {
- API_HOST: 'localhost:3000',
- LIVE_HOST: 'localhost:4000'
+ API_HOST: 'localhost:3000'
}
};
From f8028d88b7d787e192feb3e22aeab22da4153b6e Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 12 Oct 2016 09:10:41 +0200
Subject: [PATCH 029/556] Move visualization data to mixin
Add live data to edit visualization
Fix stylesheet files
---
app/components/plot-abstract.js | 2 +-
app/controllers/visualization/edit.js | 3 +-
app/controllers/visualization/index.js | 63 +----------------
app/mixins/fetch-live-data.js | 69 +++++++++++++++++++
app/mixins/live-data.js | 2 +-
app/styles/app.scss | 10 +--
app/styles/{models.css => models.scss} | 0
app/styles/{plots.css => plots.scss} | 0
app/styles/{projects.css => projects.scss} | 2 +-
.../{simulations.css => simulations.scss} | 0
.../{simulators.css => simulators.scss} | 0
app/templates/visualization/edit.hbs | 2 +-
tests/unit/mixins/fetch-live-data-test.js | 12 ++++
13 files changed, 94 insertions(+), 71 deletions(-)
create mode 100644 app/mixins/fetch-live-data.js
rename app/styles/{models.css => models.scss} (100%)
rename app/styles/{plots.css => plots.scss} (100%)
rename app/styles/{projects.css => projects.scss} (97%)
rename app/styles/{simulations.css => simulations.scss} (100%)
rename app/styles/{simulators.css => simulators.scss} (100%)
create mode 100644 tests/unit/mixins/fetch-live-data-test.js
diff --git a/app/components/plot-abstract.js b/app/components/plot-abstract.js
index 9192ef8..9b6377d 100644
--- a/app/components/plot-abstract.js
+++ b/app/components/plot-abstract.js
@@ -21,7 +21,7 @@ export default Ember.Component.extend(Resizable, Draggable, {
grid: false,
data: null,
- simulator: 0
+ simulator: 0,
disabled_resize: false,
autoHide_resize: false,
diff --git a/app/controllers/visualization/edit.js b/app/controllers/visualization/edit.js
index 063bd58..f9eaae7 100644
--- a/app/controllers/visualization/edit.js
+++ b/app/controllers/visualization/edit.js
@@ -8,8 +8,9 @@
**********************************************************************************/
import Ember from 'ember';
+import FetchLiveDataMixin from '../../mixins/fetch-live-data';
-export default Ember.Controller.extend({
+export default Ember.Controller.extend(FetchLiveDataMixin, {
actions: {
addPlot(name) {
var plot = null;
diff --git a/app/controllers/visualization/index.js b/app/controllers/visualization/index.js
index 9da9763..bf51cbe 100644
--- a/app/controllers/visualization/index.js
+++ b/app/controllers/visualization/index.js
@@ -8,67 +8,8 @@
**********************************************************************************/
import Ember from 'ember';
+import FetchLiveDataMixin from '../../mixins/fetch-live-data';
-export default Ember.Controller.extend({
- data: {},
+export default Ember.Controller.extend(FetchLiveDataMixin, {
- /*values: function() {
- console.log('update');
- return this.get('data');
- }.property('data.2.values'),*/
-
- _getData: function() {
- // check if simulation is running
- let self = this;
-
- this.get('model.project').then((project) => {
- project.get('simulation').then((simulation) => {
- if (simulation.get('running')) {
- // get all models to access data
- simulation.get('models').then((simulationModels) => {
- simulationModels.forEach(function(simulationModel) {
- // get simulator
- simulationModel.get('simulator').then((simulator) => {
- let simulatorID = simulator.get('simulatorid');
- if (simulatorID) {
- // add simulation data to list
- self._loadDataForSimulator(simulatorID);
- } else {
- Ember.debug('undefined simulator id');
- }
- });
- });
- });
- } else {
- // clear simulation data
- this.set('data', {});
-
- //Ember.debug('Simulation not running');
-
- // check again if simulation is running
- Ember.run.later(this, function() {
- // trigger _getData observer
- this.notifyPropertyChange('model');
- }, 1000);
- }
- });
- });
- }.observes('model'),
-
- _loadDataForSimulator(simulatorID) {
- // get data by simulator id
- let simulationData = this.store.peekRecord('simulation-data', simulatorID);
- if (simulationData) {
- // add data to list
- this.get('data')[simulatorID] = simulationData;
-
- // notify object for property changes
- this.notifyPropertyChange('data.' + simulatorID + '.values');
- } else {
- // try to load data later
- Ember.run.later(this, function() {
- this._loadDataForSimulator(simulatorID);
- }, 1000);
- }
- }
});
diff --git a/app/mixins/fetch-live-data.js b/app/mixins/fetch-live-data.js
new file mode 100644
index 0000000..811f104
--- /dev/null
+++ b/app/mixins/fetch-live-data.js
@@ -0,0 +1,69 @@
+/**
+ * File: fetch-live-data.js
+ * Author: Markus Grigull
+ * Date: 12.10.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import Ember from 'ember';
+
+export default Ember.Mixin.create({
+ data: {},
+
+ _getData: function() {
+ // check if simulation is running
+ let self = this;
+
+ this.get('model.project').then((project) => {
+ project.get('simulation').then((simulation) => {
+ if (simulation.get('running')) {
+ // get all models to access data
+ simulation.get('models').then((simulationModels) => {
+ simulationModels.forEach(function(simulationModel) {
+ // get simulator
+ simulationModel.get('simulator').then((simulator) => {
+ let simulatorID = simulator.get('simulatorid');
+ if (simulatorID) {
+ // add simulation data to list
+ self._loadDataForSimulator(simulatorID);
+ } else {
+ Ember.debug('undefined simulator id');
+ }
+ });
+ });
+ });
+ } else {
+ // clear simulation data
+ this.set('data', {});
+
+ //Ember.debug('Simulation not running');
+
+ // check again if simulation is running
+ Ember.run.later(this, function() {
+ // trigger _getData observer
+ this.notifyPropertyChange('model');
+ }, 1000);
+ }
+ });
+ });
+ }.observes('model'),
+
+ _loadDataForSimulator(simulatorID) {
+ // get data by simulator id
+ let simulationData = this.store.peekRecord('simulation-data', simulatorID);
+ if (simulationData) {
+ // add data to list
+ this.get('data')[simulatorID] = simulationData;
+
+ // notify object for property changes
+ this.notifyPropertyChange('data.' + simulatorID + '.values');
+ } else {
+ // try to load data later
+ Ember.run.later(this, function() {
+ this._loadDataForSimulator(simulatorID);
+ }, 1000);
+ }
+ }
+});
diff --git a/app/mixins/live-data.js b/app/mixins/live-data.js
index 54d9323..139b77d 100644
--- a/app/mixins/live-data.js
+++ b/app/mixins/live-data.js
@@ -29,7 +29,7 @@ export default Ember.Mixin.create({
setInterval((function(self) {
return function() {
self._fetchRunningSimulations();
- }
+ };
})(this), this.INTERVAL);
},
diff --git a/app/styles/app.scss b/app/styles/app.scss
index c740665..3c17c3b 100644
--- a/app/styles/app.scss
+++ b/app/styles/app.scss
@@ -7,11 +7,11 @@
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-@import 'plots.css';
-@import 'models.css';
-@import 'simulations.css';
-@import 'projects.css';
-@import 'simulators.css';
+@import 'plots';
+@import 'models';
+@import 'simulations';
+@import 'projects';
+@import 'simulators';
@import "ember-modal-dialog/ember-modal-structure";
@import "ember-modal-dialog/ember-modal-appearance";
diff --git a/app/styles/models.css b/app/styles/models.scss
similarity index 100%
rename from app/styles/models.css
rename to app/styles/models.scss
diff --git a/app/styles/plots.css b/app/styles/plots.scss
similarity index 100%
rename from app/styles/plots.css
rename to app/styles/plots.scss
diff --git a/app/styles/projects.css b/app/styles/projects.scss
similarity index 97%
rename from app/styles/projects.css
rename to app/styles/projects.scss
index 43f0f1b..5f4e5ec 100644
--- a/app/styles/projects.css
+++ b/app/styles/projects.scss
@@ -38,7 +38,7 @@
}
.project-index-row-controls a {
- margin:left: 10px;
+ margin-left: 10px;
}
.project-index-new-visualization {
diff --git a/app/styles/simulations.css b/app/styles/simulations.scss
similarity index 100%
rename from app/styles/simulations.css
rename to app/styles/simulations.scss
diff --git a/app/styles/simulators.css b/app/styles/simulators.scss
similarity index 100%
rename from app/styles/simulators.css
rename to app/styles/simulators.scss
diff --git a/app/templates/visualization/edit.hbs b/app/templates/visualization/edit.hbs
index ea00cf5..80e78f3 100644
--- a/app/templates/visualization/edit.hbs
+++ b/app/templates/visualization/edit.hbs
@@ -16,7 +16,7 @@
{{#draggable-dropzone dropped='addPlot'}}
- {{plot-container plots=model.plots editing=true}}
+ {{plot-container plots=model.plots editing=true data=data}}
{{/draggable-dropzone}}
diff --git a/tests/unit/mixins/fetch-live-data-test.js b/tests/unit/mixins/fetch-live-data-test.js
new file mode 100644
index 0000000..de5b41e
--- /dev/null
+++ b/tests/unit/mixins/fetch-live-data-test.js
@@ -0,0 +1,12 @@
+import Ember from 'ember';
+import FetchLiveDataMixin from 'villasweb-frontend/mixins/fetch-live-data';
+import { module, test } from 'qunit';
+
+module('Unit | Mixin | fetch live data');
+
+// Replace this with your real tests.
+test('it works', function(assert) {
+ let FetchLiveDataObject = Ember.Object.extend(FetchLiveDataMixin);
+ let subject = FetchLiveDataObject.create();
+ assert.ok(subject);
+});
From ddea7e5e326e83b6a361cac7e787216b17f9056a Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 12 Oct 2016 11:29:09 +0200
Subject: [PATCH 030/556] Add plot value dialog
---
app/components/plot-abstract.js | 57 ++--------
app/components/plot-container.js | 6 +
app/components/plot-value.js | 11 +-
app/controllers/visualization/edit.js | 56 ++++++++-
app/models/plot.js | 2 +-
app/router.js | 4 +
app/templates/components/plot-container.hbs | 2 +-
app/templates/components/plot-value.hbs | 2 +-
app/templates/dialog/plot/value.hbs | 44 ++++++++
app/templates/dialog/project.hbs | 68 +++++++++++
app/templates/dialog/projects.hbs | 92 +++++++++++++++
app/templates/dialog/simulation.hbs | 92 +++++++++++++++
app/templates/dialog/simulations.hbs | 86 ++++++++++++++
app/templates/dialog/simulators.hbs | 118 +++++++++++++++++++
app/templates/project/index.hbs | 69 +-----------
app/templates/projects.hbs | 93 +--------------
app/templates/simulation/index.hbs | 93 +--------------
app/templates/simulations.hbs | 87 +-------------
app/templates/simulators.hbs | 119 +-------------------
app/templates/visualization/edit.hbs | 4 +-
20 files changed, 589 insertions(+), 516 deletions(-)
create mode 100644 app/templates/dialog/plot/value.hbs
create mode 100644 app/templates/dialog/project.hbs
create mode 100644 app/templates/dialog/projects.hbs
create mode 100644 app/templates/dialog/simulation.hbs
create mode 100644 app/templates/dialog/simulations.hbs
create mode 100644 app/templates/dialog/simulators.hbs
diff --git a/app/components/plot-abstract.js b/app/components/plot-abstract.js
index 9b6377d..eded6a2 100644
--- a/app/components/plot-abstract.js
+++ b/app/components/plot-abstract.js
@@ -21,8 +21,6 @@ export default Ember.Component.extend(Resizable, Draggable, {
grid: false,
data: null,
- simulator: 0,
-
disabled_resize: false,
autoHide_resize: false,
grid_resize: [ 10, 10 ],
@@ -32,43 +30,14 @@ export default Ember.Component.extend(Resizable, Draggable, {
grid_drag: [ 10, 10 ],
scroll_drag: true,
- _popoverDisplayed: false,
-
- didInsertElement() {
- this._super();
-
- if (this.get('editing') === true) {
- // create popover
- var self = this;
-
- this.$().popover({
- html: true,
- placement: 'auto right',
- content: function () {
- return self.$('.popover-content').html();
- },
- viewport: { selector: '.plots', padding: 10 }
- });
-
- // register popover events
- this.$().on('show.bs.popover', function() {
-
- });
-
- this.$().on('shown.bs.popover', function() {
- self._popoverDisplayed = true;
- });
-
- this.$().on('hide.bs.popover', function() {
- self._popoverDisplayed = false;
- });
- }
- },
-
style: function() {
return Ember.String.htmlSafe('width: ' + this.get('plot.width') + 'px; height: ' + this.get('plot.height') + 'px; left: ' + this.get('plot.x') + 'px; top: ' + this.get('plot.y') + 'px;');
}.property('plot'),
+ name: function() {
+ return this.get('plot.name');
+ }.property('plot'),
+
stop_resize(event, ui) {
var width = ui.size.width;
var height = ui.size.height;
@@ -77,10 +46,8 @@ export default Ember.Component.extend(Resizable, Draggable, {
this.set('plot.height', height);
},
- resize_resize(event, ui) {
- if (this._popoverDisplayed === true) {
- this.$().popover('show');
- }
+ resize_resize(/* event, ui */) {
+
},
stop_drag(event, ui) {
@@ -88,10 +55,8 @@ export default Ember.Component.extend(Resizable, Draggable, {
this.set('plot.y', ui.position.top);
},
- drag_drag(event, ui) {
- if (this._popoverDisplayed === true) {
- this.$().popover('show');
- }
+ drag_drag(/* event, ui */) {
+
},
_updateUI: function() {
@@ -114,9 +79,9 @@ export default Ember.Component.extend(Resizable, Draggable, {
}
}.observes('editing', 'grid').on('init'),
- actions: {
- savePlot() {
- this.$().popover('hide');
+ doubleClick() {
+ if (this.get('editing')) {
+ this.sendAction('showPlotDialog', this.get('plot'));
}
}
});
diff --git a/app/components/plot-container.js b/app/components/plot-container.js
index df4d908..5f758c3 100644
--- a/app/components/plot-container.js
+++ b/app/components/plot-container.js
@@ -47,5 +47,11 @@ export default Ember.Component.extend({
maxHeight += 40;
return maxHeight;
+ },
+
+ actions: {
+ showPlotDialog(plot) {
+ this.sendAction('showPlotDialog', plot);
+ }
}
});
diff --git a/app/components/plot-value.js b/app/components/plot-value.js
index 09bb9d1..338d900 100644
--- a/app/components/plot-value.js
+++ b/app/components/plot-value.js
@@ -15,19 +15,16 @@ export default PlotAbstract.extend({
minWidth_resize: 50,
minHeight_resize: 20,
- simulator: 2,
- signal: 1,
-
value: function() {
// get all values for the choosen simulator
- let values = this.get('data.' + this.get('simulator') + '.values');
+ let values = this.get('data.' + this.get('plot.simulator') + '.values');
if (values) {
- return values[this.get('signal')];
+ return values[this.get('plot.signal')];
}
// values is null, try to reload later
Ember.run.later(this, function() {
- this.notifyPropertyChange('data.' + this.get('simulator') + '.values');
+ this.notifyPropertyChange('data.' + this.get('plot.simulator') + '.values');
}, 1000);
- }.property('data.2.values')
+ }.property('data.2.values', 'plot.simulator', 'plot.signal')
});
diff --git a/app/controllers/visualization/edit.js b/app/controllers/visualization/edit.js
index f9eaae7..c864a5a 100644
--- a/app/controllers/visualization/edit.js
+++ b/app/controllers/visualization/edit.js
@@ -11,17 +11,26 @@ import Ember from 'ember';
import FetchLiveDataMixin from '../../mixins/fetch-live-data';
export default Ember.Controller.extend(FetchLiveDataMixin, {
+ isShowingPlotValueModal: false,
+
+ errorMessage: null,
+
+ plot: null,
+ name: null,
+ simulator: null,
+ signal: null,
+
actions: {
addPlot(name) {
var plot = null;
if (name === 'chart') {
// create new chart plot
- plot = this.store.createRecord('plot', { name: 'Chart 1', signal: 'Signal 1', type: 'plot-chart' });
+ plot = this.store.createRecord('plot', { name: 'Chart 1', type: 'plot-chart' });
} else if (name === 'table') {
- plot = this.store.createRecord('plot', { name: 'Table 1', signal: 'Signal 1', type: 'plot-table', width: 500, height: 200, title: 'Table 1' });
+ plot = this.store.createRecord('plot', { name: 'Table 1', type: 'plot-table', width: 500, height: 200, title: 'Table 1' });
} else if (name === 'value') {
- plot = this.store.createRecord('plot', { name: 'Value 1', signal: 'Signal 1', type: 'plot-value' });
+ plot = this.store.createRecord('plot', { name: 'Value 1', type: 'plot-value' });
} else {
// DEBUG
console.log('Add plot: ' + name);
@@ -62,6 +71,47 @@ export default Ember.Controller.extend(FetchLiveDataMixin, {
let id = this.get('model.id');
this.transitionToRoute('/visualization/' + id);
+ },
+
+ showPlotDialog(plot) {
+ // show dialog by plot type
+ let plotType = plot.get('type');
+ if (plotType === 'plot-value') {
+ // set properties
+ this.set('plot', plot);
+ this.set('name', plot.get('name'));
+ this.set('simulator', plot.get('simulator'));
+ this.set('signal', plot.get('signal'));
+
+ this.set('isShowingPlotValueModal', true);
+ }
+ },
+
+ submitValuePlot() {
+ // verify properties
+ let properties = this.getProperties('name', 'simulator', 'signal');
+ if (properties['name'] === null || properties['name'] === "") {
+ this.set('errorMessage', 'Plot name is missing');
+ return;
+ }
+
+ properties['simulator'] = Number(properties['simulator']);
+ properties['signal'] = Number(properties['signal']);
+
+ // save properties
+ this.get('plot').setProperties(properties);
+
+ let self = this;
+
+ this.get('plot').save().then(function() {
+ self.set('isShowingPlotValueModal', false);
+ }, function() {
+ Ember.debug('Error saving value plot');
+ });
+ },
+
+ cancelValuePlot() {
+ this.set('isShowingPlotValueModal', false);
}
}
});
diff --git a/app/models/plot.js b/app/models/plot.js
index 17ab769..ab6cf46 100644
--- a/app/models/plot.js
+++ b/app/models/plot.js
@@ -13,7 +13,7 @@ import { belongsTo } from 'ember-data/relationships';
export default Model.extend({
name: attr('string'),
- signal: attr('string'),
+ signal: attr('number', { defaultValue: 1 }),
simulator: attr('number', { defaultValue: 1 }),
width: attr('number', { defaultValue: 100 }),
height: attr('number', { defaultValue: 100 }),
diff --git a/app/router.js b/app/router.js
index 4f52379..5e95c68 100644
--- a/app/router.js
+++ b/app/router.js
@@ -51,6 +51,10 @@ Router.map(function() {
this.route('simulators');
this.route('simulator');
+
+ this.route('dialog', function() {
+ this.route('plot', function() {});
+ });
});
export default Router;
diff --git a/app/templates/components/plot-container.hbs b/app/templates/components/plot-container.hbs
index 110a95e..008dfad 100644
--- a/app/templates/components/plot-container.hbs
+++ b/app/templates/components/plot-container.hbs
@@ -1,3 +1,3 @@
{{#each plots as |plot|}}
- {{component plot.type plot=plot editing=editing grid=grid data=data}}
+ {{component plot.type plot=plot editing=editing grid=grid data=data showPlotDialog=showPlotDialog}}
{{/each}}
diff --git a/app/templates/components/plot-value.hbs b/app/templates/components/plot-value.hbs
index 9ad31d4..b824785 100644
--- a/app/templates/components/plot-value.hbs
+++ b/app/templates/components/plot-value.hbs
@@ -1 +1 @@
-Value: {{value}}
+{{name}}: {{value}}
diff --git a/app/templates/dialog/plot/value.hbs b/app/templates/dialog/plot/value.hbs
new file mode 100644
index 0000000..971e9ec
--- /dev/null
+++ b/app/templates/dialog/plot/value.hbs
@@ -0,0 +1,44 @@
+{{#if isShowingPlotValueModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Value
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter plot name' value=name}}
+
+
+
+
+ Simulator
+
+
+ {{input id='simulator' type='number' value=simulator min='1' max='255'}}
+
+
+
+
+ Signal
+
+
+ {{input id='signal' type='number' value=signal min='1'}}
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/dialog/project.hbs b/app/templates/dialog/project.hbs
new file mode 100644
index 0000000..5d45882
--- /dev/null
+++ b/app/templates/dialog/project.hbs
@@ -0,0 +1,68 @@
+{{#if isShowingNewModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New visualization
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter visualization name' value=name}}
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingEditModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Edit visualization
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter visualization name' value=name}}
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingDeleteModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Delete visualization
+
+ Are you sure you want to delete the visualization {{visualization.name}} ?
+
+ Cancel
+ Delete
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/dialog/projects.hbs b/app/templates/dialog/projects.hbs
new file mode 100644
index 0000000..83dae43
--- /dev/null
+++ b/app/templates/dialog/projects.hbs
@@ -0,0 +1,92 @@
+{{#if isShowingNewModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New project
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter project name' value=name}}
+
+
+
+
+ Simulation
+
+
+
+ {{#each model.simulations as |simulation|}}
+ {{simulation.name}}
+ {{/each}}
+
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingEditModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Edit project
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter project name' value=name}}
+
+
+
+
+ Simulation
+
+
+
+ {{#each model.simulations as |simulation|}}
+ {{simulation.name}}
+ {{/each}}
+
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingDeleteModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Delete project
+
+ Are you sure you want to delete the project {{project.name}} ?
+
+ Cancel
+ Delete
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/dialog/simulation.hbs b/app/templates/dialog/simulation.hbs
new file mode 100644
index 0000000..aaa09a0
--- /dev/null
+++ b/app/templates/dialog/simulation.hbs
@@ -0,0 +1,92 @@
+{{#if isShowingNewModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New model
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter model name' value=name}}
+
+
+
+
+ Simulator
+
+
+
+ {{#each model.simulators as |simulator|}}
+ {{simulator.name}}
+ {{/each}}
+
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingEditModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Edit model
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter model name' value=name}}
+
+
+
+
+ Simulator
+
+
+
+ {{#each model.simulators as |simulator|}}
+ {{simulator.name}}
+ {{/each}}
+
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingDeleteModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Delete simulation-model
+
+ Are you sure you want to delete the simulation-model {{simulationModel.name}} ?
+
+ Cancel
+ Delete
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/dialog/simulations.hbs b/app/templates/dialog/simulations.hbs
new file mode 100644
index 0000000..96f847d
--- /dev/null
+++ b/app/templates/dialog/simulations.hbs
@@ -0,0 +1,86 @@
+{{#if isShowingNewModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New simulation
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter simulation name' value=name}}
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingEditModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Edit simulator
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter simulation name' value=name}}
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingDeleteModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Delete simulation
+
+ Are you sure you want to delete the simulation {{simulation.name}} ?
+
+ Cancel
+ Delete
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingRunningModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Simulation running
+
+ {{simulation.name}}:
+
+
+ running
+ not running
+
+
+
+
+ Cancel
+ Save
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/dialog/simulators.hbs b/app/templates/dialog/simulators.hbs
new file mode 100644
index 0000000..ff43682
--- /dev/null
+++ b/app/templates/dialog/simulators.hbs
@@ -0,0 +1,118 @@
+{{#if isShowingNewModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New simulator
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter simulator name' value=name}}
+
+
+
+
+ Simulator ID
+
+
+ {{input id='simulatorid' type='number' value=simulatorid min='1' max='255'}}
+
+
+
+
+ Endpoint
+
+
+ {{input id='endpoint' placeholder='Enter endpoint' value=endpoint}}
+
+
+
+
+ Cancel
+ Create
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingDeleteModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Delete simulator
+
+ Are you sure you want to delete the simulator {{simulator.name}} ?
+
+ Cancel
+ Delete
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingEditModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ New simulator
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter simulator name' value=simulatorName}}
+
+
+
+
+ Simulator ID
+
+
+ {{input id='simulatorid' type='number' value=simulatorid min='1' max='255'}}
+
+
+
+
+ Endpoint
+
+
+ {{input id='endpoint' placeholder='Enter endpoint' value=simulatorEndpoint}}
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
+
+{{#if isShowingRunningModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Simulator running
+
+ {{simulator.name}}:
+
+
+ running
+ not running
+
+
+
+
+ Cancel
+ Save
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/project/index.hbs b/app/templates/project/index.hbs
index b94ec9d..ce4c826 100644
--- a/app/templates/project/index.hbs
+++ b/app/templates/project/index.hbs
@@ -28,71 +28,4 @@
New visualization
-{{#if isShowingNewModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New visualization
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter visualization name' value=name}}
-
-
-
-
- Cancel
- Create
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingEditModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Edit visualization
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter visualization name' value=name}}
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingDeleteModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Delete visualization
-
- Are you sure you want to delete the visualization {{visualization.name}} ?
-
- Cancel
- Delete
- {{/modal-dialog}}
-{{/if}}
+{{partial "dialog/project"}}
diff --git a/app/templates/projects.hbs b/app/templates/projects.hbs
index f544a78..ff264cd 100644
--- a/app/templates/projects.hbs
+++ b/app/templates/projects.hbs
@@ -30,95 +30,4 @@
New Project
-{{#if isShowingNewModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New project
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter project name' value=name}}
-
-
-
-
- Simulation
-
-
-
- {{#each model.simulations as |simulation|}}
- {{simulation.name}}
- {{/each}}
-
-
-
-
-
- Cancel
- Create
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingEditModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Edit project
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter project name' value=name}}
-
-
-
-
- Simulation
-
-
-
- {{#each model.simulations as |simulation|}}
- {{simulation.name}}
- {{/each}}
-
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingDeleteModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Delete project
-
- Are you sure you want to delete the project {{project.name}} ?
-
- Cancel
- Delete
- {{/modal-dialog}}
-{{/if}}
+{{partial "dialog/projects"}}
diff --git a/app/templates/simulation/index.hbs b/app/templates/simulation/index.hbs
index 3804575..a938a9b 100644
--- a/app/templates/simulation/index.hbs
+++ b/app/templates/simulation/index.hbs
@@ -32,95 +32,4 @@
New model
-{{#if isShowingNewModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New model
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter model name' value=name}}
-
-
-
-
- Simulator
-
-
-
- {{#each model.simulators as |simulator|}}
- {{simulator.name}}
- {{/each}}
-
-
-
-
-
- Cancel
- Create
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingEditModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Edit model
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter model name' value=name}}
-
-
-
-
- Simulator
-
-
-
- {{#each model.simulators as |simulator|}}
- {{simulator.name}}
- {{/each}}
-
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingDeleteModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Delete simulation-model
-
- Are you sure you want to delete the simulation-model {{simulationModel.name}} ?
-
- Cancel
- Delete
- {{/modal-dialog}}
-{{/if}}
+{{partial "dialog/simulation"}}
diff --git a/app/templates/simulations.hbs b/app/templates/simulations.hbs
index fee2ede..70b16d1 100644
--- a/app/templates/simulations.hbs
+++ b/app/templates/simulations.hbs
@@ -31,89 +31,4 @@
New Simulation
-{{#if isShowingNewModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New simulation
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter simulation name' value=name}}
-
-
-
-
- Cancel
- Create
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingEditModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Edit simulator
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter simulation name' value=name}}
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingDeleteModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Delete simulation
-
- Are you sure you want to delete the simulation {{simulation.name}} ?
-
- Cancel
- Delete
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingRunningModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Simulation running
-
- {{simulation.name}}:
-
-
- running
- not running
-
-
-
-
- Cancel
- Save
- {{/modal-dialog}}
-{{/if}}
+{{partial "dialog/simulations"}}
diff --git a/app/templates/simulators.hbs b/app/templates/simulators.hbs
index d610d92..d70e298 100644
--- a/app/templates/simulators.hbs
+++ b/app/templates/simulators.hbs
@@ -40,121 +40,4 @@
New Simulator
-{{#if isShowingNewModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New simulator
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter simulator name' value=name}}
-
-
-
-
- Simulator ID
-
-
- {{input id='simulatorid' type='number' value=simulatorid min='1' max='255'}}
-
-
-
-
- Endpoint
-
-
- {{input id='endpoint' placeholder='Enter endpoint' value=endpoint}}
-
-
-
-
- Cancel
- Create
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingDeleteModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Delete simulator
-
- Are you sure you want to delete the simulator {{simulator.name}} ?
-
- Cancel
- Delete
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingEditModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New simulator
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter simulator name' value=simulatorName}}
-
-
-
-
- Simulator ID
-
-
- {{input id='simulatorid' type='number' value=simulatorid min='1' max='255'}}
-
-
-
-
- Endpoint
-
-
- {{input id='endpoint' placeholder='Enter endpoint' value=simulatorEndpoint}}
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingRunningModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Simulator running
-
- {{simulator.name}}:
-
-
- running
- not running
-
-
-
-
- Cancel
- Save
- {{/modal-dialog}}
-{{/if}}
+{{partial "dialog/simulators"}}
diff --git a/app/templates/visualization/edit.hbs b/app/templates/visualization/edit.hbs
index 80e78f3..46c89e7 100644
--- a/app/templates/visualization/edit.hbs
+++ b/app/templates/visualization/edit.hbs
@@ -16,10 +16,12 @@
{{#draggable-dropzone dropped='addPlot'}}
- {{plot-container plots=model.plots editing=true data=data}}
+ {{plot-container plots=model.plots editing=true data=data showPlotDialog='showPlotDialog'}}
{{/draggable-dropzone}}
Cancel
Save
+
+{{partial "dialog/plot/value"}}
From 22780b9d7a44a7cb18532a07140bfad1c8986ad4 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 12 Oct 2016 22:06:24 +0200
Subject: [PATCH 031/556] Move value plot modal to component
Change simulator and signal from numbers to combo boxes
---
app/components/plot-abstract.js | 4 +-
app/components/plot-value.js | 121 +++++++++++++++++-
.../dialog/plot/value.js} | 7 +-
app/controllers/simulation-model/index.js | 34 -----
app/controllers/simulation/index.js | 59 +++++----
app/controllers/visualization/delete.js | 30 -----
app/controllers/visualization/edit.js | 21 ++-
app/models/plot.js | 1 -
app/router.js | 6 +-
app/routes/dialog/plot/value.js | 4 +
app/styles/app.scss | 1 +
.../simulation-models.scss} | 20 +--
app/templates/components/plot-value.hbs | 53 ++++++++
app/templates/dialog/plot/value.hbs | 47 +------
app/templates/dialog/simulation.hbs | 16 +++
app/templates/simulation-model/index.hbs | 39 ++++--
app/templates/simulations.hbs | 2 +-
app/templates/visualization/delete.hbs | 6 -
app/templates/visualization/edit.hbs | 12 +-
app/templates/visualization/new.hbs | 1 -
.../plot/value-test.js} | 2 +-
.../new-test.js => dialog/plot/value-test.js} | 2 +-
.../unit/routes/visualization/delete-test.js | 11 --
23 files changed, 298 insertions(+), 201 deletions(-)
rename app/{routes/visualization/new.js => controllers/dialog/plot/value.js} (69%)
delete mode 100644 app/controllers/visualization/delete.js
create mode 100644 app/routes/dialog/plot/value.js
rename app/{routes/visualization/delete.js => styles/simulation-models.scss} (55%)
delete mode 100644 app/templates/visualization/delete.hbs
delete mode 100644 app/templates/visualization/new.hbs
rename tests/unit/controllers/{visualization/delete-test.js => dialog/plot/value-test.js} (75%)
rename tests/unit/routes/{visualization/new-test.js => dialog/plot/value-test.js} (75%)
delete mode 100644 tests/unit/routes/visualization/delete-test.js
diff --git a/app/components/plot-abstract.js b/app/components/plot-abstract.js
index eded6a2..5df157f 100644
--- a/app/components/plot-abstract.js
+++ b/app/components/plot-abstract.js
@@ -79,9 +79,9 @@ export default Ember.Component.extend(Resizable, Draggable, {
}
}.observes('editing', 'grid').on('init'),
- doubleClick() {
+ /*doubleClick() {
if (this.get('editing')) {
this.sendAction('showPlotDialog', this.get('plot'));
}
- }
+ }*/
});
diff --git a/app/components/plot-value.js b/app/components/plot-value.js
index 338d900..b526080 100644
--- a/app/components/plot-value.js
+++ b/app/components/plot-value.js
@@ -26,5 +26,124 @@ export default PlotAbstract.extend({
Ember.run.later(this, function() {
this.notifyPropertyChange('data.' + this.get('plot.simulator') + '.values');
}, 1000);
- }.property('data.2.values', 'plot.simulator', 'plot.signal')
+ }.property('data.2.values', 'plot.simulator', 'plot.signal'),
+
+ doubleClick() {
+ if (this.get('editing') === true) {
+ // prepare modal
+ this.set('name', this.get('plot.name'));
+
+ // get signal mapping for simulation model
+ let self = this;
+ let simulatorid = this.get('plot.simulator');
+
+ this.get('plot.visualization').then((visualization) => {
+ visualization.get('project').then((project) => {
+ project.get('simulation').then((simulation) => {
+ simulation.get('models').then((simulationModels) => {
+ // find simulation model by simulatorid
+ simulationModels.forEach(function(simulationModel) {
+ simulationModel.get('simulator').then((simulator) => {
+ if (simulator.get('simulatorid') === simulatorid) {
+ // set simulation model
+ self.set('simulationModel', simulationModel);
+ self.set('simulationModelName', simulationModel.get('name'));
+
+ // set signal
+ let mapping = simulationModel.get('mapping');
+ self.set('signalName', mapping[self.get('plot.signal')]);
+ }
+ });
+ });
+ });
+ });
+ });
+ });
+
+ // shot modal
+ this.set('isShowingModal', true);
+ }
+ },
+
+ actions: {
+ submitModal() {
+ // verify properties
+ let properties = this.getProperties('name');
+ if (properties['name'] === null || properties['name'] === "") {
+ this.set('errorMessage', 'Plot name is missing');
+ return;
+ }
+
+ // set simulator by simulation model name
+ let simulationModelName = this.get('simulationModelName');
+ let self = this;
+
+ this.get('plot.visualization').then((visualization) => {
+ visualization.get('project').then((project) => {
+ project.get('simulation').then((simulation) => {
+ simulation.get('models').then((simulationModels) => {
+ // find simulation model by name
+ simulationModels.forEach(function(simulationModel) {
+ if (simulationModel.get('name') === simulationModelName) {
+ simulationModel.get('simulator').then((simulator) => {
+ // set simulator
+ properties['simulator'] = simulator.get('simulatorid');
+
+ // set signal by name
+ let mapping = simulationModel.get('mapping');
+ let signalName = self.get('signalName');
+
+ for (let i = 0; i < mapping.length; i++) {
+ if (mapping[i] === signalName) {
+ properties['signal'] = i;
+ }
+ }
+
+ // save properties
+ self.get('plot').setProperties(properties);
+
+ self.get('plot').save().then(function() {
+ self.set('isShowingModal', false);
+ });
+ });
+ }
+ });
+ });
+ });
+ });
+ });
+ },
+
+ cancelModal() {
+ this.set('isShowingModal', false);
+ },
+
+ selectSimulationModel(simulationModelName) {
+ // save simulation model
+ this.set('simulationModelName', simulationModelName);
+
+ // get signal mapping for simulation model
+ let self = this;
+ let simulatorid = this.get('plot.simulator');
+
+ this.get('plot.visualization').then((visualization) => {
+ visualization.get('project').then((project) => {
+ project.get('simulation').then((simulation) => {
+ simulation.get('models').then((simulationModels) => {
+ // find simulation model by name
+ simulationModels.forEach(function(simulationModel) {
+ if (simulationModel.get('name') === simulationModelName) {
+ self.set('simulationModel', simulationModel);
+ }
+ });
+ });
+ });
+ });
+ });
+ },
+
+ selectSignal(signalName) {
+ this.set('signalName', signalName);
+ }
+ }
});
diff --git a/app/routes/visualization/new.js b/app/controllers/dialog/plot/value.js
similarity index 69%
rename from app/routes/visualization/new.js
rename to app/controllers/dialog/plot/value.js
index 12d85c7..427431e 100644
--- a/app/routes/visualization/new.js
+++ b/app/controllers/dialog/plot/value.js
@@ -1,14 +1,13 @@
/**
- * File: new.js
+ * File: value.js
* Author: Markus Grigull
- * Date: 28.06.2016
+ * Date: 12.07.2016
* Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
+export default Ember.Controller.extend({
});
diff --git a/app/controllers/simulation-model/index.js b/app/controllers/simulation-model/index.js
index 3481e21..e8ba731 100644
--- a/app/controllers/simulation-model/index.js
+++ b/app/controllers/simulation-model/index.js
@@ -10,38 +10,4 @@
import Ember from 'ember';
export default Ember.Controller.extend({
- values: function() {
- return this.get('simulationData.values');
- }.property('simulationData.values.@each'),
-
- _getData: function() {
- if (this.get('model.simulation.running') === true) {
- var simulator = this.get('model.simulator');
- if (simulator == null) {
- return;
- }
-
- var data = this.store.peekRecord('simulation-data', simulator);
- this.set('simulationData', data);
-
- // load model again if simulation data is null
- // this prevents from simulation data not being loaded when the controller
- // is loaded before the websocket connects
- if (data === null) {
- Ember.run.later(this, function() {
- // trigger _getData
- this.notifyPropertyChange('model');
- }, 1000);
- }
- } else {
- // clear simulation data
- this.set('simulationData', null);
-
- // check again if simulation is running now
- Ember.run.later(this, function() {
- // trigger _getData
- this.notifyPropertyChange('model');
- }, 1000);
- }
- }.observes('model').on('init')
});
diff --git a/app/controllers/simulation/index.js b/app/controllers/simulation/index.js
index d201f3a..8db5c58 100644
--- a/app/controllers/simulation/index.js
+++ b/app/controllers/simulation/index.js
@@ -21,7 +21,7 @@ export default Ember.Controller.extend({
_updateSimulators: function() {
if (this.get('model.simulators') != null && this.get('model.simulators.length') > 0) {
- var simulators = this.get('model.simulators');
+ let simulators = this.get('model.simulators');
this.set('simulatorName', simulators.toArray()[0].get('name'));
}
}.observes('model'),
@@ -31,6 +31,7 @@ export default Ember.Controller.extend({
// reset properties
this.set('errorMessage', null);
this.set('name', null);
+ this.set('length', 1);
// show the dialog
this.set('isShowingNewModal', true);
@@ -41,10 +42,11 @@ export default Ember.Controller.extend({
this.set('errorMessage', null);
this.set('simulationModel', simulationModel);
this.set('name', simulationModel.get('name'));
+ this.set('length', simulationModel.get('length'));
- var simulators = this.get('model.simulators');
- var simulatorId = simulationModel.get('simulator.id');
- var simulatorName = null;
+ let simulators = this.get('model.simulators');
+ let simulatorId = simulationModel.get('simulator.id');
+ let simulatorName = null;
simulators.forEach(function(simulator) {
if (simulator.get('id') === simulatorId) {
@@ -68,19 +70,19 @@ export default Ember.Controller.extend({
submitNew() {
// verify properties
- var properties = this.getProperties('name');
+ let properties = this.getProperties('name', 'length');
if (properties['name'] == null || properties['name'] === "") {
this.set('errorMessage', 'Simulation model name is missing');
return;
}
// set simuatlion properties
- var simulation = this.get('model.simulation');
+ let simulation = this.get('model.simulation');
properties['simulation'] = simulation;
- // get the simulator id by simulator name
- var simulators = this.get('model.simulators');
- var simulatorName = this.get('simulatorName');
+ // get the simulator by simulator name
+ let simulators = this.get('model.simulators');
+ let simulatorName = this.get('simulatorName');
simulators.forEach(function(simulator) {
if (simulator.get('name') === simulatorName) {
@@ -88,13 +90,22 @@ export default Ember.Controller.extend({
}
});
+ // create mapping
+ let mapping = [];
+
+ for (let i = 0; i < properties['length']; i++) {
+ mapping.pushObject("Signal " + (i + 1));
+ }
+
+ properties['mapping'] = mapping;
+
// create new model
- var simulationModel = this.store.createRecord('simulation-model', properties);
+ let simulationModel = this.store.createRecord('simulation-model', properties);
// this change will not be saved, but it is nessecary otherwise ember will omit the simulation's id in the post request
simulation.get('models').pushObject(simulationModel);
- var controller = this;
+ let controller = this;
simulationModel.save().then(function() {
controller.set('isShowingNewModal', false);
@@ -109,36 +120,28 @@ export default Ember.Controller.extend({
submitEdit() {
// verify properties
- var properties = this.getProperties('name');
+ let properties = this.getProperties('name', 'length');
if (properties['name'] == null || properties['name'] === "") {
this.set('errorMessage', 'Simulation model name is missing');
return;
}
// set simuatlion properties
- var simulation = this.get('model.simulation');
- properties['simulation'] = simulation.get('id');
+ let simulation = this.get('model.simulation');
+ properties['simulation'] = simulation;
- // get the simulator id by simulator name
- var simulators = this.get('model.simulators');
- var simulatorId = null;
- var simulatorName = this.get('simulatorName');
+ // get the simulator by simulator name
+ let simulators = this.get('model.simulators');
+ let simulatorName = this.get('simulatorName');
simulators.forEach(function(simulator) {
if (simulator.get('name') === simulatorName) {
- simulatorId = simulator.get('simulatorid');
+ properties['simulator'] = simulator;
}
});
- if (simulatorId == null) {
- Ember.debug('Unable to find simulator by name');
- return;
- }
-
- properties['simulator'] = simulatorId;
-
// save properties
- var controller = this;
+ let controller = this;
this.get('simulationModel').setProperties(properties);
@@ -155,7 +158,7 @@ export default Ember.Controller.extend({
confirmDelete() {
// delete the model
- var simulationModel = this.get('simulationModel');
+ let simulationModel = this.get('simulationModel');
simulationModel.destroyRecord();
// hide the dialog
diff --git a/app/controllers/visualization/delete.js b/app/controllers/visualization/delete.js
deleted file mode 100644
index 99bb874..0000000
--- a/app/controllers/visualization/delete.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * File: delete.js
- * Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- actions: {
- cancelDelete() {
- // go back to visualization edit view
- let visualizationId = this.get('model.id');
- this.transitionToRoute('/visualization/' + visualizationId);
- },
-
- confirmDelete() {
- // get the objects
- var projectId = this.get('model.project.id');
-
- var visualization = this.get('model');
- visualization.destroyRecord();
-
- this.transitionToRoute('/project/' + projectId);
- }
- }
-});
diff --git a/app/controllers/visualization/edit.js b/app/controllers/visualization/edit.js
index c864a5a..a7c1845 100644
--- a/app/controllers/visualization/edit.js
+++ b/app/controllers/visualization/edit.js
@@ -18,8 +18,16 @@ export default Ember.Controller.extend(FetchLiveDataMixin, {
plot: null,
name: null,
simulator: null,
+ simulatorName: null,
signal: null,
+ _updateSimulators: function() {
+ if (this.get('model.simulators') !== null && this.get('model.simulators.length') > 0) {
+ let simulators = this.get('model.simulators');
+ this.set('simulatorName', simulators.toArray()[0].get('name'));
+ }
+ }.observes('model'),
+
actions: {
addPlot(name) {
var plot = null;
@@ -30,7 +38,7 @@ export default Ember.Controller.extend(FetchLiveDataMixin, {
} else if (name === 'table') {
plot = this.store.createRecord('plot', { name: 'Table 1', type: 'plot-table', width: 500, height: 200, title: 'Table 1' });
} else if (name === 'value') {
- plot = this.store.createRecord('plot', { name: 'Value 1', type: 'plot-value' });
+ plot = this.store.createRecord('plot', { name: 'Value 1', type: 'plot-value', simulator: 2 });
} else {
// DEBUG
console.log('Add plot: ' + name);
@@ -79,9 +87,10 @@ export default Ember.Controller.extend(FetchLiveDataMixin, {
if (plotType === 'plot-value') {
// set properties
this.set('plot', plot);
- this.set('name', plot.get('name'));
- this.set('simulator', plot.get('simulator'));
- this.set('signal', plot.get('signal'));
+ /*this.set('name', plot.get('name'));
+ this.set('signal', plot.get('signal'));*/
+
+ //this.set('simulatorName', simulatorName);
this.set('isShowingPlotValueModal', true);
}
@@ -112,6 +121,10 @@ export default Ember.Controller.extend(FetchLiveDataMixin, {
cancelValuePlot() {
this.set('isShowingPlotValueModal', false);
+ },
+
+ selectSimulator(simulator) {
+ this.set('simulatorName', simulator);
}
}
});
diff --git a/app/models/plot.js b/app/models/plot.js
index ab6cf46..6349409 100644
--- a/app/models/plot.js
+++ b/app/models/plot.js
@@ -17,7 +17,6 @@ export default Model.extend({
simulator: attr('number', { defaultValue: 1 }),
width: attr('number', { defaultValue: 100 }),
height: attr('number', { defaultValue: 100 }),
- title: attr('string'),
type: attr('string'),
x: attr('number', { defaultValue: 0 }),
y: attr('number', { defaultValue: 0 }),
diff --git a/app/router.js b/app/router.js
index 5e95c68..924f60b 100644
--- a/app/router.js
+++ b/app/router.js
@@ -27,9 +27,7 @@ Router.map(function() {
this.route('visualization', function() {
this.route('index', { path: '/:visualizationid' });
- this.route('new');
this.route('edit', { path: '/edit/:visualizationid' });
- this.route('delete', { path: '/delete/:visualizationid' });
});
this.route('user', function() {
@@ -53,7 +51,9 @@ Router.map(function() {
this.route('simulator');
this.route('dialog', function() {
- this.route('plot', function() {});
+ this.route('plot', function() {
+ this.route('value');
+ });
});
});
diff --git a/app/routes/dialog/plot/value.js b/app/routes/dialog/plot/value.js
new file mode 100644
index 0000000..26d9f31
--- /dev/null
+++ b/app/routes/dialog/plot/value.js
@@ -0,0 +1,4 @@
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+});
diff --git a/app/styles/app.scss b/app/styles/app.scss
index 3c17c3b..f650627 100644
--- a/app/styles/app.scss
+++ b/app/styles/app.scss
@@ -12,6 +12,7 @@
@import 'simulations';
@import 'projects';
@import 'simulators';
+@import 'simulation-models';
@import "ember-modal-dialog/ember-modal-structure";
@import "ember-modal-dialog/ember-modal-appearance";
diff --git a/app/routes/visualization/delete.js b/app/styles/simulation-models.scss
similarity index 55%
rename from app/routes/visualization/delete.js
rename to app/styles/simulation-models.scss
index a6f5f3e..04aea01 100644
--- a/app/routes/visualization/delete.js
+++ b/app/styles/simulation-models.scss
@@ -1,17 +1,19 @@
/**
- * File: delete.js
+ * File: simulation-models.css
* Author: Markus Grigull
- * Date: 28.06.2016
+ * Date: 12.10.2016
* Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
+/**
+ * Route: simulation-model/index
+ */
+.simulation-model-index-mapping {
+ margin-top: 20px;
+}
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return this.store.findRecord('visualization', params.visualizationid);
- }
-});
+.simulation-model-index-buttons {
+ margin-top: 20px;
+}
diff --git a/app/templates/components/plot-value.hbs b/app/templates/components/plot-value.hbs
index b824785..0e68e9a 100644
--- a/app/templates/components/plot-value.hbs
+++ b/app/templates/components/plot-value.hbs
@@ -1 +1,54 @@
{{name}}: {{value}}
+
+{{#if isShowingModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Value
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter plot name' value=name}}
+
+
+
+
+ Simulator
+
+
+
+ {{#each plot.visualization.project.simulation.models as |simulationModel|}}
+ {{simulationModel.name}}
+ {{/each}}
+
+
+
+
+
+ Signal
+
+
+
+ {{#each simulationModel.mapping as |signal|}}
+ {{signal}}
+ {{/each}}
+
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/dialog/plot/value.hbs b/app/templates/dialog/plot/value.hbs
index 971e9ec..8f11e5f 100644
--- a/app/templates/dialog/plot/value.hbs
+++ b/app/templates/dialog/plot/value.hbs
@@ -1,44 +1,5 @@
-{{#if isShowingPlotValueModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Value
+Test
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter plot name' value=name}}
-
-
-
-
- Simulator
-
-
- {{input id='simulator' type='number' value=simulator min='1' max='255'}}
-
-
-
-
- Signal
-
-
- {{input id='signal' type='number' value=signal min='1'}}
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
+
+
+
diff --git a/app/templates/dialog/simulation.hbs b/app/templates/dialog/simulation.hbs
index aaa09a0..9e2bfb6 100644
--- a/app/templates/dialog/simulation.hbs
+++ b/app/templates/dialog/simulation.hbs
@@ -24,6 +24,14 @@
+
+
+ Length
+
+
+ {{input id='length' type='number' value=length min='1'}}
+
+
Cancel
@@ -65,6 +73,14 @@
+
+
+ Length
+
+
+ {{input id='length' type='number' value=length min='1'}}
+
+
Cancel
diff --git a/app/templates/simulation-model/index.hbs b/app/templates/simulation-model/index.hbs
index d993484..b1d2c6c 100644
--- a/app/templates/simulation-model/index.hbs
+++ b/app/templates/simulation-model/index.hbs
@@ -1,18 +1,29 @@
+{{#link-to 'simulation.index' model.simulation.id}}Back to {{model.simulation.name}}{{/link-to}}
+
{{model.name}}
-
- Running: {{model.simulation.running}}
-
+Mapping
-
- Simulator: {{model.simulator}}
-
+
+
+
+ Signal
+ Name
+
+ {{#each-in model.mapping as |signal name|}}
+
+
+ {{signal}}
+
+
+ {{name}}
+
+
+ {{/each-in}}
+
+
-
- Data:
-
-
-{{#each values as |value|}}
- {{value}}
-
-{{/each}}
+
+
+ Save
+
diff --git a/app/templates/simulations.hbs b/app/templates/simulations.hbs
index 70b16d1..698d9a7 100644
--- a/app/templates/simulations.hbs
+++ b/app/templates/simulations.hbs
@@ -5,7 +5,7 @@
Name
Running
-
+
{{#each model as |simulation|}}
diff --git a/app/templates/visualization/delete.hbs b/app/templates/visualization/delete.hbs
deleted file mode 100644
index 0be5279..0000000
--- a/app/templates/visualization/delete.hbs
+++ /dev/null
@@ -1,6 +0,0 @@
-Delete
-
-Are you sure you want to delete the visualization?
-
-Cancel
-Delete
diff --git a/app/templates/visualization/edit.hbs b/app/templates/visualization/edit.hbs
index 46c89e7..a6872ac 100644
--- a/app/templates/visualization/edit.hbs
+++ b/app/templates/visualization/edit.hbs
@@ -1,14 +1,14 @@
-{{model.name}}
+{{model.ame}}
{{#draggable-dropzone dropped='addWidget'}}
From c40974acf54e2efbac6c4394ec455214f178eb8e Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Fri, 13 Jan 2017 17:11:48 +0100
Subject: [PATCH 040/556] Add plot widget
Fixed to first simuator, first signal
Add flot to project
---
app/components/draggable-dropzone.js | 2 --
app/components/widget-container.js | 2 +-
app/controllers/visualization/edit.js | 36 +++++++++++++++++++++++----
app/mixins/live-data.js | 2 ++
app/models/simulation-data.js | 24 ++++++++++++------
app/models/visualization.js | 3 +--
app/templates/visualization/edit.hbs | 4 +++
bower.json | 3 ++-
ember-cli-build.js | 1 +
package.json | 1 +
todo.md | 5 ----
11 files changed, 60 insertions(+), 23 deletions(-)
diff --git a/app/components/draggable-dropzone.js b/app/components/draggable-dropzone.js
index 6fd48a7..c8d7956 100644
--- a/app/components/draggable-dropzone.js
+++ b/app/components/draggable-dropzone.js
@@ -34,8 +34,6 @@ export default Ember.Component.extend({
y: event.originalEvent.pageY - $(event.target).offset().top - parseFloat(event.dataTransfer.getData('offset/y'))
}
- console.log(position);
-
this.sendAction('dropped', data, position);
set(this, 'dragClass', 'deactivated');
diff --git a/app/components/widget-container.js b/app/components/widget-container.js
index fd1e992..c1dcdc1 100644
--- a/app/components/widget-container.js
+++ b/app/components/widget-container.js
@@ -16,7 +16,7 @@ export default Ember.Component.extend({
widgets: null,
editing: false,
- grid: true,
+ grid: false,
data: null,
style: Ember.computed('widgets.@each.height', 'widgets.@each.y', function() {
diff --git a/app/controllers/visualization/edit.js b/app/controllers/visualization/edit.js
index 930629d..c6033a1 100644
--- a/app/controllers/visualization/edit.js
+++ b/app/controllers/visualization/edit.js
@@ -34,20 +34,46 @@ export default Ember.Controller.extend(FetchLiveDataMixin, {
// create widget
let widget = null;
+ let properties = {
+ x: position.x,
+ y: position.y,
+ name: 'widget',
+ type: null
+ };
if (name === 'label') {
- widget = this.store.createRecord('widget', { name: 'Label', type: 'widget-label', width: 100, height: 20, x: position.x, y: position.y });
+ properties.type = 'widget-label';
+ properties.width = 100;
+ properties.height = 20;
+ properties.name = 'Label';
} else if (name === 'table') {
- widget = this.store.createRecord('widget', { name: 'Table 1', type: 'widget-table', width: 500, height: 200, x: position.x, y: position.y, widgetData: { simulator: defaultSimulatorid } });
+ properties.type = 'widget-table';
+ properties.name = "Table";
+ properties.width = 500;
+ proeprties.height = 200;
+ properties.widgetData = { simulator: defaultSimulatorid };
} else if (name === 'value') {
- widget = this.store.createRecord('widget', { name: 'Value 1', type: 'widget-value', width: 250, height: 20, x: position.x, y: position.y, widgetData: { signal: 0, simulator: defaultSimulatorid } });
+ properties.type = 'widget-value';
+ properties.name = 'Value';
+ properties.width = 250;
+ properties.height = 20;
+ properties.widgetData = { signal: 0, simulator: defaultSimulatorid };
+ } else if (name === 'plot') {
+ properties.type = 'widget-plot';
+ properties.name = 'Plot';
+ properties.width = 500;
+ properties.height = 200;
+ properties.widgetData = { signal: 0, simulator: defaultSimulatorid };
} else {
// DEBUG
- console.log('Add widget ' + name);
+ console.log('Add unknown widget ' + name);
return;
}
- if (widget != null) {
+ if (properties.type != null) {
+ // create widget
+ widget = this.store.createRecord('widget', properties);
+
// add widget to visualization
this.get('model.widgets').pushObject(widget);
diff --git a/app/mixins/live-data.js b/app/mixins/live-data.js
index 0aedb5e..059c2a4 100644
--- a/app/mixins/live-data.js
+++ b/app/mixins/live-data.js
@@ -141,10 +141,12 @@ export default Ember.Mixin.create({
var simulationData = this.store.peekRecord('simulation-data', message.simulator);
if (simulationData != null) {
simulationData.set('sequence', message.sequence);
+ simulationData.set('timestamp', new Date(message.timestamp).getTime());
simulationData.set('values', message.values);
} else {
this.store.createRecord('simulation-data', {
sequence: message.sequence,
+ timestamp: new Date(message.timestamp).getTime(),
values: message.values,
id: message.simulator
});
diff --git a/app/models/simulation-data.js b/app/models/simulation-data.js
index b145faf..44eb110 100644
--- a/app/models/simulation-data.js
+++ b/app/models/simulation-data.js
@@ -15,18 +15,28 @@ import attr from 'ember-data/attr';
export default Model.extend({
simulator: Ember.computed.alias('id'),
sequence: attr('number'),
+ timestamp: attr('number'),
values: attr('array'),
- /*historyValues() {
+ flotValues: Ember.computed('_flotValues', function() {
+ return this._flotValues;
+ }),
+
+ _flotValues: [],
+
+ historyValues: Ember.computed('_history', function() {
return this._history;
- },
+ }),
_history: [],
- _updateHistory: Ember.observer('values', function() {
- this._history.unshift(this.get('values'));
- while (this._history.length > 5) {
- this._history.shift();
+ _updateHistories: Ember.observer('values', function() {
+ // save set of values with timestamp
+ this._flotValues.push([this.get('timestamp'), this.get('values')[0]]);
+
+ // discard old values
+ while (this._flotValues.length > 100) {
+ this._flotValues.shift();
}
- })*/
+ })
});
diff --git a/app/models/visualization.js b/app/models/visualization.js
index cb5253a..439d526 100644
--- a/app/models/visualization.js
+++ b/app/models/visualization.js
@@ -14,6 +14,5 @@ import { belongsTo, hasMany } from 'ember-data/relationships';
export default Model.extend({
name: attr('string'),
widgets: hasMany('widget', { async: true }),
- project: belongsTo('project', { async: true }),
- rows: attr('number', { defaultValue: 1 })
+ project: belongsTo('project', { async: true })
});
diff --git a/app/templates/visualization/edit.hbs b/app/templates/visualization/edit.hbs
index 9d68285..4d9d36d 100644
--- a/app/templates/visualization/edit.hbs
+++ b/app/templates/visualization/edit.hbs
@@ -14,6 +14,10 @@
Label
{{/draggable-item}}
+ {{#draggable-item content='plot'}}
+ Plot
+ {{/draggable-item}}
+
Hint: Double click widgets to edit or delete them.
diff --git a/bower.json b/bower.json
index 070c570..9020a79 100644
--- a/bower.json
+++ b/bower.json
@@ -6,7 +6,8 @@
"ember-cli-test-loader": "0.2.2",
"ember-qunit-notifications": "0.1.0",
"jquery-ui": "1.11.4",
- "bootstrap": "~3.3.5"
+ "bootstrap": "~3.3.5",
+ "flot": "~0.8.3"
},
"resolutions": {
"ember": "~2.5.0"
diff --git a/ember-cli-build.js b/ember-cli-build.js
index 87da6af..ab8a0ed 100644
--- a/ember-cli-build.js
+++ b/ember-cli-build.js
@@ -21,6 +21,7 @@ module.exports = function(defaults) {
// along with the exports of each module as its value.
app.import('bower_components/bootstrap/dist/js/bootstrap.js');
+ app.import('bower_components/flot/jquery.flot.time.js');
return app.toTree();
};
diff --git a/package.json b/package.json
index 45b186e..7cdb0e3 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"ember-cli-app-version": "^1.0.0",
"ember-cli-babel": "^5.1.6",
"ember-cli-dependency-checker": "^1.2.0",
+ "ember-cli-flot": "0.0.3",
"ember-cli-htmlbars": "^1.0.3",
"ember-cli-htmlbars-inline-precompile": "^0.3.1",
"ember-cli-inject-live-reload": "^1.4.0",
diff --git a/todo.md b/todo.md
index f0e8443..aca9507 100644
--- a/todo.md
+++ b/todo.md
@@ -1,13 +1,8 @@
# To-Do
- Change password
- - Move plot attributes/styling from plot-container into actual plots
- - Move drag-n-drop to mixins
- Go into edit mode if visualization is empty
- Auto-detect if simulators are running
- Remove running socket if it's not in the updated list
- - Rebrand plots into widgets
- - Change widget model (plot) to custom data to provide mechanism for all widgets
- - Add widgets where dropped
websocketserverip/config.json
{
From 3ec9cc3497e0df458c259c25493caa74a5e7d649 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 25 Jan 2017 12:54:34 +0100
Subject: [PATCH 041/556] Add missing files
---
app/components/flow-plot.js | 27 +++
app/components/widget-plot.js | 205 ++++++++++++++++++
app/controllers/visualization/edit.js | 4 +-
app/models/simulation-data.js | 25 ++-
app/templates/components/flow-plot.hbs | 1 +
app/templates/components/widget-plot.hbs | 56 +++++
.../integration/components/flow-plot-test.js | 24 ++
.../components/widget-plot-test.js | 24 ++
8 files changed, 353 insertions(+), 13 deletions(-)
create mode 100644 app/components/flow-plot.js
create mode 100644 app/components/widget-plot.js
create mode 100644 app/templates/components/flow-plot.hbs
create mode 100644 app/templates/components/widget-plot.hbs
create mode 100644 tests/integration/components/flow-plot-test.js
create mode 100644 tests/integration/components/widget-plot-test.js
diff --git a/app/components/flow-plot.js b/app/components/flow-plot.js
new file mode 100644
index 0000000..01700ab
--- /dev/null
+++ b/app/components/flow-plot.js
@@ -0,0 +1,27 @@
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+ tagName: 'div',
+ classNames: [ 'flow-plot' ],
+ attributeBindings: [ 'style' ],
+
+ plot: null,
+ data: [],
+ options: {},
+ height: '85%',
+
+ setupPlot: Ember.on('didInsertElement', function() {
+ var plot = Ember.$.plot('#' + this.get('element').id, this.get('data'), this.get('options'));
+ this.set('plot', plot);
+ }),
+
+ updateData: Ember.observer('data.@each', function() {
+ // update plot
+ var plot = Ember.$.plot('#' + this.get('element').id, this.get('data'), this.get('options'));
+ this.set('plot', plot);
+ }),
+
+ style: Ember.computed('height', function() {
+ return Ember.String.htmlSafe("height: " + this.get('height') + ";");
+ })
+});
diff --git a/app/components/widget-plot.js b/app/components/widget-plot.js
new file mode 100644
index 0000000..733c0da
--- /dev/null
+++ b/app/components/widget-plot.js
@@ -0,0 +1,205 @@
+/**
+ * File: widget-value.js
+ * Author: Markus Grigull
+ * Date: 08.12.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import Ember from 'ember';
+import WidgetAbstract from './widget-abstract';
+
+export default WidgetAbstract.extend({
+ classNames: [ 'widgetPlot' ],
+
+ plotData: Ember.A([]),
+
+ plotOptions: {
+ series: {
+ lines: {
+ show: true,
+ lineWidth: 2
+ },
+ shadowSize: 0
+ },
+ xaxis: {
+ mode: 'time',
+ timeformat: '%M:%S',
+ /*min: firstTimestamp,
+ max: lastTimestamp,*/
+ axisLabel: 'time [min]',
+ axisLabelUseCanvas: true
+ }/*,
+ yaxis: {
+ tickDecimals: 1,
+ axisLabel: this.data.get('type'),
+ axisLabelUseCanvas: true
+ }*/
+ },
+
+ signals: Ember.A([]),
+
+ _updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', function() {
+ // get query for observer
+ let simulatorId = this.get('widget.widgetData.simulator');
+ let query = 'data.' + simulatorId + '.sequence';
+
+ // get plot settings
+ let signals = this.get('widget.widgetData.signals');
+ this.set('signals', signals);
+
+ this.addObserver(query, function() {
+ // get values from array
+ let values = this.get('data.' + simulatorId + '.flotValues');
+ var updatedValues = this.get('plotData');
+
+ // update values
+ var index = 0;
+
+ this.get('signals').forEach(function(signal) {
+ updatedValues.replace(index, 1, Ember.A([ values[signal] ]));
+ index += 1;
+ });
+
+ this.set('plotData', updatedValues);
+ });
+ })),
+
+ doubleClick() {
+ if (this.get('editing') === true) {
+ // prepare modal
+ this.set('name', this.get('widget.name'));
+ this.set('errorMessage', null);
+
+ // get signal mapping for simulation model
+ let self = this;
+ let simulatorid = this.get('widget.widgetData.simulator');
+
+ this.get('widget.visualization').then((visualization) => {
+ visualization.get('project').then((project) => {
+ project.get('simulation').then((simulation) => {
+ simulation.get('models').then((simulationModels) => {
+ // find simulation model by simulatorid
+ simulationModels.forEach(function(simulationModel) {
+ simulationModel.get('simulator').then((simulator) => {
+ if (simulator.get('simulatorid') === simulatorid) {
+ // set simulation model
+ self.set('simulationModel', simulationModel);
+ self.set('simulationModelName', simulationModel.get('name'));
+
+ // set signals
+ let mapping = simulationModel.get('mapping');
+
+ // uncheck all signals
+ mapping.forEach(function(key) {
+ self.set(key + 'Checked', false);
+ });
+
+ self.get('signals').forEach(function(signal) {
+ self.set(mapping[signal] + 'Checked', true);
+ });
+ }
+ });
+ });
+ });
+ });
+ });
+ });
+
+ // show modal
+ this.set('isShowingModal', true);
+ }
+ },
+
+ actions: {
+ submitModal() {
+ // verify properties
+ let properties = this.getProperties('name');
+
+ if (properties['name'] === null || properties['name'] === "") {
+ this.set('errorMessage', 'Widget name is missing');
+ return;
+ }
+
+ // set simulator by simulation model name
+ let simulationModelName = this.get('simulationModelName');
+ let self = this;
+
+ this.get('widget.visualization').then((visualization) => {
+ visualization.get('project').then((project) => {
+ project.get('simulation').then((simulation) => {
+ simulation.get('models').then((simulationModels) => {
+ // find simulation model by name
+ simulationModels.forEach(function(simulationModel) {
+ if (simulationModel.get('name') === simulationModelName) {
+ simulationModel.get('simulator').then((simulator) => {
+ // set simulator
+ let widgetData = {};
+ widgetData.simulator = simulator.get('simulatorid');
+
+ // set signals
+ let mapping = simulationModel.get('mapping');
+ widgetData.signals = [];
+
+ // uncheck all signals
+ for (var i = 0; i < mapping.length; i++) {
+ if (self.get(mapping[i] + 'Checked')) {
+ widgetData.signals.push(i);
+ }
+ }
+
+ // save properties
+ properties['widgetData'] = widgetData;
+
+ console.log(properties);
+
+ self.get('widget').setProperties(properties);
+
+ self.get('widget').save().then(function() {
+ self.set('isShowingModal', false);
+ });
+ });
+ }
+ });
+ });
+ });
+ });
+ });
+ },
+
+ cancelModal() {
+ this.set('isShowingModal', false);
+ },
+
+ deleteModal() {
+ // delete widget
+ this.get('widget').destroyRecord();
+
+ this.set('isShowingModal', false);
+ },
+
+ selectSimulationModel(simulationModelName) {
+ // save simulation model
+ this.set('simulationModelName', simulationModelName);
+
+ // get signal mapping for simulation model
+ let self = this;
+
+ this.get('widget.visualization').then((visualization) => {
+ visualization.get('project').then((project) => {
+ project.get('simulation').then((simulation) => {
+ simulation.get('models').then((simulationModels) => {
+ // find simulation model by name
+ simulationModels.forEach(function(simulationModel) {
+ if (simulationModel.get('name') === simulationModelName) {
+ self.set('simulationModel', simulationModel);
+ }
+ });
+ });
+ });
+ });
+ });
+ }
+ }
+});
diff --git a/app/controllers/visualization/edit.js b/app/controllers/visualization/edit.js
index c6033a1..5d7556d 100644
--- a/app/controllers/visualization/edit.js
+++ b/app/controllers/visualization/edit.js
@@ -62,8 +62,8 @@ export default Ember.Controller.extend(FetchLiveDataMixin, {
properties.type = 'widget-plot';
properties.name = 'Plot';
properties.width = 500;
- properties.height = 200;
- properties.widgetData = { signal: 0, simulator: defaultSimulatorid };
+ properties.height = 400;
+ properties.widgetData = { signals: [0], simulator: defaultSimulatorid, type: 'multiple' };
} else {
// DEBUG
console.log('Add unknown widget ' + name);
diff --git a/app/models/simulation-data.js b/app/models/simulation-data.js
index 44eb110..b978222 100644
--- a/app/models/simulation-data.js
+++ b/app/models/simulation-data.js
@@ -24,19 +24,22 @@ export default Model.extend({
_flotValues: [],
- historyValues: Ember.computed('_history', function() {
- return this._history;
- }),
-
- _history: [],
-
_updateHistories: Ember.observer('values', function() {
- // save set of values with timestamp
- this._flotValues.push([this.get('timestamp'), this.get('values')[0]]);
+ // update flot values
+ let values = this.get('values');
- // discard old values
- while (this._flotValues.length > 100) {
- this._flotValues.shift();
+ // add empty arrays for each value
+ while (this._flotValues.length < values.length) {
+ this._flotValues.push([]);
+ }
+
+ for (var i = 0; i < values.length; i++) {
+ this._flotValues[i].push([this.get('timestamp'), values[i]]);
+
+ // discard old values
+ while (this._flotValues[i].length > 100) {
+ this._flotValues[i].shift();
+ }
}
})
});
diff --git a/app/templates/components/flow-plot.hbs b/app/templates/components/flow-plot.hbs
new file mode 100644
index 0000000..889d9ee
--- /dev/null
+++ b/app/templates/components/flow-plot.hbs
@@ -0,0 +1 @@
+{{yield}}
diff --git a/app/templates/components/widget-plot.hbs b/app/templates/components/widget-plot.hbs
new file mode 100644
index 0000000..3f04c8f
--- /dev/null
+++ b/app/templates/components/widget-plot.hbs
@@ -0,0 +1,56 @@
+{{widget.name}}
+
+{{flow-plot data=plotData options=plotOptions}}
+
+{{#if isShowingModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Plot
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
diff --git a/tests/integration/components/flow-plot-test.js b/tests/integration/components/flow-plot-test.js
new file mode 100644
index 0000000..949b9a7
--- /dev/null
+++ b/tests/integration/components/flow-plot-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('flow-plot', 'Integration | Component | flow plot', {
+ integration: true
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{flow-plot}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:
+ this.render(hbs`
+ {{#flow-plot}}
+ template block text
+ {{/flow-plot}}
+ `);
+
+ assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/tests/integration/components/widget-plot-test.js b/tests/integration/components/widget-plot-test.js
new file mode 100644
index 0000000..1b38f7a
--- /dev/null
+++ b/tests/integration/components/widget-plot-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('widget-plot', 'Integration | Component | widget plot', {
+ integration: true
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{widget-plot}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:
+ this.render(hbs`
+ {{#widget-plot}}
+ template block text
+ {{/widget-plot}}
+ `);
+
+ assert.equal(this.$().text().trim(), 'template block text');
+});
From 7c4d67c16388431de653a7b8bf56e68cf17da51d Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 25 Jan 2017 19:36:23 +0100
Subject: [PATCH 042/556] Add image widget and file upload
File upload is in image widget edit dialog
Add ember-uploader package
---
app/components/file-upload.js | 19 ++++
app/components/widget-image.js | 106 ++++++++++++++++++
app/controllers/visualization/edit.js | 8 +-
app/models/file.js | 18 +++
app/models/user.js | 3 +-
app/templates/components/file-upload.hbs | 1 +
app/templates/components/widget-image.hbs | 51 +++++++++
app/templates/visualization/edit.hbs | 4 +
package.json | 1 +
.../components/file-upload-test.js | 24 ++++
.../components/widget-image-test.js | 24 ++++
tests/unit/models/file-test.js | 12 ++
12 files changed, 269 insertions(+), 2 deletions(-)
create mode 100644 app/components/file-upload.js
create mode 100644 app/components/widget-image.js
create mode 100644 app/models/file.js
create mode 100644 app/templates/components/file-upload.hbs
create mode 100644 app/templates/components/widget-image.hbs
create mode 100644 tests/integration/components/file-upload-test.js
create mode 100644 tests/integration/components/widget-image-test.js
create mode 100644 tests/unit/models/file-test.js
diff --git a/app/components/file-upload.js b/app/components/file-upload.js
new file mode 100644
index 0000000..461df9b
--- /dev/null
+++ b/app/components/file-upload.js
@@ -0,0 +1,19 @@
+/**
+ * File: file-upload.js
+ * Author: Markus Grigull
+ * Date: 05.12.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import Ember from 'ember';
+import EmberUploader from 'ember-uploader';
+
+export default EmberUploader.FileField.extend({
+ files: null,
+
+ filesDidChange: function(files) {
+ this.set('files', files);
+ }
+});
diff --git a/app/components/widget-image.js b/app/components/widget-image.js
new file mode 100644
index 0000000..22a3dc1
--- /dev/null
+++ b/app/components/widget-image.js
@@ -0,0 +1,106 @@
+/**
+ * File: widget-image.js
+ * Author: Markus Grigull
+ * Date: 05.12.2016
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import WidgetAbstract from './widget-abstract';
+import Ember from 'ember';
+import ENV from '../config/environment';
+import EmberUploader from 'ember-uploader';
+
+const {
+ inject: { service },
+ RSVP
+} = Ember;
+
+export default WidgetAbstract.extend({
+ classNames: [ 'widgetImage' ],
+
+ session: service('session'),
+ sessionUser: Ember.inject.service('session-user'),
+ store: service(),
+
+ url: 'http://' + ENV.APP.API_HOST,
+ namespace: 'api/v1',
+
+ doubleClick() {
+ if (this.get('editing') === true) {
+ // prepare modal
+ this.set('name', this.get('widget.name'));
+
+ // show modal
+ this.set('isShowingModal', true);
+ }
+ },
+
+ actions: {
+ submitModal() {
+ // verify properties
+ let properties = this.getProperties('name');
+ properties.widgetData = { path: this.get('image.path') };
+
+ this.get('widget').setProperties(properties);
+
+ let self = this;
+
+ this.get('widget').save().then(function() {
+ self.set('isShowingModal', false);
+ });
+ },
+
+ cancelModal() {
+ this.set('isShowingModal', false);
+ },
+
+ selectImage(image) {
+ // get image by path
+ var self = this;
+
+ this.get('widget.visualization').then((visualization) => {
+ visualization.get('project').then((project) => {
+ project.get('owner').then((user) => {
+ user.get('files').then((files) => {
+ files.forEach(function(file) {
+ if (file.get('name') === image) {
+ // set image
+ self.set('image', file);
+ }
+ });
+ });
+ });
+ });
+ });
+ },
+
+ upload() {
+ // check if any files to upload
+ let files = this.get('uploadFiles');
+
+ if (!Ember.isEmpty(files)) {
+ var uploadURL = this.get('url') + '/' + this.get('namespace') + '/upload';
+
+ const uploader = EmberUploader.Uploader.create({
+ multiple: true,
+ url: uploadURL,
+ ajaxSettings: {
+ headers: {
+ 'x-access-token': this.get('session.data.authenticated.token')
+ }
+ }
+ });
+
+ var self = this;
+
+ uploader.upload(files).then(event => {
+ // reload user
+ var user = self.get('sessionUser.user');
+ self.get('store').findRecord('user', user.get('id'));
+ });
+ }
+ }
+ }
+});
diff --git a/app/controllers/visualization/edit.js b/app/controllers/visualization/edit.js
index 5d7556d..ad31ff4 100644
--- a/app/controllers/visualization/edit.js
+++ b/app/controllers/visualization/edit.js
@@ -50,7 +50,7 @@ export default Ember.Controller.extend(FetchLiveDataMixin, {
properties.type = 'widget-table';
properties.name = "Table";
properties.width = 500;
- proeprties.height = 200;
+ properties.height = 200;
properties.widgetData = { simulator: defaultSimulatorid };
} else if (name === 'value') {
properties.type = 'widget-value';
@@ -64,6 +64,12 @@ export default Ember.Controller.extend(FetchLiveDataMixin, {
properties.width = 500;
properties.height = 400;
properties.widgetData = { signals: [0], simulator: defaultSimulatorid, type: 'multiple' };
+ } else if (name === 'image') {
+ properties.type = 'widget-image';
+ properties.name = 'Image';
+ properties.width = 300;
+ properties.height = 300;
+ properties.widgetData = { path: null };
} else {
// DEBUG
console.log('Add unknown widget ' + name);
diff --git a/app/models/file.js b/app/models/file.js
new file mode 100644
index 0000000..fc7e63a
--- /dev/null
+++ b/app/models/file.js
@@ -0,0 +1,18 @@
+/**
+ * File: file.js
+ * Author: Markus Grigull
+ * Date: 25.01.2017
+ * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import DS from 'ember-data';
+
+export default DS.Model.extend({
+ name: DS.attr('string'),
+ path: DS.attr('string'),
+ type: DS.attr('string'),
+ user: DS.belongsTo('user', { async: true }),
+ date: DS.attr('date')
+});
diff --git a/app/models/user.js b/app/models/user.js
index cded992..b2bf6d4 100644
--- a/app/models/user.js
+++ b/app/models/user.js
@@ -17,5 +17,6 @@ export default Model.extend({
adminLevel: attr('number'),
projects: hasMany('project', { async: true }),
simulations: hasMany('simulation', { async: true }),
- mail: attr('string')
+ mail: attr('string'),
+ files: hasMany('file', { async: true })
});
diff --git a/app/templates/components/file-upload.hbs b/app/templates/components/file-upload.hbs
new file mode 100644
index 0000000..889d9ee
--- /dev/null
+++ b/app/templates/components/file-upload.hbs
@@ -0,0 +1 @@
+{{yield}}
diff --git a/app/templates/components/widget-image.hbs b/app/templates/components/widget-image.hbs
new file mode 100644
index 0000000..b9b4f0c
--- /dev/null
+++ b/app/templates/components/widget-image.hbs
@@ -0,0 +1,51 @@
+{{#if widget.widgetData.path}}
+
+{{/if}}
+
+{{#if isShowingModal}}
+ {{#modal-dialog attachment="middle center" translucentOverlay=true}}
+ Image
+
+
+
+
+
+ Name
+
+
+ {{input id='name' placeholder='Enter widget name' value=name}}
+
+
+
+
+ Image
+
+
+
+ {{#each widget.visualization.project.owner.files as |imageFile|}}
+ {{imageFile.name}}
+ {{/each}}
+
+
+
+
+
+
+
+ {{file-upload files=uploadFiles}} Upload
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+
+ {{#if errorMessage}}
+ Error: {{errorMessage}}
+ {{/if}}
+ {{/modal-dialog}}
+{{/if}}
diff --git a/app/templates/visualization/edit.hbs b/app/templates/visualization/edit.hbs
index 4d9d36d..c15d593 100644
--- a/app/templates/visualization/edit.hbs
+++ b/app/templates/visualization/edit.hbs
@@ -18,6 +18,10 @@
Plot
{{/draggable-item}}
+ {{#draggable-item content='image'}}
+ Image
+ {{/draggable-item}}
+
Hint: Double click widgets to edit or delete them.
diff --git a/package.json b/package.json
index 7cdb0e3..30d5a65 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
"ember-simple-auth": "^1.1.0",
"ember-tether": "0.3.1",
"ember-truth-helpers": "1.2.0",
+ "ember-uploader": "1.2.3",
"loader.js": "^4.0.1"
},
"dependencies": {}
diff --git a/tests/integration/components/file-upload-test.js b/tests/integration/components/file-upload-test.js
new file mode 100644
index 0000000..3c7b795
--- /dev/null
+++ b/tests/integration/components/file-upload-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('file-upload', 'Integration | Component | file upload', {
+ integration: true
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{file-upload}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:
+ this.render(hbs`
+ {{#file-upload}}
+ template block text
+ {{/file-upload}}
+ `);
+
+ assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/tests/integration/components/widget-image-test.js b/tests/integration/components/widget-image-test.js
new file mode 100644
index 0000000..8eace27
--- /dev/null
+++ b/tests/integration/components/widget-image-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('widget-image', 'Integration | Component | widget image', {
+ integration: true
+});
+
+test('it renders', function(assert) {
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });
+
+ this.render(hbs`{{widget-image}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:
+ this.render(hbs`
+ {{#widget-image}}
+ template block text
+ {{/widget-image}}
+ `);
+
+ assert.equal(this.$().text().trim(), 'template block text');
+});
diff --git a/tests/unit/models/file-test.js b/tests/unit/models/file-test.js
new file mode 100644
index 0000000..225d072
--- /dev/null
+++ b/tests/unit/models/file-test.js
@@ -0,0 +1,12 @@
+import { moduleForModel, test } from 'ember-qunit';
+
+moduleForModel('file', 'Unit | Model | file', {
+ // Specify the other units that are required for this test.
+ needs: []
+});
+
+test('it exists', function(assert) {
+ let model = this.subject();
+ // let store = this.store();
+ assert.ok(!!model);
+});
From 64397eebff345196db1050233bdde58bc1adc19a Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 25 Jan 2017 19:51:33 +0100
Subject: [PATCH 043/556] Fix plot signal selection checkboxes
---
app/components/widget-image.js | 2 +-
app/components/widget-plot.js | 13 ++++++++++---
app/templates/components/widget-plot.hbs | 2 +-
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/app/components/widget-image.js b/app/components/widget-image.js
index 22a3dc1..e7c062a 100644
--- a/app/components/widget-image.js
+++ b/app/components/widget-image.js
@@ -46,7 +46,7 @@ export default WidgetAbstract.extend({
this.get('widget').setProperties(properties);
let self = this;
-
+
this.get('widget').save().then(function() {
self.set('isShowingModal', false);
});
diff --git a/app/components/widget-plot.js b/app/components/widget-plot.js
index 733c0da..106165c 100644
--- a/app/components/widget-plot.js
+++ b/app/components/widget-plot.js
@@ -40,6 +40,8 @@ export default WidgetAbstract.extend({
signals: Ember.A([]),
+ checkedSignals: {},
+
_updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', function() {
// get query for observer
let simulatorId = this.get('widget.widgetData.simulator');
@@ -90,15 +92,18 @@ export default WidgetAbstract.extend({
// set signals
let mapping = simulationModel.get('mapping');
+ let checkedSignals = {};
// uncheck all signals
mapping.forEach(function(key) {
- self.set(key + 'Checked', false);
+ checkedSignals[key] = false;
});
self.get('signals').forEach(function(signal) {
- self.set(mapping[signal] + 'Checked', true);
+ checkedSignals[mapping[signal]] = true;
});
+
+ self.set('checkedSignals', checkedSignals);
}
});
});
@@ -143,8 +148,10 @@ export default WidgetAbstract.extend({
widgetData.signals = [];
// uncheck all signals
+ let checkedSignals = self.get('checkedSignals');
+
for (var i = 0; i < mapping.length; i++) {
- if (self.get(mapping[i] + 'Checked')) {
+ if (checkedSignals[mapping[i]]) {
widgetData.signals.push(i);
}
}
diff --git a/app/templates/components/widget-plot.hbs b/app/templates/components/widget-plot.hbs
index 3f04c8f..11f0101 100644
--- a/app/templates/components/widget-plot.hbs
+++ b/app/templates/components/widget-plot.hbs
@@ -34,7 +34,7 @@
{{#each simulationModel.mapping as |signal|}}
- {{signal}}
+ {{input type='checkbox' name=signal checked=(mut (get checkedSignals signal))}} {{signal}}
{{/each}}
From 0e83bbd6863a4a5f5bf7838d16cf0c1e17de7848 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Tue, 31 Jan 2017 22:12:24 +0100
Subject: [PATCH 044/556] Add table plot widget type
In the plot widget the plot type can be selected
Fix plot widget selecting signals
Fix widgets data observers
---
app/components/widget-plot.js | 90 ++++++++++++++++++++----
app/components/widget-table.js | 45 +++++++-----
app/components/widget-value.js | 29 +++++---
app/styles/widgets.scss | 13 ++++
app/templates/components/widget-plot.hbs | 52 ++++++++++++--
5 files changed, 181 insertions(+), 48 deletions(-)
diff --git a/app/components/widget-plot.js b/app/components/widget-plot.js
index 106165c..4cc045e 100644
--- a/app/components/widget-plot.js
+++ b/app/components/widget-plot.js
@@ -42,7 +42,11 @@ export default WidgetAbstract.extend({
checkedSignals: {},
- _updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', function() {
+ plotType: "multiple",
+
+ observeQuery: null,
+
+ _updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', 'widget.widgetData.type', 'widget.widgetData.signals', function() {
// get query for observer
let simulatorId = this.get('widget.widgetData.simulator');
let query = 'data.' + simulatorId + '.sequence';
@@ -51,27 +55,67 @@ export default WidgetAbstract.extend({
let signals = this.get('widget.widgetData.signals');
this.set('signals', signals);
- this.addObserver(query, function() {
- // get values from array
- let values = this.get('data.' + simulatorId + '.flotValues');
- var updatedValues = this.get('plotData');
+ let plotType = this.get('widget.widgetData.type');
+ this.set('plotType', plotType);
- // update values
- var index = 0;
+ if (plotType === 'table') {
+ // set simulation model for table with signals
+ var self = this;
+ let simulatorid = this.get('widget.widgetData.simulator');
- this.get('signals').forEach(function(signal) {
- updatedValues.replace(index, 1, Ember.A([ values[signal] ]));
- index += 1;
+ this.get('widget.visualization').then((visualization) => {
+ visualization.get('project').then((project) => {
+ project.get('simulation').then((simulation) => {
+ simulation.get('models').then((simulationModels) => {
+ // find simulation model by simulatorid
+ simulationModels.forEach(function(simulationModel) {
+ simulationModel.get('simulator').then((simulator) => {
+ if (simulator.get('simulatorid') === simulatorid) {
+ // set simulation model
+ self.set('simulationModel', simulationModel);
+ }
+ });
+ });
+ });
+ });
+ });
});
+ }
- this.set('plotData', updatedValues);
- });
+ // update observer TODO: Only update when (query) changed
+ let observeQuery = this.get('observeQuery');
+ if (query != observeQuery) {
+ if (observeQuery != null) {
+ this.removeObserver(observeQuery, this._updateData);
+ }
+
+ this.addObserver(query, this._updateData);
+ this.set('observeQuery', query);
+ }
})),
+ _updateData() {
+ // get values from array
+ let simulatorId = this.get('widget.widgetData.simulator');
+ let values = this.get('data.' + simulatorId + '.flotValues');
+ var updatedValues = Ember.A([]);
+
+ // update values
+ var index = 0;
+
+ this.get('signals').forEach(function(signal) {
+ updatedValues.replace(index, 1, Ember.A([ values[signal] ]));
+ index += 1;
+ });
+
+ this.set('plotData', updatedValues);
+ },
+
doubleClick() {
if (this.get('editing') === true) {
// prepare modal
this.set('name', this.get('widget.name'));
+ this.set('plotType', this.get('widget.widgetData.type'));
this.set('errorMessage', null);
// get signal mapping for simulation model
@@ -140,7 +184,10 @@ export default WidgetAbstract.extend({
if (simulationModel.get('name') === simulationModelName) {
simulationModel.get('simulator').then((simulator) => {
// set simulator
- let widgetData = {};
+ let widgetData = {
+ type: self.get('plotType')
+ };
+
widgetData.simulator = simulator.get('simulatorid');
// set signals
@@ -159,8 +206,6 @@ export default WidgetAbstract.extend({
// save properties
properties['widgetData'] = widgetData;
- console.log(properties);
-
self.get('widget').setProperties(properties);
self.get('widget').save().then(function() {
@@ -207,6 +252,21 @@ export default WidgetAbstract.extend({
});
});
});
+ },
+
+ selectType(type) {
+ this.set('plotType', type);
+ },
+
+ selectTableSignal(signal) {
+ // display signal
+ let mapping = this.get('simulationModel.mapping');
+
+ for (var i = 0; i < mapping.length; i++) {
+ if (mapping[i] === signal) {
+ this.set('widget.widgetData.signals', [ i ]);
+ }
+ }
}
}
});
diff --git a/app/components/widget-table.js b/app/components/widget-table.js
index 2bd1f77..6e9f401 100644
--- a/app/components/widget-table.js
+++ b/app/components/widget-table.js
@@ -18,29 +18,19 @@ export default WidgetAbstract.extend({
signals: [],
+ observeQuery: null,
+
_updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', function() {
// get query for observer
let simulatorId = this.get('widget.widgetData.simulator');
let query = 'data.' + simulatorId + '.sequence';
+ let observeQuery = this.get('observeQuery');
+ if (observeQuery != null) {
+ this.removeObserver(observeQuery, this._updateData);
+ }
- this.addObserver(query, function() {
- // get signal names to fill data in
- let signals = this.get('signals');
- if (!signals) {
- // wait till names are loaded
- return;
- }
-
- // get values from array
- let values = this.get('data.' + simulatorId + '.values');
- for (let i = 0; i < values.length; i++) {
- if (!signals[i]) {
- break;
- }
-
- Ember.set(signals[i], 'value', values[i]);
- }
- });
+ this.addObserver(query, this._updateData);
+ this.set('observeQuery', query);
// get signal names
let self = this;
@@ -70,6 +60,25 @@ export default WidgetAbstract.extend({
});
})),
+ _updateData() {
+ // get signal names to fill data in
+ let signals = this.get('signals');
+ if (!signals) {
+ // wait till names are loaded
+ return;
+ }
+
+ // get values from array
+ let values = this.get('data.' + simulatorId + '.values');
+ for (let i = 0; i < values.length; i++) {
+ if (!signals[i]) {
+ break;
+ }
+
+ Ember.set(signals[i], 'value', values[i]);
+ }
+ },
+
doubleClick() {
if (this.get('editing') === true) {
// prepare modal
diff --git a/app/components/widget-value.js b/app/components/widget-value.js
index 485e0af..ed42fb8 100644
--- a/app/components/widget-value.js
+++ b/app/components/widget-value.js
@@ -16,19 +16,30 @@ export default WidgetAbstract.extend({
minWidth_resize: 50,
minHeight_resize: 20,
+ observeQuery: null,
+
_updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', 'widget.widgetData.signal', function() {
+ // update observer
let query = 'data.' + this.get('widget.widgetData.simulator') + '.sequence';
- this.addObserver(query, function() {
- // get value from array
- let values = this.get('data.' + this.get('widget.widgetData.simulator') + '.values');
- if (values) {
- this.set('value', values[this.get('widget.widgetData.signal')]);
- } else {
- this.set('value', null);
- }
- });
+ let observeQuery = this.get('observeQuery');
+ if (observeQuery != null) {
+ this.removeObserver(observeQuery, this._updateData);
+ }
+
+ this.addObserver(query, this._updateData);
+ this.set('observeQuery', query);
})),
+ _updateData() {
+ // get value from array
+ let values = this.get('data.' + this.get('widget.widgetData.simulator') + '.values');
+ if (values) {
+ this.set('value', values[this.get('widget.widgetData.signal')]);
+ } else {
+ this.set('value', null);
+ }
+ },
+
doubleClick() {
if (this.get('editing') === true) {
// prepare modal
diff --git a/app/styles/widgets.scss b/app/styles/widgets.scss
index 39e0eb8..3d49d68 100644
--- a/app/styles/widgets.scss
+++ b/app/styles/widgets.scss
@@ -76,3 +76,16 @@
padding: 2px 5px;
}
+
+/**
+ * Component: widget-plot
+ */
+.widgetPlot-signal-table {
+ border: 1px solid gray;
+
+ padding: 2px 5px;
+}
+
+.widgetPlot-signal-table th {
+ border: 0;
+}
diff --git a/app/templates/components/widget-plot.hbs b/app/templates/components/widget-plot.hbs
index 11f0101..6768416 100644
--- a/app/templates/components/widget-plot.hbs
+++ b/app/templates/components/widget-plot.hbs
@@ -1,6 +1,29 @@
{{widget.name}}
-{{flow-plot data=plotData options=plotOptions}}
+{{#if (eq plotType "table")}}
+
+
+
+ {{flow-plot data=plotData options=plotOptions}}
+
+{{/if}}
+
+{{#if (eq plotType "multiple")}}
+ {{flow-plot data=plotData options=plotOptions}}
+{{/if}}
{{#if isShowingModal}}
{{#modal-dialog attachment="middle center" translucentOverlay=true}}
@@ -30,15 +53,32 @@
- Signals
+ Type
- {{#each simulationModel.mapping as |signal|}}
- {{input type='checkbox' name=signal checked=(mut (get checkedSignals signal))}} {{signal}}
-
- {{/each}}
+
+ Multiple
+ Table
+
+ {{#if (eq plotType "multiple")}}
+
+
+ Signals
+
+
+ {{#each simulationModel.mapping as |signal|}}
+ {{input type='checkbox' name=signal checked=(mut (get checkedSignals signal))}} {{signal}}
+
+ {{/each}}
+
+
+ {{/if}}
+
+ {{#if (eq plotType "table")}}
+
+ {{/if}}
Cancel
From ec034a57bfa35063cf122807b4cd40526ad66093 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 1 Feb 2017 12:26:41 +0100
Subject: [PATCH 045/556] Fix minor errors and warnings
---
app/components/draggable-dropzone.js | 6 +++---
app/components/draggable-item.js | 4 ++--
app/components/file-upload.js | 1 -
app/components/widget-image.js | 5 ++---
app/components/widget-plot.js | 2 +-
app/components/widget-table.js | 2 +-
6 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/app/components/draggable-dropzone.js b/app/components/draggable-dropzone.js
index c8d7956..18cdbff 100644
--- a/app/components/draggable-dropzone.js
+++ b/app/components/draggable-dropzone.js
@@ -30,9 +30,9 @@ export default Ember.Component.extend({
drop(event) {
var data = event.dataTransfer.getData('text/data');
var position = {
- x: event.originalEvent.pageX - $(event.target).offset().left - parseFloat(event.dataTransfer.getData('offset/x')),
- y: event.originalEvent.pageY - $(event.target).offset().top - parseFloat(event.dataTransfer.getData('offset/y'))
- }
+ x: event.originalEvent.pageX - Ember.$(event.target).offset().left - parseFloat(event.dataTransfer.getData('offset/x')),
+ y: event.originalEvent.pageY - Ember.$(event.target).offset().top - parseFloat(event.dataTransfer.getData('offset/y'))
+ };
this.sendAction('dropped', data, position);
diff --git a/app/components/draggable-item.js b/app/components/draggable-item.js
index 71d5dee..c390d26 100644
--- a/app/components/draggable-item.js
+++ b/app/components/draggable-item.js
@@ -17,8 +17,8 @@ export default Ember.Component.extend({
draggable: 'true',
dragStart(event) {
- event.dataTransfer.setData('offset/x', event.originalEvent.pageX - $(event.target).offset().left);
- event.dataTransfer.setData('offset/y', event.originalEvent.pageY - $(event.target).offset().top);
+ event.dataTransfer.setData('offset/x', event.originalEvent.pageX - Ember.$(event.target).offset().left);
+ event.dataTransfer.setData('offset/y', event.originalEvent.pageY - Ember.$(event.target).offset().top);
return event.dataTransfer.setData('text/data', get(this, 'content'));
}
diff --git a/app/components/file-upload.js b/app/components/file-upload.js
index 461df9b..12c0dd0 100644
--- a/app/components/file-upload.js
+++ b/app/components/file-upload.js
@@ -7,7 +7,6 @@
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-import Ember from 'ember';
import EmberUploader from 'ember-uploader';
export default EmberUploader.FileField.extend({
diff --git a/app/components/widget-image.js b/app/components/widget-image.js
index e7c062a..b4f15f0 100644
--- a/app/components/widget-image.js
+++ b/app/components/widget-image.js
@@ -13,8 +13,7 @@ import ENV from '../config/environment';
import EmberUploader from 'ember-uploader';
const {
- inject: { service },
- RSVP
+ inject: { service }
} = Ember;
export default WidgetAbstract.extend({
@@ -95,7 +94,7 @@ export default WidgetAbstract.extend({
var self = this;
- uploader.upload(files).then(event => {
+ uploader.upload(files).then(function() {
// reload user
var user = self.get('sessionUser.user');
self.get('store').findRecord('user', user.get('id'));
diff --git a/app/components/widget-plot.js b/app/components/widget-plot.js
index 4cc045e..707f9fd 100644
--- a/app/components/widget-plot.js
+++ b/app/components/widget-plot.js
@@ -84,7 +84,7 @@ export default WidgetAbstract.extend({
// update observer TODO: Only update when (query) changed
let observeQuery = this.get('observeQuery');
- if (query != observeQuery) {
+ if (query !== observeQuery) {
if (observeQuery != null) {
this.removeObserver(observeQuery, this._updateData);
}
diff --git a/app/components/widget-table.js b/app/components/widget-table.js
index 6e9f401..8272310 100644
--- a/app/components/widget-table.js
+++ b/app/components/widget-table.js
@@ -69,7 +69,7 @@ export default WidgetAbstract.extend({
}
// get values from array
- let values = this.get('data.' + simulatorId + '.values');
+ let values = this.get('data.' + this.get('widget.widgetData.simulator') + '.values');
for (let i = 0; i < values.length; i++) {
if (!signals[i]) {
break;
From 42bc6bb47337a0535ab9a652d2138984b6d9be6f Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 1 Feb 2017 12:54:33 +0100
Subject: [PATCH 046/556] Update to latest ember version
Version 2.11.0
---
.editorconfig | 14 --------
.gitignore | 6 ++--
.jshintrc | 2 +-
.travis.yml | 8 +++--
README.md | 17 +++++----
app/app.js | 4 ---
app/index.html | 10 +++---
app/resolver.js | 9 -----
app/router.js | 3 +-
bower.json | 7 ----
config/environment.js | 6 ++--
package.json | 49 ++++++++++++++------------
tests/.jshintrc | 2 +-
tests/helpers/module-for-acceptance.js | 12 +++----
tests/index.html | 19 +++++-----
15 files changed, 68 insertions(+), 100 deletions(-)
diff --git a/.editorconfig b/.editorconfig
index 47c5438..219985c 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -13,22 +13,8 @@ insert_final_newline = true
indent_style = space
indent_size = 2
-[*.js]
-indent_style = space
-indent_size = 2
-
[*.hbs]
insert_final_newline = false
-indent_style = space
-indent_size = 2
-
-[*.css]
-indent_style = space
-indent_size = 2
-
-[*.html]
-indent_style = space
-indent_size = 2
[*.{diff,md}]
trim_trailing_whitespace = false
diff --git a/.gitignore b/.gitignore
index b876c89..5ad14dd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-# See http://help.github.com/ignore-files/ for more about ignoring files.
+# See https://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
@@ -13,7 +13,5 @@
/connect.lock
/coverage/*
/libpeerconnection.log
-npm-debug.log
+npm-debug.log*
testem.log
-
-.DS_Store
diff --git a/.jshintrc b/.jshintrc
index 08096ef..d421faa 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -27,6 +27,6 @@
"strict": false,
"white": false,
"eqnull": true,
- "esnext": true,
+ "esversion": 6,
"unused": true
}
diff --git a/.travis.yml b/.travis.yml
index 64533be..a75f20e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,12 +7,14 @@ sudo: false
cache:
directories:
- - node_modules
+ - $HOME/.npm
+ - $HOME/.cache # includes bowers cache
before_install:
- npm config set spin false
- - npm install -g bower
- - npm install phantomjs-prebuilt
+ - npm install -g bower phantomjs-prebuilt
+ - bower --version
+ - phantomjs --version
install:
- npm install
diff --git a/README.md b/README.md
index 4dff7cf..8081f80 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Villasweb-frontend
+# villasweb-frontend
This README outlines the details of collaborating on this Ember application.
A short introduction of this app could easily go here.
@@ -7,22 +7,22 @@ A short introduction of this app could easily go here.
You will need the following things properly installed on your computer.
-* [Git](http://git-scm.com/)
-* [Node.js](http://nodejs.org/) (with NPM)
-* [Bower](http://bower.io/)
-* [Ember CLI](http://ember-cli.com/)
+* [Git](https://git-scm.com/)
+* [Node.js](https://nodejs.org/) (with NPM)
+* [Bower](https://bower.io/)
+* [Ember CLI](https://ember-cli.com/)
* [PhantomJS](http://phantomjs.org/)
## Installation
* `git clone ` this repository
-* change into the new directory
+* `cd villasweb-frontend`
* `npm install`
* `bower install`
## Running / Development
-* `ember server`
+* `ember serve`
* Visit your app at [http://localhost:4200](http://localhost:4200).
### Code Generators
@@ -46,8 +46,7 @@ Specify what it takes to deploy your app.
## Further Reading / Useful Links
* [ember.js](http://emberjs.com/)
-* [ember-cli](http://ember-cli.com/)
+* [ember-cli](https://ember-cli.com/)
* Development Browser Extensions
* [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
* [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/)
-
diff --git a/app/app.js b/app/app.js
index 01d4b13..6921924 100644
--- a/app/app.js
+++ b/app/app.js
@@ -22,10 +22,6 @@ App = Ember.Application.extend({
Resolver
});
-Ember.RSVP.on('error', function(error) {
- console.error(error.message);
-});
-
loadInitializers(App, config.modulePrefix);
export default App;
diff --git a/app/index.html b/app/index.html
index fd514c9..f0991a2 100644
--- a/app/index.html
+++ b/app/index.html
@@ -3,22 +3,22 @@
- VILLASwebFrontend
+ VillaswebFrontend
{{content-for "head"}}
-
-
+
+
{{content-for "head-footer"}}
{{content-for "body"}}
-
-
+
+
{{content-for "body-footer"}}
diff --git a/app/resolver.js b/app/resolver.js
index 50a19ab..2fb563d 100644
--- a/app/resolver.js
+++ b/app/resolver.js
@@ -1,12 +1,3 @@
-/**
- * File: resolver.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
import Resolver from 'ember-resolver';
export default Resolver;
diff --git a/app/router.js b/app/router.js
index 47f4580..8fbc33a 100644
--- a/app/router.js
+++ b/app/router.js
@@ -11,7 +11,8 @@ import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
- location: config.locationType
+ location: config.locationType,
+ rootURL: config.rootURL
});
Router.map(function() {
diff --git a/bower.json b/bower.json
index 9020a79..adf3c54 100644
--- a/bower.json
+++ b/bower.json
@@ -1,15 +1,8 @@
{
"name": "villasweb-frontend",
"dependencies": {
- "ember": "~2.5.0",
- "ember-cli-shims": "0.1.1",
- "ember-cli-test-loader": "0.2.2",
- "ember-qunit-notifications": "0.1.0",
"jquery-ui": "1.11.4",
"bootstrap": "~3.3.5",
"flot": "~0.8.3"
- },
- "resolutions": {
- "ember": "~2.5.0"
}
}
diff --git a/config/environment.js b/config/environment.js
index a6feb08..0783652 100644
--- a/config/environment.js
+++ b/config/environment.js
@@ -4,7 +4,7 @@ module.exports = function(environment) {
var ENV = {
modulePrefix: 'villasweb-frontend',
environment: environment,
- baseURL: '/',
+ rootURL: '/',
locationType: 'auto',
EmberENV: {
FEATURES: {
@@ -12,7 +12,8 @@ module.exports = function(environment) {
// e.g. 'with-controller': true
},
EXTEND_PROTOTYPES: {
- Date: false,
+ // Prevent Ember Data from overriding Date.parse.
+ Date: false
}
},
@@ -31,7 +32,6 @@ module.exports = function(environment) {
if (environment === 'test') {
// Testem prefers this...
- ENV.baseURL = '/';
ENV.locationType = 'none';
// keep test console output quieter
diff --git a/package.json b/package.json
index 30d5a65..4640180 100644
--- a/package.json
+++ b/package.json
@@ -2,50 +2,53 @@
"name": "villasweb-frontend",
"version": "0.0.0",
"description": "Small description for villasweb-frontend goes here",
- "private": true,
+ "license": "MIT",
+ "author": "",
"directories": {
"doc": "doc",
"test": "tests"
},
+ "repository": "",
"scripts": {
"build": "ember build",
"start": "ember server",
"test": "ember test"
},
- "repository": "",
- "engines": {
- "node": ">= 0.10.0"
- },
- "author": "",
- "license": "MIT",
"devDependencies": {
- "broccoli-asset-rev": "^2.4.2",
- "ember-ajax": "0.7.1",
- "ember-cli": "2.5.1",
- "ember-cli-app-version": "^1.0.0",
- "ember-cli-babel": "^5.1.6",
- "ember-cli-dependency-checker": "^1.2.0",
+ "broccoli-asset-rev": "^2.4.5",
+ "ember-ajax": "^2.4.1",
+ "ember-cli": "2.11.0",
+ "ember-cli-app-version": "^2.0.0",
+ "ember-cli-babel": "^5.1.7",
+ "ember-cli-dependency-checker": "^1.3.0",
"ember-cli-flot": "0.0.3",
- "ember-cli-htmlbars": "^1.0.3",
- "ember-cli-htmlbars-inline-precompile": "^0.3.1",
- "ember-cli-inject-live-reload": "^1.4.0",
+ "ember-cli-htmlbars": "^1.1.1",
+ "ember-cli-htmlbars-inline-precompile": "^0.3.3",
+ "ember-cli-inject-live-reload": "^1.4.1",
"ember-cli-jquery-ui": "0.0.20",
- "ember-cli-jshint": "^1.0.0",
- "ember-cli-qunit": "^1.4.0",
- "ember-cli-release": "0.2.8",
+ "ember-cli-jshint": "^2.0.1",
+ "ember-cli-qunit": "^3.0.1",
+ "ember-cli-release": "^0.2.9",
"ember-cli-sass": "5.5.2",
+ "ember-cli-shims": "^1.0.2",
"ember-cli-sri": "^2.1.0",
+ "ember-cli-test-loader": "^1.1.0",
"ember-cli-uglify": "^1.2.0",
- "ember-data": "^2.5.0",
+ "ember-data": "^2.11.0",
"ember-export-application-global": "^1.0.5",
- "ember-load-initializers": "^0.5.1",
+ "ember-load-initializers": "^0.6.0",
"ember-modal-dialog": "^0.9.0",
"ember-resolver": "^2.0.3",
"ember-simple-auth": "^1.1.0",
"ember-tether": "0.3.1",
"ember-truth-helpers": "1.2.0",
"ember-uploader": "1.2.3",
- "loader.js": "^4.0.1"
+ "ember-source": "^2.11.0",
+ "ember-welcome-page": "^2.0.2",
+ "loader.js": "^4.0.10"
},
- "dependencies": {}
+ "engines": {
+ "node": ">= 0.12.0"
+ },
+ "private": true
}
diff --git a/tests/.jshintrc b/tests/.jshintrc
index 6ec0b7c..d2bd113 100644
--- a/tests/.jshintrc
+++ b/tests/.jshintrc
@@ -47,6 +47,6 @@
"strict": false,
"white": false,
"eqnull": true,
- "esnext": true,
+ "esversion": 6,
"unused": true
}
diff --git a/tests/helpers/module-for-acceptance.js b/tests/helpers/module-for-acceptance.js
index 8c8b74e..76996fd 100644
--- a/tests/helpers/module-for-acceptance.js
+++ b/tests/helpers/module-for-acceptance.js
@@ -1,23 +1,23 @@
import { module } from 'qunit';
+import Ember from 'ember';
import startApp from '../helpers/start-app';
import destroyApp from '../helpers/destroy-app';
+const { RSVP: { Promise } } = Ember;
+
export default function(name, options = {}) {
module(name, {
beforeEach() {
this.application = startApp();
if (options.beforeEach) {
- options.beforeEach.apply(this, arguments);
+ return options.beforeEach.apply(this, arguments);
}
},
afterEach() {
- if (options.afterEach) {
- options.afterEach.apply(this, arguments);
- }
-
- destroyApp(this.application);
+ let afterEach = options.afterEach && options.afterEach.apply(this, arguments);
+ return Promise.resolve(afterEach).then(() => destroyApp(this.application));
}
});
}
diff --git a/tests/index.html b/tests/index.html
index 9cffb74..4def306 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -3,16 +3,16 @@
- VILLASwebFrontend Tests
+ VillaswebFrontend Tests
{{content-for "head"}}
{{content-for "test-head"}}
-
-
-
+
+
+
{{content-for "head-footer"}}
{{content-for "test-head-footer"}}
@@ -21,12 +21,11 @@
{{content-for "body"}}
{{content-for "test-body"}}
-
-
-
-
-
-
+
+
+
+
+
{{content-for "body-footer"}}
{{content-for "test-body-footer"}}
From ed6ea99d14ff99f8b570d5b4f7e3fe843178f58c Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 1 Feb 2017 13:33:55 +0100
Subject: [PATCH 047/556] Add time length option to plot widget
Increase simulation-data storage to 1200 entries
---
app/components/widget-plot.js | 35 ++++++++++++++++++++----
app/controllers/visualization/edit.js | 2 +-
app/models/simulation-data.js | 2 +-
app/templates/components/widget-plot.hbs | 16 ++++++++++-
4 files changed, 47 insertions(+), 8 deletions(-)
diff --git a/app/components/widget-plot.js b/app/components/widget-plot.js
index 707f9fd..6bc681d 100644
--- a/app/components/widget-plot.js
+++ b/app/components/widget-plot.js
@@ -26,8 +26,6 @@ export default WidgetAbstract.extend({
xaxis: {
mode: 'time',
timeformat: '%M:%S',
- /*min: firstTimestamp,
- max: lastTimestamp,*/
axisLabel: 'time [min]',
axisLabelUseCanvas: true
}/*,
@@ -39,12 +37,11 @@ export default WidgetAbstract.extend({
},
signals: Ember.A([]),
-
checkedSignals: {},
-
plotType: "multiple",
-
+ time: null,
observeQuery: null,
+ selectedSignal: null,
_updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', 'widget.widgetData.type', 'widget.widgetData.signals', function() {
// get query for observer
@@ -73,6 +70,10 @@ export default WidgetAbstract.extend({
if (simulator.get('simulatorid') === simulatorid) {
// set simulation model
self.set('simulationModel', simulationModel);
+
+ if (self.get('selectedSignal') === null) {
+ self.set('selectedSignal', simulationModel.get('mapping')[0]);
+ }
}
});
});
@@ -100,6 +101,26 @@ export default WidgetAbstract.extend({
let values = this.get('data.' + simulatorId + '.flotValues');
var updatedValues = Ember.A([]);
+ // update plot options
+ var plotOptions = this.get('plotOptions');
+
+ // calculate diff for first and last timestamp
+ var firstTimestamp = values[0][0][0];
+ var lastTimestamp = values[0][values[0].length - 1][0];
+
+ var diff = lastTimestamp - firstTimestamp;
+ var diffValue = this.get('widget.widgetData.time') * 1000; // javascript timestamps are in milliseconds
+
+ if (diff > diffValue) {
+ firstTimestamp = lastTimestamp - diffValue;
+ } else {
+ lastTimestamp = +firstTimestamp + +diffValue;
+ }
+
+ plotOptions.xaxis.min = firstTimestamp;
+ plotOptions.xaxis.max = lastTimestamp;
+ this.set('plotOptions', plotOptions);
+
// update values
var index = 0;
@@ -116,6 +137,7 @@ export default WidgetAbstract.extend({
// prepare modal
this.set('name', this.get('widget.name'));
this.set('plotType', this.get('widget.widgetData.type'));
+ this.set('time', this.get('widget.widgetData.time'));
this.set('errorMessage', null);
// get signal mapping for simulation model
@@ -189,6 +211,7 @@ export default WidgetAbstract.extend({
};
widgetData.simulator = simulator.get('simulatorid');
+ widgetData.time = self.get('time');
// set signals
let mapping = simulationModel.get('mapping');
@@ -267,6 +290,8 @@ export default WidgetAbstract.extend({
this.set('widget.widgetData.signals', [ i ]);
}
}
+
+ this.set('selectedSignal', signal);
}
}
});
diff --git a/app/controllers/visualization/edit.js b/app/controllers/visualization/edit.js
index ad31ff4..3478d7e 100644
--- a/app/controllers/visualization/edit.js
+++ b/app/controllers/visualization/edit.js
@@ -63,7 +63,7 @@ export default Ember.Controller.extend(FetchLiveDataMixin, {
properties.name = 'Plot';
properties.width = 500;
properties.height = 400;
- properties.widgetData = { signals: [0], simulator: defaultSimulatorid, type: 'multiple' };
+ properties.widgetData = { signals: [0], simulator: defaultSimulatorid, type: 'multiple', time: 300 };
} else if (name === 'image') {
properties.type = 'widget-image';
properties.name = 'Image';
diff --git a/app/models/simulation-data.js b/app/models/simulation-data.js
index b978222..37744dc 100644
--- a/app/models/simulation-data.js
+++ b/app/models/simulation-data.js
@@ -37,7 +37,7 @@ export default Model.extend({
this._flotValues[i].push([this.get('timestamp'), values[i]]);
// discard old values
- while (this._flotValues[i].length > 100) {
+ while (this._flotValues[i].length > 1200) {
this._flotValues[i].shift();
}
}
diff --git a/app/templates/components/widget-plot.hbs b/app/templates/components/widget-plot.hbs
index 6768416..7fd4040 100644
--- a/app/templates/components/widget-plot.hbs
+++ b/app/templates/components/widget-plot.hbs
@@ -10,7 +10,13 @@
{{#each simulationModel.mapping as |signal|}}
- {{signal}}
+ {{#if (eq signal selectedSignal)}}
+
+ {{signal}}
+
+ {{else}}
+ {{signal}}
+ {{/if}}
{{/each}}
@@ -51,6 +57,14 @@
+
+
+ Time in sec
+
+
+ {{input type='number' id='time' placeholder='Enter time length' value=time}}
+
+
Type
From 31c3c9bf3356eff636dfaf34e652220983eb6f69 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Fri, 3 Feb 2017 15:02:35 +0100
Subject: [PATCH 048/556] Minor fixes
---
app/adapters/application.js | 8 +++++++-
app/components/widget-plot.js | 2 +-
app/mixins/draggable.js | 2 +-
app/mixins/droppable.js | 2 +-
app/mixins/live-data.js | 2 +-
app/mixins/resizable.js | 2 +-
app/mixins/sortable.js | 2 +-
app/services/session-user.js | 2 +-
8 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/app/adapters/application.js b/app/adapters/application.js
index 961ded9..c87b180 100644
--- a/app/adapters/application.js
+++ b/app/adapters/application.js
@@ -15,5 +15,11 @@ export default RESTAdapter.extend(DataAdapterMixin, {
host: 'http://' + ENV.APP.API_HOST,
namespace: 'api/v1',
authorizer: 'authorizer:custom',
- headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }
+ headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
+
+ urlForQueryRecord(query /*, modelName */) {
+ // Fix for /users/me query
+ let baseUrl = this.buildURL();
+ return baseUrl + '/users/' + query;
+ }
});
diff --git a/app/components/widget-plot.js b/app/components/widget-plot.js
index 6bc681d..9b553d7 100644
--- a/app/components/widget-plot.js
+++ b/app/components/widget-plot.js
@@ -114,7 +114,7 @@ export default WidgetAbstract.extend({
if (diff > diffValue) {
firstTimestamp = lastTimestamp - diffValue;
} else {
- lastTimestamp = +firstTimestamp + +diffValue;
+ lastTimestamp = firstTimestamp + diffValue;
}
plotOptions.xaxis.min = firstTimestamp;
diff --git a/app/mixins/draggable.js b/app/mixins/draggable.js
index 811b31e..1edf9f4 100644
--- a/app/mixins/draggable.js
+++ b/app/mixins/draggable.js
@@ -17,7 +17,7 @@ export default Ember.Mixin.create({
uiDragEvents: [ 'create_drag', 'start_drag', 'drag_drag', 'stop_drag' ],
didInsertElement() {
- this._super();
+ this._super.init();
// get available options and events
var options = this._gatherDragOptions();
diff --git a/app/mixins/droppable.js b/app/mixins/droppable.js
index 7e557e8..203ab21 100644
--- a/app/mixins/droppable.js
+++ b/app/mixins/droppable.js
@@ -16,7 +16,7 @@ export default Ember.Mixin.create({
'out_drop', 'drop_drop' ],
didInsertElement() {
- this._super();
+ this._super.init();
// get available options and events
var options = this._gatherDropOptions();
diff --git a/app/mixins/live-data.js b/app/mixins/live-data.js
index 059c2a4..2ba081e 100644
--- a/app/mixins/live-data.js
+++ b/app/mixins/live-data.js
@@ -20,7 +20,7 @@ export default Ember.Mixin.create({
_sockets: {},
init: function() {
- this._super();
+ this._super.init();
// fetch the simulations for the first time
this._fetchRunningSimulations();
diff --git a/app/mixins/resizable.js b/app/mixins/resizable.js
index 28a1073..50c1383 100644
--- a/app/mixins/resizable.js
+++ b/app/mixins/resizable.js
@@ -18,7 +18,7 @@ export default Ember.Mixin.create({
uiResizeEvents: [ 'create_resize', 'start_resize', 'resize_resize', 'stop_resize' ],
didInsertElement() {
- this._super();
+ this._super.init();
// get available options and events
var options = this._gatherResizeOptions();
diff --git a/app/mixins/sortable.js b/app/mixins/sortable.js
index 737367f..a69d4e8 100644
--- a/app/mixins/sortable.js
+++ b/app/mixins/sortable.js
@@ -21,7 +21,7 @@ export default Ember.Mixin.create({
'sort_sort', 'start_sort', 'stop_sort', 'update_sort' ],
didInsertElement() {
- this._super();
+ this._super.init();
// get available options and events
var options = this._gatherSortOptions();
diff --git a/app/services/session-user.js b/app/services/session-user.js
index ed736ac..06b94b9 100644
--- a/app/services/session-user.js
+++ b/app/services/session-user.js
@@ -24,7 +24,7 @@ export default Ember.Service.extend({
return new RSVP.Promise((resolve, reject) => {
const token = this.get('session.data.authenticated.token');
if (!Ember.isEmpty(token)) {
- return this.get('store').findRecord('user', 'me').then(function(user) {
+ return this.get('store').queryRecord('user', 'me').then(function(user) {
_this.set('user', user);
resolve();
}, function() {
From 1104bcfec54e2c1088b79cb3cd14bc3fbd30d319 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Sat, 4 Feb 2017 15:11:41 +0100
Subject: [PATCH 049/556] Fix jquery-ui dependency
Fix super class init
---
app/mixins/draggable.js | 2 +-
app/mixins/droppable.js | 2 +-
app/mixins/live-data.js | 2 +-
app/mixins/resizable.js | 2 +-
app/mixins/sortable.js | 2 +-
ember-cli-build.js | 5 +++++
package.json | 3 +--
7 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/app/mixins/draggable.js b/app/mixins/draggable.js
index 1edf9f4..811b31e 100644
--- a/app/mixins/draggable.js
+++ b/app/mixins/draggable.js
@@ -17,7 +17,7 @@ export default Ember.Mixin.create({
uiDragEvents: [ 'create_drag', 'start_drag', 'drag_drag', 'stop_drag' ],
didInsertElement() {
- this._super.init();
+ this._super();
// get available options and events
var options = this._gatherDragOptions();
diff --git a/app/mixins/droppable.js b/app/mixins/droppable.js
index 203ab21..7e557e8 100644
--- a/app/mixins/droppable.js
+++ b/app/mixins/droppable.js
@@ -16,7 +16,7 @@ export default Ember.Mixin.create({
'out_drop', 'drop_drop' ],
didInsertElement() {
- this._super.init();
+ this._super();
// get available options and events
var options = this._gatherDropOptions();
diff --git a/app/mixins/live-data.js b/app/mixins/live-data.js
index 2ba081e..059c2a4 100644
--- a/app/mixins/live-data.js
+++ b/app/mixins/live-data.js
@@ -20,7 +20,7 @@ export default Ember.Mixin.create({
_sockets: {},
init: function() {
- this._super.init();
+ this._super();
// fetch the simulations for the first time
this._fetchRunningSimulations();
diff --git a/app/mixins/resizable.js b/app/mixins/resizable.js
index 50c1383..28a1073 100644
--- a/app/mixins/resizable.js
+++ b/app/mixins/resizable.js
@@ -18,7 +18,7 @@ export default Ember.Mixin.create({
uiResizeEvents: [ 'create_resize', 'start_resize', 'resize_resize', 'stop_resize' ],
didInsertElement() {
- this._super.init();
+ this._super();
// get available options and events
var options = this._gatherResizeOptions();
diff --git a/app/mixins/sortable.js b/app/mixins/sortable.js
index a69d4e8..737367f 100644
--- a/app/mixins/sortable.js
+++ b/app/mixins/sortable.js
@@ -21,7 +21,7 @@ export default Ember.Mixin.create({
'sort_sort', 'start_sort', 'stop_sort', 'update_sort' ],
didInsertElement() {
- this._super.init();
+ this._super();
// get available options and events
var options = this._gatherSortOptions();
diff --git a/ember-cli-build.js b/ember-cli-build.js
index ab8a0ed..3418f9e 100644
--- a/ember-cli-build.js
+++ b/ember-cli-build.js
@@ -22,6 +22,11 @@ module.exports = function(defaults) {
app.import('bower_components/bootstrap/dist/js/bootstrap.js');
app.import('bower_components/flot/jquery.flot.time.js');
+ app.import('bower_components/jquery-ui/jquery-ui.js');
+
+ app.import('bower_components/jquery-ui/themes/smoothness/jquery-ui.css');
+
+ app.import('bower_components/jquery-ui/themes/smoothness/images/ui-icons_222222_256x240.png', { destDir: 'assets/images' });
return app.toTree();
};
diff --git a/package.json b/package.json
index 4640180..1a3bcb0 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,6 @@
"ember-cli-htmlbars": "^1.1.1",
"ember-cli-htmlbars-inline-precompile": "^0.3.3",
"ember-cli-inject-live-reload": "^1.4.1",
- "ember-cli-jquery-ui": "0.0.20",
"ember-cli-jshint": "^2.0.1",
"ember-cli-qunit": "^3.0.1",
"ember-cli-release": "^0.2.9",
@@ -40,10 +39,10 @@
"ember-modal-dialog": "^0.9.0",
"ember-resolver": "^2.0.3",
"ember-simple-auth": "^1.1.0",
+ "ember-source": "^2.11.0",
"ember-tether": "0.3.1",
"ember-truth-helpers": "1.2.0",
"ember-uploader": "1.2.3",
- "ember-source": "^2.11.0",
"ember-welcome-page": "^2.0.2",
"loader.js": "^4.0.10"
},
From bc50ec11a6734f82096fed203276d3a7323f5539 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Sat, 4 Feb 2017 15:31:57 +0100
Subject: [PATCH 050/556] Allow empty widget names
Fix resetting widget dialog error message
---
app/components/widget-label.js | 1 +
app/components/widget-plot.js | 5 -----
app/components/widget-table.js | 6 +-----
app/components/widget-value.js | 6 +-----
app/templates/components/widget-plot.hbs | 10 ++++++----
app/templates/components/widget-value.hbs | 2 +-
6 files changed, 10 insertions(+), 20 deletions(-)
diff --git a/app/components/widget-label.js b/app/components/widget-label.js
index 732430e..5fd22fe 100644
--- a/app/components/widget-label.js
+++ b/app/components/widget-label.js
@@ -19,6 +19,7 @@ export default WidgetAbstract.extend({
if (this.get('editing') === true) {
// prepare modal
this.set('name', this.get('widget.name'));
+ this.set('errorMessage', null);
// show modal
this.set('isShowingModal', true);
diff --git a/app/components/widget-plot.js b/app/components/widget-plot.js
index 9b553d7..7574de0 100644
--- a/app/components/widget-plot.js
+++ b/app/components/widget-plot.js
@@ -188,11 +188,6 @@ export default WidgetAbstract.extend({
// verify properties
let properties = this.getProperties('name');
- if (properties['name'] === null || properties['name'] === "") {
- this.set('errorMessage', 'Widget name is missing');
- return;
- }
-
// set simulator by simulation model name
let simulationModelName = this.get('simulationModelName');
let self = this;
diff --git a/app/components/widget-table.js b/app/components/widget-table.js
index 8272310..74c14bd 100644
--- a/app/components/widget-table.js
+++ b/app/components/widget-table.js
@@ -83,6 +83,7 @@ export default WidgetAbstract.extend({
if (this.get('editing') === true) {
// prepare modal
this.set('name', this.get('widget.name'));
+ this.set('errorMessage', null);
// get simlator name from id
let self = this;
@@ -117,11 +118,6 @@ export default WidgetAbstract.extend({
// verify properties
let properties = this.getProperties('name');
- if (properties['name'] === null || properties['name'] === "") {
- this.set('errorMessage', 'Widget name is missing');
- return;
- }
-
// set simulator by simulation model name
let simulationModelName = this.get('simulationModelName');
let self = this;
diff --git a/app/components/widget-value.js b/app/components/widget-value.js
index ed42fb8..efcbfbe 100644
--- a/app/components/widget-value.js
+++ b/app/components/widget-value.js
@@ -44,6 +44,7 @@ export default WidgetAbstract.extend({
if (this.get('editing') === true) {
// prepare modal
this.set('name', this.get('widget.name'));
+ this.set('errorMessage', null);
// get signal mapping for simulation model
let self = this;
@@ -82,11 +83,6 @@ export default WidgetAbstract.extend({
// verify properties
let properties = this.getProperties('name');
- if (properties['name'] === null || properties['name'] === "") {
- this.set('errorMessage', 'Widget name is missing');
- return;
- }
-
// set simulator by simulation model name
let simulationModelName = this.get('simulationModelName');
let self = this;
diff --git a/app/templates/components/widget-plot.hbs b/app/templates/components/widget-plot.hbs
index 7fd4040..8e95dda 100644
--- a/app/templates/components/widget-plot.hbs
+++ b/app/templates/components/widget-plot.hbs
@@ -35,6 +35,12 @@
{{#modal-dialog attachment="middle center" translucentOverlay=true}}
Plot
+ {{#if errorMessage}}
+
+ Error: {{errorMessage}}
+
+ {{/if}}
+
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
{{/modal-dialog}}
{{/if}}
diff --git a/app/templates/components/widget-value.hbs b/app/templates/components/widget-value.hbs
index 6bfb445..00c246b 100644
--- a/app/templates/components/widget-value.hbs
+++ b/app/templates/components/widget-value.hbs
@@ -1,4 +1,4 @@
-{{name}}: {{value}}
+{{name}}{{#if name}}:{{/if}} {{value}}
{{#if isShowingModal}}
{{#modal-dialog attachment="middle center" translucentOverlay=true}}
From 0cf1884192dac7652b6fdb8e8272414cdc789b07 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Thu, 2 Mar 2017 12:47:52 +0100
Subject: [PATCH 051/556] !!! Move complete project to ReactJS !!!
ATTENTION: The complete project is ported to ReactJS.
Motivation: React (with flux) is much more flexible and performant in the
use case of VILLASweb. Ember is a good framework, but it has many tradeoffs
to its easy handling and feature completeness. Many work arounds had to be done
to get ember to work the way needed. Because ReactJS gives the developer much
more flexibility and feature choice, VILLASweb can be build much better.
The aim is to only depends on needed packages and be as performance as possible.
This new version still works with the current backend!
For library usage see package.json.
This first version contains the same base website as the old version but
changed back to legacy color scheme. Simulators are loaded from and can be added
to the backend as a proof-of-concept.
---
.bowerrc | 4 -
.editorconfig | 20 -
.ember-cli | 9 -
.gitignore | 21 +-
.jshintrc | 32 -
.travis.yml | 24 -
.watchmanconfig | 3 -
README.md | 1588 ++++++++++++++++-
app/adapters/application.js | 25 -
app/app.js | 27 -
app/authenticators/custom.js | 57 -
app/authorizers/custom.js | 21 -
app/components/.gitkeep | 0
app/components/draggable-dropzone.js | 41 -
app/components/draggable-item.js | 25 -
app/components/flow-plot.js | 27 -
app/components/widget-abstract.js | 93 -
app/components/widget-container.js | 53 -
app/components/widget-image.js | 105 --
app/components/widget-label.js | 60 -
app/components/widget-plot.js | 292 ---
app/components/widget-table.js | 170 --
app/components/widget-value.js | 167 --
app/controllers/.gitkeep | 0
app/controllers/login.js | 23 -
app/controllers/me.js | 25 -
app/controllers/project/index.js | 116 --
app/controllers/projects.js | 151 --
app/controllers/simulation-model/index.js | 48 -
app/controllers/simulation/index.js | 193 --
app/controllers/simulations.js | 153 --
app/controllers/simulators.js | 158 --
app/controllers/user/delete.js | 28 -
app/controllers/user/edit.js | 28 -
app/controllers/user/index.js | 26 -
app/controllers/user/new.js | 30 -
app/controllers/visualization/edit.js | 137 --
app/helpers/.gitkeep | 0
app/index.html | 25 -
app/mixins/draggable.js | 84 -
app/mixins/droppable.js | 83 -
app/mixins/fetch-live-data.js | 61 -
app/mixins/live-data.js | 186 --
app/mixins/resizable.js | 88 -
app/mixins/sortable.js | 91 -
app/models/.gitkeep | 0
app/models/file.js | 18 -
app/models/project.js | 19 -
app/models/simulation-data.js | 45 -
app/models/simulation-model.js | 20 -
app/models/simulation.js | 20 -
app/models/simulator-status.js | 5 -
app/models/simulator.js | 18 -
app/models/user.js | 22 -
app/models/visualization.js | 18 -
app/models/widget.js | 23 -
app/resolver.js | 3 -
app/router.js | 55 -
app/routes/.gitkeep | 0
app/routes/application.js | 34 -
app/routes/dialog/plot/value.js | 4 -
app/routes/index.js | 15 -
app/routes/login.js | 14 -
app/routes/logout.js | 17 -
app/routes/me.js | 18 -
app/routes/project/index.js | 17 -
app/routes/projects.js | 25 -
app/routes/simulation-model/index.js | 17 -
app/routes/simulation/index.js | 20 -
app/routes/simulations.js | 21 -
app/routes/simulators.js | 18 -
app/routes/user/delete.js | 17 -
app/routes/user/edit.js | 17 -
app/routes/user/index.js | 17 -
app/routes/user/new.js | 14 -
app/routes/visualization/edit.js | 17 -
app/routes/visualization/index.js | 17 -
app/serializers/application.js | 15 -
app/serializers/project.js | 17 -
app/serializers/simulation-model.js | 16 -
app/serializers/simulation.js | 18 -
app/serializers/user.js | 16 -
app/serializers/visualization.js | 17 -
app/services/session-user.js | 39 -
app/styles/app.scss | 277 ---
app/styles/models.scss | 51 -
app/styles/projects.scss | 46 -
app/styles/simulation-models.scss | 19 -
app/styles/simulations.scss | 46 -
app/styles/simulators.scss | 27 -
app/styles/widgets.scss | 91 -
app/templates/404.hbs | 1 -
app/templates/application.hbs | 28 -
app/templates/components/.gitkeep | 0
.../components/draggable-dropzone.hbs | 1 -
app/templates/components/draggable-item.hbs | 1 -
app/templates/components/file-upload.hbs | 1 -
app/templates/components/flow-plot.hbs | 1 -
app/templates/components/widget-abstract.hbs | 1 -
app/templates/components/widget-chart.hbs | 1 -
app/templates/components/widget-container.hbs | 3 -
app/templates/components/widget-image.hbs | 51 -
app/templates/components/widget-label.hbs | 27 -
app/templates/components/widget-plot.hbs | 112 --
app/templates/components/widget-table.hbs | 56 -
app/templates/components/widget-value.hbs | 55 -
app/templates/dialog/project.hbs | 68 -
app/templates/dialog/projects.hbs | 92 -
app/templates/dialog/simulation.hbs | 108 --
app/templates/dialog/simulations.hbs | 86 -
app/templates/dialog/simulators.hbs | 118 --
app/templates/index.hbs | 1 -
app/templates/login.hbs | 19 -
app/templates/logout.hbs | 1 -
app/templates/me.hbs | 20 -
app/templates/project/index.hbs | 31 -
app/templates/projects.hbs | 33 -
app/templates/simulation-model/index.hbs | 31 -
app/templates/simulation/index.hbs | 35 -
app/templates/simulations.hbs | 34 -
app/templates/simulators.hbs | 43 -
app/templates/user/delete.hbs | 10 -
app/templates/user/edit.hbs | 14 -
app/templates/user/index.hbs | 11 -
app/templates/user/new.hbs | 21 -
app/templates/visualization/edit.hbs | 37 -
app/templates/visualization/index.hbs | 9 -
app/transforms/array.js | 20 -
bower.json | 8 -
config/environment.js | 49 -
ember-cli-build.js | 32 -
package.json | 70 +-
public/crossdomain.xml | 15 -
public/favicon.ico | Bin 0 -> 24838 bytes
public/index.html | 31 +
public/robots.txt | 3 -
src/App.test.js | 8 +
src/api/rest-api.js | 46 +
.../application.js => src/app-dispatcher.js | 14 +-
.../components/footer.js | 24 +-
src/components/header.js | 24 +
src/components/menu-sidebar.js | 30 +
src/components/table.js | 53 +
src/containers/app.js | 55 +
src/containers/home.js | 36 +
src/containers/projects.js | 39 +
src/containers/simulators.js | 72 +
src/data-managers/simulators-data-manager.js | 43 +
.../visualization => src}/index.js | 16 +-
src/router.js | 32 +
src/stores/simulator-store.js | 60 +
src/stores/villas-store.js | 31 +
src/styles/app.css | 138 ++
app/routes/404.js => src/styles/home.css | 11 +-
src/styles/index.css | 4 +
.../value.js => src/styles/projects.css | 11 +-
.../styles/simulators.css | 11 +-
testem.js | 13 -
tests/.jshintrc | 52 -
tests/helpers/destroy-app.js | 5 -
tests/helpers/module-for-acceptance.js | 23 -
tests/helpers/resolver.js | 11 -
tests/helpers/start-app.js | 18 -
tests/index.html | 33 -
tests/integration/.gitkeep | 0
.../components/draggable-dropzone-test.js | 24 -
.../components/draggable-item-test.js | 24 -
.../components/file-upload-test.js | 24 -
.../integration/components/flow-plot-test.js | 24 -
.../components/plot-abstract-test.js | 24 -
.../integration/components/plot-chart-test.js | 24 -
.../components/plot-container-test.js | 24 -
.../integration/components/plot-table-test.js | 24 -
.../integration/components/plot-value-test.js | 24 -
.../components/widget-image-test.js | 24 -
.../components/widget-label-test.js | 24 -
.../components/widget-plot-test.js | 24 -
tests/test-helper.js | 6 -
tests/unit/.gitkeep | 0
tests/unit/adapters/application-test.js | 12 -
tests/unit/controllers/application-test.js | 12 -
.../controllers/dialog/plot/value-test.js | 12 -
tests/unit/controllers/login-test.js | 12 -
tests/unit/controllers/project/index-test.js | 12 -
tests/unit/controllers/projects-test.js | 12 -
tests/unit/controllers/projects/new-test.js | 12 -
.../simulation-model/index-test.js | 12 -
.../unit/controllers/simulation/index-test.js | 12 -
tests/unit/controllers/simulations-test.js | 12 -
tests/unit/controllers/simulators-test.js | 12 -
tests/unit/controllers/user/edit-test.js | 12 -
tests/unit/controllers/users/delete-test.js | 12 -
tests/unit/controllers/users/edit-test.js | 12 -
tests/unit/controllers/users/index-test.js | 12 -
tests/unit/controllers/users/new-test.js | 12 -
.../controllers/visualization/edit-test.js | 12 -
.../controllers/visualization/index-test.js | 12 -
tests/unit/mixins/draggable-test.js | 12 -
tests/unit/mixins/droppable-test.js | 12 -
tests/unit/mixins/fetch-live-data-test.js | 12 -
tests/unit/mixins/live-data-test.js | 12 -
tests/unit/mixins/resizable-test.js | 12 -
tests/unit/mixins/sortable-test.js | 12 -
tests/unit/models/file-test.js | 12 -
tests/unit/models/plot-test.js | 12 -
tests/unit/models/project-test.js | 12 -
tests/unit/models/simulation-data-test.js | 12 -
tests/unit/models/simulation-model-test.js | 12 -
tests/unit/models/simulation-test.js | 12 -
tests/unit/models/simulator-status-test.js | 12 -
tests/unit/models/simulator-test.js | 12 -
tests/unit/models/user-test.js | 12 -
tests/unit/models/visualization-test.js | 12 -
tests/unit/routes/404-test.js | 11 -
tests/unit/routes/application-test.js | 11 -
tests/unit/routes/dialog/plot/value-test.js | 11 -
tests/unit/routes/index-test.js | 11 -
tests/unit/routes/login-test.js | 11 -
tests/unit/routes/logout-test.js | 11 -
tests/unit/routes/me-test.js | 11 -
tests/unit/routes/models-test.js | 11 -
tests/unit/routes/projects-test.js | 11 -
tests/unit/routes/projects/delete-test.js | 11 -
tests/unit/routes/projects/edit-test.js | 11 -
tests/unit/routes/projects/index-test.js | 11 -
tests/unit/routes/projects/new-test.js | 11 -
tests/unit/routes/projects/project-test.js | 11 -
.../routes/simulation-model/index-test.js | 11 -
tests/unit/routes/simulation/index-test.js | 11 -
tests/unit/routes/simulations-test.js | 11 -
tests/unit/routes/simulators-test.js | 11 -
tests/unit/routes/simulators/delete-test.js | 11 -
tests/unit/routes/simulators/edit-test.js | 11 -
tests/unit/routes/simulators/index-test.js | 11 -
tests/unit/routes/user/delete-test.js | 11 -
tests/unit/routes/user/edit-test.js | 11 -
tests/unit/routes/user/index-test.js | 11 -
tests/unit/routes/user/new-test.js | 11 -
tests/unit/routes/visualization/edit-test.js | 11 -
tests/unit/routes/visualization/index-test.js | 11 -
tests/unit/serializers/application-test.js | 15 -
tests/unit/serializers/project-test.js | 15 -
.../unit/serializers/simulation-model-test.js | 15 -
tests/unit/serializers/simulation-test.js | 15 -
tests/unit/serializers/user-test.js | 15 -
tests/unit/serializers/visualization-test.js | 15 -
tests/unit/services/session-user-test.js | 12 -
tests/unit/transforms/array-test.js | 12 -
todo.md | 89 -
vendor/.gitkeep | 0
250 files changed, 2330 insertions(+), 7052 deletions(-)
delete mode 100644 .bowerrc
delete mode 100644 .editorconfig
delete mode 100644 .ember-cli
delete mode 100644 .jshintrc
delete mode 100644 .travis.yml
delete mode 100644 .watchmanconfig
delete mode 100644 app/adapters/application.js
delete mode 100644 app/app.js
delete mode 100644 app/authenticators/custom.js
delete mode 100644 app/authorizers/custom.js
delete mode 100644 app/components/.gitkeep
delete mode 100644 app/components/draggable-dropzone.js
delete mode 100644 app/components/draggable-item.js
delete mode 100644 app/components/flow-plot.js
delete mode 100644 app/components/widget-abstract.js
delete mode 100644 app/components/widget-container.js
delete mode 100644 app/components/widget-image.js
delete mode 100644 app/components/widget-label.js
delete mode 100644 app/components/widget-plot.js
delete mode 100644 app/components/widget-table.js
delete mode 100644 app/components/widget-value.js
delete mode 100644 app/controllers/.gitkeep
delete mode 100644 app/controllers/login.js
delete mode 100644 app/controllers/me.js
delete mode 100644 app/controllers/project/index.js
delete mode 100644 app/controllers/projects.js
delete mode 100644 app/controllers/simulation-model/index.js
delete mode 100644 app/controllers/simulation/index.js
delete mode 100644 app/controllers/simulations.js
delete mode 100644 app/controllers/simulators.js
delete mode 100644 app/controllers/user/delete.js
delete mode 100644 app/controllers/user/edit.js
delete mode 100644 app/controllers/user/index.js
delete mode 100644 app/controllers/user/new.js
delete mode 100644 app/controllers/visualization/edit.js
delete mode 100644 app/helpers/.gitkeep
delete mode 100644 app/index.html
delete mode 100644 app/mixins/draggable.js
delete mode 100644 app/mixins/droppable.js
delete mode 100644 app/mixins/fetch-live-data.js
delete mode 100644 app/mixins/live-data.js
delete mode 100644 app/mixins/resizable.js
delete mode 100644 app/mixins/sortable.js
delete mode 100644 app/models/.gitkeep
delete mode 100644 app/models/file.js
delete mode 100644 app/models/project.js
delete mode 100644 app/models/simulation-data.js
delete mode 100644 app/models/simulation-model.js
delete mode 100644 app/models/simulation.js
delete mode 100644 app/models/simulator-status.js
delete mode 100644 app/models/simulator.js
delete mode 100644 app/models/user.js
delete mode 100644 app/models/visualization.js
delete mode 100644 app/models/widget.js
delete mode 100644 app/resolver.js
delete mode 100644 app/router.js
delete mode 100644 app/routes/.gitkeep
delete mode 100644 app/routes/application.js
delete mode 100644 app/routes/dialog/plot/value.js
delete mode 100644 app/routes/index.js
delete mode 100644 app/routes/login.js
delete mode 100644 app/routes/logout.js
delete mode 100644 app/routes/me.js
delete mode 100644 app/routes/project/index.js
delete mode 100644 app/routes/projects.js
delete mode 100644 app/routes/simulation-model/index.js
delete mode 100644 app/routes/simulation/index.js
delete mode 100644 app/routes/simulations.js
delete mode 100644 app/routes/simulators.js
delete mode 100644 app/routes/user/delete.js
delete mode 100644 app/routes/user/edit.js
delete mode 100644 app/routes/user/index.js
delete mode 100644 app/routes/user/new.js
delete mode 100644 app/routes/visualization/edit.js
delete mode 100644 app/routes/visualization/index.js
delete mode 100644 app/serializers/application.js
delete mode 100644 app/serializers/project.js
delete mode 100644 app/serializers/simulation-model.js
delete mode 100644 app/serializers/simulation.js
delete mode 100644 app/serializers/user.js
delete mode 100644 app/serializers/visualization.js
delete mode 100644 app/services/session-user.js
delete mode 100644 app/styles/app.scss
delete mode 100644 app/styles/models.scss
delete mode 100644 app/styles/projects.scss
delete mode 100644 app/styles/simulation-models.scss
delete mode 100644 app/styles/simulations.scss
delete mode 100644 app/styles/simulators.scss
delete mode 100644 app/styles/widgets.scss
delete mode 100644 app/templates/404.hbs
delete mode 100644 app/templates/application.hbs
delete mode 100644 app/templates/components/.gitkeep
delete mode 100644 app/templates/components/draggable-dropzone.hbs
delete mode 100644 app/templates/components/draggable-item.hbs
delete mode 100644 app/templates/components/file-upload.hbs
delete mode 100644 app/templates/components/flow-plot.hbs
delete mode 100644 app/templates/components/widget-abstract.hbs
delete mode 100644 app/templates/components/widget-chart.hbs
delete mode 100644 app/templates/components/widget-container.hbs
delete mode 100644 app/templates/components/widget-image.hbs
delete mode 100644 app/templates/components/widget-label.hbs
delete mode 100644 app/templates/components/widget-plot.hbs
delete mode 100644 app/templates/components/widget-table.hbs
delete mode 100644 app/templates/components/widget-value.hbs
delete mode 100644 app/templates/dialog/project.hbs
delete mode 100644 app/templates/dialog/projects.hbs
delete mode 100644 app/templates/dialog/simulation.hbs
delete mode 100644 app/templates/dialog/simulations.hbs
delete mode 100644 app/templates/dialog/simulators.hbs
delete mode 100644 app/templates/index.hbs
delete mode 100644 app/templates/login.hbs
delete mode 100644 app/templates/logout.hbs
delete mode 100644 app/templates/me.hbs
delete mode 100644 app/templates/project/index.hbs
delete mode 100644 app/templates/projects.hbs
delete mode 100644 app/templates/simulation-model/index.hbs
delete mode 100644 app/templates/simulation/index.hbs
delete mode 100644 app/templates/simulations.hbs
delete mode 100644 app/templates/simulators.hbs
delete mode 100644 app/templates/user/delete.hbs
delete mode 100644 app/templates/user/edit.hbs
delete mode 100644 app/templates/user/index.hbs
delete mode 100644 app/templates/user/new.hbs
delete mode 100644 app/templates/visualization/edit.hbs
delete mode 100644 app/templates/visualization/index.hbs
delete mode 100644 app/transforms/array.js
delete mode 100644 bower.json
delete mode 100644 config/environment.js
delete mode 100644 ember-cli-build.js
delete mode 100644 public/crossdomain.xml
create mode 100644 public/favicon.ico
create mode 100644 public/index.html
delete mode 100644 public/robots.txt
create mode 100644 src/App.test.js
create mode 100644 src/api/rest-api.js
rename app/controllers/application.js => src/app-dispatcher.js (59%)
rename app/components/file-upload.js => src/components/footer.js (51%)
create mode 100644 src/components/header.js
create mode 100644 src/components/menu-sidebar.js
create mode 100644 src/components/table.js
create mode 100644 src/containers/app.js
create mode 100644 src/containers/home.js
create mode 100644 src/containers/projects.js
create mode 100644 src/containers/simulators.js
create mode 100644 src/data-managers/simulators-data-manager.js
rename {app/controllers/visualization => src}/index.js (56%)
create mode 100644 src/router.js
create mode 100644 src/stores/simulator-store.js
create mode 100644 src/stores/villas-store.js
create mode 100644 src/styles/app.css
rename app/routes/404.js => src/styles/home.css (66%)
create mode 100644 src/styles/index.css
rename app/controllers/dialog/widget/value.js => src/styles/projects.css (65%)
rename app/components/widget-chart.js => src/styles/simulators.css (64%)
delete mode 100644 testem.js
delete mode 100644 tests/.jshintrc
delete mode 100644 tests/helpers/destroy-app.js
delete mode 100644 tests/helpers/module-for-acceptance.js
delete mode 100644 tests/helpers/resolver.js
delete mode 100644 tests/helpers/start-app.js
delete mode 100644 tests/index.html
delete mode 100644 tests/integration/.gitkeep
delete mode 100644 tests/integration/components/draggable-dropzone-test.js
delete mode 100644 tests/integration/components/draggable-item-test.js
delete mode 100644 tests/integration/components/file-upload-test.js
delete mode 100644 tests/integration/components/flow-plot-test.js
delete mode 100644 tests/integration/components/plot-abstract-test.js
delete mode 100644 tests/integration/components/plot-chart-test.js
delete mode 100644 tests/integration/components/plot-container-test.js
delete mode 100644 tests/integration/components/plot-table-test.js
delete mode 100644 tests/integration/components/plot-value-test.js
delete mode 100644 tests/integration/components/widget-image-test.js
delete mode 100644 tests/integration/components/widget-label-test.js
delete mode 100644 tests/integration/components/widget-plot-test.js
delete mode 100644 tests/test-helper.js
delete mode 100644 tests/unit/.gitkeep
delete mode 100644 tests/unit/adapters/application-test.js
delete mode 100644 tests/unit/controllers/application-test.js
delete mode 100644 tests/unit/controllers/dialog/plot/value-test.js
delete mode 100644 tests/unit/controllers/login-test.js
delete mode 100644 tests/unit/controllers/project/index-test.js
delete mode 100644 tests/unit/controllers/projects-test.js
delete mode 100644 tests/unit/controllers/projects/new-test.js
delete mode 100644 tests/unit/controllers/simulation-model/index-test.js
delete mode 100644 tests/unit/controllers/simulation/index-test.js
delete mode 100644 tests/unit/controllers/simulations-test.js
delete mode 100644 tests/unit/controllers/simulators-test.js
delete mode 100644 tests/unit/controllers/user/edit-test.js
delete mode 100644 tests/unit/controllers/users/delete-test.js
delete mode 100644 tests/unit/controllers/users/edit-test.js
delete mode 100644 tests/unit/controllers/users/index-test.js
delete mode 100644 tests/unit/controllers/users/new-test.js
delete mode 100644 tests/unit/controllers/visualization/edit-test.js
delete mode 100644 tests/unit/controllers/visualization/index-test.js
delete mode 100644 tests/unit/mixins/draggable-test.js
delete mode 100644 tests/unit/mixins/droppable-test.js
delete mode 100644 tests/unit/mixins/fetch-live-data-test.js
delete mode 100644 tests/unit/mixins/live-data-test.js
delete mode 100644 tests/unit/mixins/resizable-test.js
delete mode 100644 tests/unit/mixins/sortable-test.js
delete mode 100644 tests/unit/models/file-test.js
delete mode 100644 tests/unit/models/plot-test.js
delete mode 100644 tests/unit/models/project-test.js
delete mode 100644 tests/unit/models/simulation-data-test.js
delete mode 100644 tests/unit/models/simulation-model-test.js
delete mode 100644 tests/unit/models/simulation-test.js
delete mode 100644 tests/unit/models/simulator-status-test.js
delete mode 100644 tests/unit/models/simulator-test.js
delete mode 100644 tests/unit/models/user-test.js
delete mode 100644 tests/unit/models/visualization-test.js
delete mode 100644 tests/unit/routes/404-test.js
delete mode 100644 tests/unit/routes/application-test.js
delete mode 100644 tests/unit/routes/dialog/plot/value-test.js
delete mode 100644 tests/unit/routes/index-test.js
delete mode 100644 tests/unit/routes/login-test.js
delete mode 100644 tests/unit/routes/logout-test.js
delete mode 100644 tests/unit/routes/me-test.js
delete mode 100644 tests/unit/routes/models-test.js
delete mode 100644 tests/unit/routes/projects-test.js
delete mode 100644 tests/unit/routes/projects/delete-test.js
delete mode 100644 tests/unit/routes/projects/edit-test.js
delete mode 100644 tests/unit/routes/projects/index-test.js
delete mode 100644 tests/unit/routes/projects/new-test.js
delete mode 100644 tests/unit/routes/projects/project-test.js
delete mode 100644 tests/unit/routes/simulation-model/index-test.js
delete mode 100644 tests/unit/routes/simulation/index-test.js
delete mode 100644 tests/unit/routes/simulations-test.js
delete mode 100644 tests/unit/routes/simulators-test.js
delete mode 100644 tests/unit/routes/simulators/delete-test.js
delete mode 100644 tests/unit/routes/simulators/edit-test.js
delete mode 100644 tests/unit/routes/simulators/index-test.js
delete mode 100644 tests/unit/routes/user/delete-test.js
delete mode 100644 tests/unit/routes/user/edit-test.js
delete mode 100644 tests/unit/routes/user/index-test.js
delete mode 100644 tests/unit/routes/user/new-test.js
delete mode 100644 tests/unit/routes/visualization/edit-test.js
delete mode 100644 tests/unit/routes/visualization/index-test.js
delete mode 100644 tests/unit/serializers/application-test.js
delete mode 100644 tests/unit/serializers/project-test.js
delete mode 100644 tests/unit/serializers/simulation-model-test.js
delete mode 100644 tests/unit/serializers/simulation-test.js
delete mode 100644 tests/unit/serializers/user-test.js
delete mode 100644 tests/unit/serializers/visualization-test.js
delete mode 100644 tests/unit/services/session-user-test.js
delete mode 100644 tests/unit/transforms/array-test.js
delete mode 100644 todo.md
delete mode 100644 vendor/.gitkeep
diff --git a/.bowerrc b/.bowerrc
deleted file mode 100644
index 959e169..0000000
--- a/.bowerrc
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "directory": "bower_components",
- "analytics": false
-}
diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 219985c..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-# EditorConfig helps developers define and maintain consistent
-# coding styles between different editors and IDEs
-# editorconfig.org
-
-root = true
-
-
-[*]
-end_of_line = lf
-charset = utf-8
-trim_trailing_whitespace = true
-insert_final_newline = true
-indent_style = space
-indent_size = 2
-
-[*.hbs]
-insert_final_newline = false
-
-[*.{diff,md}]
-trim_trailing_whitespace = false
diff --git a/.ember-cli b/.ember-cli
deleted file mode 100644
index ee64cfe..0000000
--- a/.ember-cli
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- /**
- Ember CLI sends analytics information by default. The data is completely
- anonymous, but there are times when you might want to disable this behavior.
-
- Setting `disableAnalytics` to true will prevent any data from being sent.
- */
- "disableAnalytics": false
-}
diff --git a/.gitignore b/.gitignore
index 5ad14dd..927d17b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,17 +1,18 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
-# compiled output
-/dist
-/tmp
-
# dependencies
/node_modules
-/bower_components
+
+# testing
+/coverage
+
+# production
+/build
# misc
-/.sass-cache
-/connect.lock
-/coverage/*
-/libpeerconnection.log
+.DS_Store
+.env
npm-debug.log*
-testem.log
+yarn-debug.log*
+yarn-error.log*
+
diff --git a/.jshintrc b/.jshintrc
deleted file mode 100644
index d421faa..0000000
--- a/.jshintrc
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "predef": [
- "document",
- "window",
- "-Promise"
- ],
- "browser": true,
- "boss": true,
- "curly": true,
- "debug": false,
- "devel": true,
- "eqeqeq": true,
- "evil": true,
- "forin": false,
- "immed": false,
- "laxbreak": false,
- "newcap": true,
- "noarg": true,
- "noempty": false,
- "nonew": false,
- "nomen": false,
- "onevar": false,
- "plusplus": false,
- "regexp": false,
- "undef": true,
- "sub": true,
- "strict": false,
- "white": false,
- "eqnull": true,
- "esversion": 6,
- "unused": true
-}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index a75f20e..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,24 +0,0 @@
----
-language: node_js
-node_js:
- - "4"
-
-sudo: false
-
-cache:
- directories:
- - $HOME/.npm
- - $HOME/.cache # includes bowers cache
-
-before_install:
- - npm config set spin false
- - npm install -g bower phantomjs-prebuilt
- - bower --version
- - phantomjs --version
-
-install:
- - npm install
- - bower install
-
-script:
- - npm test
diff --git a/.watchmanconfig b/.watchmanconfig
deleted file mode 100644
index e7834e3..0000000
--- a/.watchmanconfig
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "ignore_dirs": ["tmp", "dist"]
-}
diff --git a/README.md b/README.md
index 8081f80..e290b93 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,1572 @@
-# villasweb-frontend
+This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
-This README outlines the details of collaborating on this Ember application.
-A short introduction of this app could easily go here.
+Below you will find some information on how to perform common tasks.
+You can find the most recent version of this guide [here](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md).
-## Prerequisites
+## Table of Contents
-You will need the following things properly installed on your computer.
+- [Updating to New Releases](#updating-to-new-releases)
+- [Sending Feedback](#sending-feedback)
+- [Folder Structure](#folder-structure)
+- [Available Scripts](#available-scripts)
+ - [npm start](#npm-start)
+ - [npm test](#npm-test)
+ - [npm run build](#npm-run-build)
+ - [npm run eject](#npm-run-eject)
+- [Supported Language Features and Polyfills](#supported-language-features-and-polyfills)
+- [Syntax Highlighting in the Editor](#syntax-highlighting-in-the-editor)
+- [Displaying Lint Output in the Editor](#displaying-lint-output-in-the-editor)
+- [Debugging in the Editor](#debugging-in-the-editor)
+- [Changing the Page ``](#changing-the-page-title)
+- [Installing a Dependency](#installing-a-dependency)
+- [Importing a Component](#importing-a-component)
+- [Adding a Stylesheet](#adding-a-stylesheet)
+- [Post-Processing CSS](#post-processing-css)
+- [Adding a CSS Preprocessor (Sass, Less etc.)](#adding-a-css-preprocessor-sass-less-etc)
+- [Adding Images and Fonts](#adding-images-and-fonts)
+- [Using the `public` Folder](#using-the-public-folder)
+ - [Changing the HTML](#changing-the-html)
+ - [Adding Assets Outside of the Module System](#adding-assets-outside-of-the-module-system)
+ - [When to Use the `public` Folder](#when-to-use-the-public-folder)
+- [Using Global Variables](#using-global-variables)
+- [Adding Bootstrap](#adding-bootstrap)
+ - [Using a Custom Theme](#using-a-custom-theme)
+- [Adding Flow](#adding-flow)
+- [Adding Custom Environment Variables](#adding-custom-environment-variables)
+ - [Referencing Environment Variables in the HTML](#referencing-environment-variables-in-the-html)
+ - [Adding Temporary Environment Variables In Your Shell](#adding-temporary-environment-variables-in-your-shell)
+ - [Adding Development Environment Variables In `.env`](#adding-development-environment-variables-in-env)
+- [Can I Use Decorators?](#can-i-use-decorators)
+- [Integrating with an API Backend](#integrating-with-an-api-backend)
+ - [Node](#node)
+ - [Ruby on Rails](#ruby-on-rails)
+- [Proxying API Requests in Development](#proxying-api-requests-in-development)
+- [Using HTTPS in Development](#using-https-in-development)
+- [Generating Dynamic ` ` Tags on the Server](#generating-dynamic-meta-tags-on-the-server)
+- [Pre-Rendering into Static HTML Files](#pre-rendering-into-static-html-files)
+- [Injecting Data from the Server into the Page](#injecting-data-from-the-server-into-the-page)
+- [Running Tests](#running-tests)
+ - [Filename Conventions](#filename-conventions)
+ - [Command Line Interface](#command-line-interface)
+ - [Version Control Integration](#version-control-integration)
+ - [Writing Tests](#writing-tests)
+ - [Testing Components](#testing-components)
+ - [Using Third Party Assertion Libraries](#using-third-party-assertion-libraries)
+ - [Initializing Test Environment](#initializing-test-environment)
+ - [Focusing and Excluding Tests](#focusing-and-excluding-tests)
+ - [Coverage Reporting](#coverage-reporting)
+ - [Continuous Integration](#continuous-integration)
+ - [Disabling jsdom](#disabling-jsdom)
+ - [Snapshot Testing](#snapshot-testing)
+ - [Editor Integration](#editor-integration)
+- [Developing Components in Isolation](#developing-components-in-isolation)
+- [Making a Progressive Web App](#making-a-progressive-web-app)
+- [Deployment](#deployment)
+ - [Serving Apps with Client-Side Routing](#serving-apps-with-client-side-routing)
+ - [Building for Relative Paths](#building-for-relative-paths)
+ - [Azure](#azure)
+ - [Firebase](#firebase)
+ - [GitHub Pages](#github-pages)
+ - [Heroku](#heroku)
+ - [Modulus](#modulus)
+ - [Netlify](#netlify)
+ - [Now](#now)
+ - [S3 and CloudFront](#s3-and-cloudfront)
+ - [Surge](#surge)
+- [Advanced Configuration](#advanced-configuration)
+- [Troubleshooting](#troubleshooting)
+ - [`npm start` doesn’t detect changes](#npm-start-doesnt-detect-changes)
+ - [`npm test` hangs on macOS Sierra](#npm-test-hangs-on-macos-sierra)
+ - [`npm run build` silently fails](#npm-run-build-silently-fails)
+ - [`npm run build` fails on Heroku](#npm-run-build-fails-on-heroku)
+- [Something Missing?](#something-missing)
-* [Git](https://git-scm.com/)
-* [Node.js](https://nodejs.org/) (with NPM)
-* [Bower](https://bower.io/)
-* [Ember CLI](https://ember-cli.com/)
-* [PhantomJS](http://phantomjs.org/)
+## Updating to New Releases
-## Installation
+Create React App is divided into two packages:
-* `git clone ` this repository
-* `cd villasweb-frontend`
-* `npm install`
-* `bower install`
+* `create-react-app` is a global command-line utility that you use to create new projects.
+* `react-scripts` is a development dependency in the generated projects (including this one).
-## Running / Development
+You almost never need to update `create-react-app` itself: it delegates all the setup to `react-scripts`.
-* `ember serve`
-* Visit your app at [http://localhost:4200](http://localhost:4200).
+When you run `create-react-app`, it always creates the project with the latest version of `react-scripts` so you’ll get all the new features and improvements in newly created apps automatically.
-### Code Generators
+To update an existing project to a new version of `react-scripts`, [open the changelog](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md), find the version you’re currently on (check `package.json` in this folder if you’re not sure), and apply the migration instructions for the newer versions.
-Make use of the many generators for code, try `ember help generate` for more details
+In most cases bumping the `react-scripts` version in `package.json` and running `npm install` in this folder should be enough, but it’s good to consult the [changelog](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md) for potential breaking changes.
-### Running Tests
+We commit to keeping the breaking changes minimal so you can upgrade `react-scripts` painlessly.
-* `ember test`
-* `ember test --server`
+## Sending Feedback
-### Building
+We are always open to [your feedback](https://github.com/facebookincubator/create-react-app/issues).
-* `ember build` (development)
-* `ember build --environment production` (production)
+## Folder Structure
-### Deploying
+After creation, your project should look like this:
-Specify what it takes to deploy your app.
+```
+my-app/
+ README.md
+ node_modules/
+ package.json
+ public/
+ index.html
+ favicon.ico
+ src/
+ App.css
+ App.js
+ App.test.js
+ index.css
+ index.js
+ logo.svg
+```
-## Further Reading / Useful Links
+For the project to build, **these files must exist with exact filenames**:
-* [ember.js](http://emberjs.com/)
-* [ember-cli](https://ember-cli.com/)
-* Development Browser Extensions
- * [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
- * [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/)
+* `public/index.html` is the page template;
+* `src/index.js` is the JavaScript entry point.
+
+You can delete or rename the other files.
+
+You may create subdirectories inside `src`. For faster rebuilds, only files inside `src` are processed by Webpack.
+You need to **put any JS and CSS files inside `src`**, or Webpack won’t see them.
+
+Only files inside `public` can be used from `public/index.html`.
+Read instructions below for using assets from JavaScript and HTML.
+
+You can, however, create more top-level directories.
+They will not be included in the production build so you can use them for things like documentation.
+
+## Available Scripts
+
+In the project directory, you can run:
+
+### `npm start`
+
+Runs the app in the development mode.
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
+
+The page will reload if you make edits.
+You will also see any lint errors in the console.
+
+### `npm test`
+
+Launches the test runner in the interactive watch mode.
+See the section about [running tests](#running-tests) for more information.
+
+### `npm run build`
+
+Builds the app for production to the `build` folder.
+It correctly bundles React in production mode and optimizes the build for the best performance.
+
+The build is minified and the filenames include the hashes.
+Your app is ready to be deployed!
+
+See the section about [deployment](#deployment) for more information.
+
+### `npm run eject`
+
+**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
+
+If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
+
+Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
+
+You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
+
+## Supported Language Features and Polyfills
+
+This project supports a superset of the latest JavaScript standard.
+In addition to [ES6](https://github.com/lukehoban/es6features) syntax features, it also supports:
+
+* [Exponentiation Operator](https://github.com/rwaldron/exponentiation-operator) (ES2016).
+* [Async/await](https://github.com/tc39/ecmascript-asyncawait) (ES2017).
+* [Object Rest/Spread Properties](https://github.com/sebmarkbage/ecmascript-rest-spread) (stage 3 proposal).
+* [Class Fields and Static Properties](https://github.com/tc39/proposal-class-public-fields) (stage 2 proposal).
+* [JSX](https://facebook.github.io/react/docs/introducing-jsx.html) and [Flow](https://flowtype.org/) syntax.
+
+Learn more about [different proposal stages](https://babeljs.io/docs/plugins/#presets-stage-x-experimental-presets-).
+
+While we recommend to use experimental proposals with some caution, Facebook heavily uses these features in the product code, so we intend to provide [codemods](https://medium.com/@cpojer/effective-javascript-codemods-5a6686bb46fb) if any of these proposals change in the future.
+
+Note that **the project only includes a few ES6 [polyfills](https://en.wikipedia.org/wiki/Polyfill)**:
+
+* [`Object.assign()`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) via [`object-assign`](https://github.com/sindresorhus/object-assign).
+* [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) via [`promise`](https://github.com/then/promise).
+* [`fetch()`](https://developer.mozilla.org/en/docs/Web/API/Fetch_API) via [`whatwg-fetch`](https://github.com/github/fetch).
+
+If you use any other ES6+ features that need **runtime support** (such as `Array.from()` or `Symbol`), make sure you are including the appropriate polyfills manually, or that the browsers you are targeting already support them.
+
+## Syntax Highlighting in the Editor
+
+To configure the syntax highlighting in your favorite text editor, head to the [relevant Babel documentation page](https://babeljs.io/docs/editors) and follow the instructions. Some of the most popular editors are covered.
+
+## Displaying Lint Output in the Editor
+
+>Note: this feature is available with `react-scripts@0.2.0` and higher.
+
+Some editors, including Sublime Text, Atom, and Visual Studio Code, provide plugins for ESLint.
+
+They are not required for linting. You should see the linter output right in your terminal as well as the browser console. However, if you prefer the lint results to appear right in your editor, there are some extra steps you can do.
+
+You would need to install an ESLint plugin for your editor first.
+
+>**A note for Atom `linter-eslint` users**
+
+>If you are using the Atom `linter-eslint` plugin, make sure that **Use global ESLint installation** option is checked:
+
+>
+
+
+>**For Visual Studio Code users**
+
+>VS Code ESLint plugin automatically detects Create React App's configuration file. So you do not need to create `eslintrc.json` at the root directory, except when you want to add your own rules. In that case, you should include CRA's config by adding this line:
+
+>```js
+{
+ // ...
+ "extends": "react-app"
+}
+```
+
+Then add this block to the `package.json` file of your project:
+
+```js
+{
+ // ...
+ "eslintConfig": {
+ "extends": "react-app"
+ }
+}
+```
+
+Finally, you will need to install some packages *globally*:
+
+```sh
+npm install -g eslint-config-react-app@0.3.0 eslint@3.8.1 babel-eslint@7.0.0 eslint-plugin-react@6.4.1 eslint-plugin-import@2.0.1 eslint-plugin-jsx-a11y@2.2.3 eslint-plugin-flowtype@2.21.0
+```
+
+We recognize that this is suboptimal, but it is currently required due to the way we hide the ESLint dependency. The ESLint team is already [working on a solution to this](https://github.com/eslint/eslint/issues/3458) so this may become unnecessary in a couple of months.
+
+## Debugging in the Editor
+
+**This feature is currently only supported by [Visual Studio Code](https://code.visualstudio.com) editor.**
+
+Visual Studio Code supports live-editing and debugging out of the box with Create React App. This enables you as a developer to write and debug your React code without leaving the editor, and most importantly it enables you to have a continuous development workflow, where context switching is minimal, as you don’t have to switch between tools.
+
+You would need to have the latest version of [VS Code](https://code.visualstudio.com) and VS Code [Chrome Debugger Extension](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) installed.
+
+Then add the block below to your `launch.json` file and put it inside the `.vscode` folder in your app’s root directory.
+
+```json
+{
+ "version": "0.2.0",
+ "configurations": [{
+ "name": "Chrome",
+ "type": "chrome",
+ "request": "launch",
+ "url": "http://localhost:3000",
+ "webRoot": "${workspaceRoot}/src",
+ "userDataDir": "${workspaceRoot}/.vscode/chrome",
+ "sourceMapPathOverrides": {
+ "webpack:///src/*": "${webRoot}/*"
+ }
+ }]
+}
+```
+
+Start your app by running `npm start`, and start debugging in VS Code by pressing `F5` or by clicking the green debug icon. You can now write code, set breakpoints, make changes to the code, and debug your newly modified code—all from your editor.
+
+## Changing the Page ``
+
+You can find the source HTML file in the `public` folder of the generated project. You may edit the `` tag in it to change the title from “React App” to anything else.
+
+Note that normally you wouldn’t edit files in the `public` folder very often. For example, [adding a stylesheet](#adding-a-stylesheet) is done without touching the HTML.
+
+If you need to dynamically update the page title based on the content, you can use the browser [`document.title`](https://developer.mozilla.org/en-US/docs/Web/API/Document/title) API. For more complex scenarios when you want to change the title from React components, you can use [React Helmet](https://github.com/nfl/react-helmet), a third party library.
+
+If you use a custom server for your app in production and want to modify the title before it gets sent to the browser, you can follow advice in [this section](#generating-dynamic-meta-tags-on-the-server). Alternatively, you can pre-build each page as a static HTML file which then loads the JavaScript bundle, which is covered [here](#pre-rendering-into-static-html-files).
+
+## Installing a Dependency
+
+The generated project includes React and ReactDOM as dependencies. It also includes a set of scripts used by Create React App as a development dependency. You may install other dependencies (for example, React Router) with `npm`:
+
+```
+npm install --save
+```
+
+## Importing a Component
+
+This project setup supports ES6 modules thanks to Babel.
+While you can still use `require()` and `module.exports`, we encourage you to use [`import` and `export`](http://exploringjs.com/es6/ch_modules.html) instead.
+
+For example:
+
+### `Button.js`
+
+```js
+import React, { Component } from 'react';
+
+class Button extends Component {
+ render() {
+ // ...
+ }
+}
+
+export default Button; // Don’t forget to use export default!
+```
+
+### `DangerButton.js`
+
+
+```js
+import React, { Component } from 'react';
+import Button from './Button'; // Import a component from another file
+
+class DangerButton extends Component {
+ render() {
+ return ;
+ }
+}
+
+export default DangerButton;
+```
+
+Be aware of the [difference between default and named exports](http://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281). It is a common source of mistakes.
+
+We suggest that you stick to using default imports and exports when a module only exports a single thing (for example, a component). That’s what you get when you use `export default Button` and `import Button from './Button'`.
+
+Named exports are useful for utility modules that export several functions. A module may have at most one default export and as many named exports as you like.
+
+Learn more about ES6 modules:
+
+* [When to use the curly braces?](http://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281)
+* [Exploring ES6: Modules](http://exploringjs.com/es6/ch_modules.html)
+* [Understanding ES6: Modules](https://leanpub.com/understandinges6/read#leanpub-auto-encapsulating-code-with-modules)
+
+## Adding a Stylesheet
+
+This project setup uses [Webpack](https://webpack.github.io/) for handling all assets. Webpack offers a custom way of “extending” the concept of `import` beyond JavaScript. To express that a JavaScript file depends on a CSS file, you need to **import the CSS from the JavaScript file**:
+
+### `Button.css`
+
+```css
+.Button {
+ padding: 20px;
+}
+```
+
+### `Button.js`
+
+```js
+import React, { Component } from 'react';
+import './Button.css'; // Tell Webpack that Button.js uses these styles
+
+class Button extends Component {
+ render() {
+ // You can use them as regular CSS styles
+ return
;
+ }
+}
+```
+
+**This is not required for React** but many people find this feature convenient. You can read about the benefits of this approach [here](https://medium.com/seek-ui-engineering/block-element-modifying-your-javascript-components-d7f99fcab52b). However you should be aware that this makes your code less portable to other build tools and environments than Webpack.
+
+In development, expressing dependencies this way allows your styles to be reloaded on the fly as you edit them. In production, all CSS files will be concatenated into a single minified `.css` file in the build output.
+
+If you are concerned about using Webpack-specific semantics, you can put all your CSS right into `src/index.css`. It would still be imported from `src/index.js`, but you could always remove that import if you later migrate to a different build tool.
+
+## Post-Processing CSS
+
+This project setup minifies your CSS and adds vendor prefixes to it automatically through [Autoprefixer](https://github.com/postcss/autoprefixer) so you don’t need to worry about it.
+
+For example, this:
+
+```css
+.App {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+```
+
+becomes this:
+
+```css
+.App {
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-orient: horizontal;
+ -webkit-box-direction: normal;
+ -ms-flex-direction: row;
+ flex-direction: row;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+```
+
+If you need to disable autoprefixing for some reason, [follow this section](https://github.com/postcss/autoprefixer#disabling).
+
+## Adding a CSS Preprocessor (Sass, Less etc.)
+
+Generally, we recommend that you don’t reuse the same CSS classes across different components. For example, instead of using a `.Button` CSS class in `` and `` components, we recommend creating a `` component with its own `.Button` styles, that both `` and `` can render (but [not inherit](https://facebook.github.io/react/docs/composition-vs-inheritance.html)).
+
+Following this rule often makes CSS preprocessors less useful, as features like mixins and nesting are replaced by component composition. You can, however, integrate a CSS preprocessor if you find it valuable. In this walkthrough, we will be using Sass, but you can also use Less, or another alternative.
+
+First, let’s install the command-line interface for Sass:
+
+```
+npm install node-sass --save-dev
+```
+
+Then in `package.json`, add the following lines to `scripts`:
+
+```diff
+ "scripts": {
++ "build-css": "node-sass src/ -o src/",
++ "watch-css": "npm run build-css && node-sass src/ -o src/ --watch",
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test --env=jsdom",
+```
+
+>Note: To use a different preprocessor, replace `build-css` and `watch-css` commands according to your preprocessor’s documentation.
+
+Now you can rename `src/App.css` to `src/App.scss` and run `npm run watch-css`. The watcher will find every Sass file in `src` subdirectories, and create a corresponding CSS file next to it, in our case overwriting `src/App.css`. Since `src/App.js` still imports `src/App.css`, the styles become a part of your application. You can now edit `src/App.scss`, and `src/App.css` will be regenerated.
+
+To share variables between Sass files, you can use Sass imports. For example, `src/App.scss` and other component style files could include `@import "./shared.scss";` with variable definitions.
+
+At this point you might want to remove all CSS files from the source control, and add `src/**/*.css` to your `.gitignore` file. It is generally a good practice to keep the build products outside of the source control.
+
+As a final step, you may find it convenient to run `watch-css` automatically with `npm start`, and run `build-css` as a part of `npm run build`. You can use the `&&` operator to execute two scripts sequentially. However, there is no cross-platform way to run two scripts in parallel, so we will install a package for this:
+
+```
+npm install --save-dev npm-run-all
+```
+
+Then we can change `start` and `build` scripts to include the CSS preprocessor commands:
+
+```diff
+ "scripts": {
+ "build-css": "node-sass src/ -o src/",
+ "watch-css": "npm run build-css && node-sass src/ -o src/ --watch --recursive",
+- "start": "react-scripts start",
+- "build": "react-scripts build",
++ "start-js": "react-scripts start",
++ "start": "npm-run-all -p watch-css start-js",
++ "build": "npm run build-css && react-scripts build",
+ "test": "react-scripts test --env=jsdom",
+ "eject": "react-scripts eject"
+ }
+```
+
+Now running `npm start` and `npm run build` also builds Sass files. Note that `node-sass` seems to have an [issue recognizing newly created files on some systems](https://github.com/sass/node-sass/issues/1891) so you might need to restart the watcher when you create a file until it’s resolved.
+
+## Adding Images and Fonts
+
+With Webpack, using static assets like images and fonts works similarly to CSS.
+
+You can **`import` an image right in a JavaScript module**. This tells Webpack to include that image in the bundle. Unlike CSS imports, importing an image or a font gives you a string value. This value is the final image path you can reference in your code.
+
+Here is an example:
+
+```js
+import React from 'react';
+import logo from './logo.png'; // Tell Webpack this JS file uses this image
+
+console.log(logo); // /logo.84287d09.png
+
+function Header() {
+ // Import result is the URL of your image
+ return ;
+}
+
+export default Header;
+```
+
+This ensures that when the project is built, Webpack will correctly move the images into the build folder, and provide us with correct paths.
+
+This works in CSS too:
+
+```css
+.Logo {
+ background-image: url(./logo.png);
+}
+```
+
+Webpack finds all relative module references in CSS (they start with `./`) and replaces them with the final paths from the compiled bundle. If you make a typo or accidentally delete an important file, you will see a compilation error, just like when you import a non-existent JavaScript module. The final filenames in the compiled bundle are generated by Webpack from content hashes. If the file content changes in the future, Webpack will give it a different name in production so you don’t need to worry about long-term caching of assets.
+
+Please be advised that this is also a custom feature of Webpack.
+
+**It is not required for React** but many people enjoy it (and React Native uses a similar mechanism for images).
+An alternative way of handling static assets is described in the next section.
+
+## Using the `public` Folder
+
+>Note: this feature is available with `react-scripts@0.5.0` and higher.
+
+### Changing the HTML
+
+The `public` folder contains the HTML file so you can tweak it, for example, to [set the page title](#changing-the-page-title).
+The `
+```
+
+Then, on the server, you can replace `__SERVER_DATA__` with a JSON of real data right before sending the response. The client code can then read `window.SERVER_DATA` to use it. **Make sure to [sanitize the JSON before sending it to the client](https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0) as it makes your app vulnerable to XSS attacks.**
+
+## Running Tests
+
+>Note: this feature is available with `react-scripts@0.3.0` and higher.
+>[Read the migration guide to learn how to enable it in older projects!](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md#migrating-from-023-to-030)
+
+Create React App uses [Jest](https://facebook.github.io/jest/) as its test runner. To prepare for this integration, we did a [major revamp](https://facebook.github.io/jest/blog/2016/09/01/jest-15.html) of Jest so if you heard bad things about it years ago, give it another try.
+
+Jest is a Node-based runner. This means that the tests always run in a Node environment and not in a real browser. This lets us enable fast iteration speed and prevent flakiness.
+
+While Jest provides browser globals such as `window` thanks to [jsdom](https://github.com/tmpvar/jsdom), they are only approximations of the real browser behavior. Jest is intended to be used for unit tests of your logic and your components rather than the DOM quirks.
+
+We recommend that you use a separate tool for browser end-to-end tests if you need them. They are beyond the scope of Create React App.
+
+### Filename Conventions
+
+Jest will look for test files with any of the following popular naming conventions:
+
+* Files with `.js` suffix in `__tests__` folders.
+* Files with `.test.js` suffix.
+* Files with `.spec.js` suffix.
+
+The `.test.js` / `.spec.js` files (or the `__tests__` folders) can be located at any depth under the `src` top level folder.
+
+We recommend to put the test files (or `__tests__` folders) next to the code they are testing so that relative imports appear shorter. For example, if `App.test.js` and `App.js` are in the same folder, the test just needs to `import App from './App'` instead of a long relative path. Colocation also helps find tests more quickly in larger projects.
+
+### Command Line Interface
+
+When you run `npm test`, Jest will launch in the watch mode. Every time you save a file, it will re-run the tests, just like `npm start` recompiles the code.
+
+The watcher includes an interactive command-line interface with the ability to run all tests, or focus on a search pattern. It is designed this way so that you can keep it open and enjoy fast re-runs. You can learn the commands from the “Watch Usage” note that the watcher prints after every run:
+
+
+
+### Version Control Integration
+
+By default, when you run `npm test`, Jest will only run the tests related to files changed since the last commit. This is an optimization designed to make your tests runs fast regardless of how many tests you have. However it assumes that you don’t often commit the code that doesn’t pass the tests.
+
+Jest will always explicitly mention that it only ran tests related to the files changed since the last commit. You can also press `a` in the watch mode to force Jest to run all tests.
+
+Jest will always run all tests on a [continuous integration](#continuous-integration) server or if the project is not inside a Git or Mercurial repository.
+
+### Writing Tests
+
+To create tests, add `it()` (or `test()`) blocks with the name of the test and its code. You may optionally wrap them in `describe()` blocks for logical grouping but this is neither required nor recommended.
+
+Jest provides a built-in `expect()` global function for making assertions. A basic test could look like this:
+
+```js
+import sum from './sum';
+
+it('sums numbers', () => {
+ expect(sum(1, 2)).toEqual(3);
+ expect(sum(2, 2)).toEqual(4);
+});
+```
+
+All `expect()` matchers supported by Jest are [extensively documented here](http://facebook.github.io/jest/docs/expect.html).
+You can also use [`jest.fn()` and `expect(fn).toBeCalled()`](http://facebook.github.io/jest/docs/expect.html#tohavebeencalled) to create “spies” or mock functions.
+
+### Testing Components
+
+There is a broad spectrum of component testing techniques. They range from a “smoke test” verifying that a component renders without throwing, to shallow rendering and testing some of the output, to full rendering and testing component lifecycle and state changes.
+
+Different projects choose different testing tradeoffs based on how often components change, and how much logic they contain. If you haven’t decided on a testing strategy yet, we recommend that you start with creating simple smoke tests for your components:
+
+```js
+import React from 'react';
+import ReactDOM from 'react-dom';
+import App from './App';
+
+it('renders without crashing', () => {
+ const div = document.createElement('div');
+ ReactDOM.render( , div);
+});
+```
+
+This test mounts a component and makes sure that it didn’t throw during rendering. Tests like this provide a lot value with very little effort so they are great as a starting point, and this is the test you will find in `src/App.test.js`.
+
+When you encounter bugs caused by changing components, you will gain a deeper insight into which parts of them are worth testing in your application. This might be a good time to introduce more specific tests asserting specific expected output or behavior.
+
+If you’d like to test components in isolation from the child components they render, we recommend using [`shallow()` rendering API](http://airbnb.io/enzyme/docs/api/shallow.html) from [Enzyme](http://airbnb.io/enzyme/). You can write a smoke test with it too:
+
+```sh
+npm install --save-dev enzyme react-addons-test-utils
+```
+
+```js
+import React from 'react';
+import { shallow } from 'enzyme';
+import App from './App';
+
+it('renders without crashing', () => {
+ shallow( );
+});
+```
+
+Unlike the previous smoke test using `ReactDOM.render()`, this test only renders `` and doesn’t go deeper. For example, even if `` itself renders a `` that throws, this test will pass. Shallow rendering is great for isolated unit tests, but you may still want to create some full rendering tests to ensure the components integrate correctly. Enzyme supports [full rendering with `mount()`](http://airbnb.io/enzyme/docs/api/mount.html), and you can also use it for testing state changes and component lifecycle.
+
+You can read the [Enzyme documentation](http://airbnb.io/enzyme/) for more testing techniques. Enzyme documentation uses Chai and Sinon for assertions but you don’t have to use them because Jest provides built-in `expect()` and `jest.fn()` for spies.
+
+Here is an example from Enzyme documentation that asserts specific output, rewritten to use Jest matchers:
+
+```js
+import React from 'react';
+import { shallow } from 'enzyme';
+import App from './App';
+
+it('renders welcome message', () => {
+ const wrapper = shallow( );
+ const welcome = Welcome to React ;
+ // expect(wrapper.contains(welcome)).to.equal(true);
+ expect(wrapper.contains(welcome)).toEqual(true);
+});
+```
+
+All Jest matchers are [extensively documented here](http://facebook.github.io/jest/docs/expect.html).
+Nevertheless you can use a third-party assertion library like [Chai](http://chaijs.com/) if you want to, as described below.
+
+Additionally, you might find [jest-enzyme](https://github.com/blainekasten/enzyme-matchers) helpful to simplify your tests with readable matchers. The above `contains` code can be written simpler with jest-enzyme.
+
+```js
+expect(wrapper).toContainReact(welcome)
+```
+
+To setup jest-enzyme with Create React App, follow the instructions for [initializing your test environment](#initializing-test-environment) to import `jest-enzyme`.
+
+```sh
+npm install --save-dev jest-enzyme
+```
+
+```js
+// src/setupTests.js
+import 'jest-enzyme';
+```
+
+
+### Using Third Party Assertion Libraries
+
+We recommend that you use `expect()` for assertions and `jest.fn()` for spies. If you are having issues with them please [file those against Jest](https://github.com/facebook/jest/issues/new), and we’ll fix them. We intend to keep making them better for React, supporting, for example, [pretty-printing React elements as JSX](https://github.com/facebook/jest/pull/1566).
+
+However, if you are used to other libraries, such as [Chai](http://chaijs.com/) and [Sinon](http://sinonjs.org/), or if you have existing code using them that you’d like to port over, you can import them normally like this:
+
+```js
+import sinon from 'sinon';
+import { expect } from 'chai';
+```
+
+and then use them in your tests like you normally do.
+
+### Initializing Test Environment
+
+>Note: this feature is available with `react-scripts@0.4.0` and higher.
+
+If your app uses a browser API that you need to mock in your tests or if you just need a global setup before running your tests, add a `src/setupTests.js` to your project. It will be automatically executed before running your tests.
+
+For example:
+
+#### `src/setupTests.js`
+```js
+const localStorageMock = {
+ getItem: jest.fn(),
+ setItem: jest.fn(),
+ clear: jest.fn()
+};
+global.localStorage = localStorageMock
+```
+
+### Focusing and Excluding Tests
+
+You can replace `it()` with `xit()` to temporarily exclude a test from being executed.
+Similarly, `fit()` lets you focus on a specific test without running any other tests.
+
+### Coverage Reporting
+
+Jest has an integrated coverage reporter that works well with ES6 and requires no configuration.
+Run `npm test -- --coverage` (note extra `--` in the middle) to include a coverage report like this:
+
+
+
+Note that tests run much slower with coverage so it is recommended to run it separately from your normal workflow.
+
+### Continuous Integration
+
+By default `npm test` runs the watcher with interactive CLI. However, you can force it to run tests once and finish the process by setting an environment variable called `CI`.
+
+When creating a build of your application with `npm run build` linter warnings are not checked by default. Like `npm test`, you can force the build to perform a linter warning check by setting the environment variable `CI`. If any warnings are encountered then the build fails.
+
+Popular CI servers already set the environment variable `CI` by default but you can do this yourself too:
+
+### On CI servers
+#### Travis CI
+
+1. Following the [Travis Getting started](https://docs.travis-ci.com/user/getting-started/) guide for syncing your GitHub repository with Travis. You may need to initialize some settings manually in your [profile](https://travis-ci.org/profile) page.
+1. Add a `.travis.yml` file to your git repository.
+```
+language: node_js
+node_js:
+ - 4
+ - 6
+cache:
+ directories:
+ - node_modules
+script:
+ - npm test
+ - npm run build
+```
+1. Trigger your first build with a git push.
+1. [Customize your Travis CI Build](https://docs.travis-ci.com/user/customizing-the-build/) if needed.
+
+### On your own environment
+##### Windows (cmd.exe)
+
+```cmd
+set CI=true&&npm test
+```
+
+```cmd
+set CI=true&&npm run build
+```
+
+(Note: the lack of whitespace is intentional.)
+
+##### Linux, macOS (Bash)
+
+```bash
+CI=true npm test
+```
+
+```bash
+CI=true npm run build
+```
+
+The test command will force Jest to run tests once instead of launching the watcher.
+
+> If you find yourself doing this often in development, please [file an issue](https://github.com/facebookincubator/create-react-app/issues/new) to tell us about your use case because we want to make watcher the best experience and are open to changing how it works to accommodate more workflows.
+
+The build command will check for linter warnings and fail if any are found.
+
+### Disabling jsdom
+
+By default, the `package.json` of the generated project looks like this:
+
+```js
+ // ...
+ "scripts": {
+ // ...
+ "test": "react-scripts test --env=jsdom"
+ }
+```
+
+If you know that none of your tests depend on [jsdom](https://github.com/tmpvar/jsdom), you can safely remove `--env=jsdom`, and your tests will run faster.
+To help you make up your mind, here is a list of APIs that **need jsdom**:
+
+* Any browser globals like `window` and `document`
+* [`ReactDOM.render()`](https://facebook.github.io/react/docs/top-level-api.html#reactdom.render)
+* [`TestUtils.renderIntoDocument()`](https://facebook.github.io/react/docs/test-utils.html#renderintodocument) ([a shortcut](https://github.com/facebook/react/blob/34761cf9a252964abfaab6faf74d473ad95d1f21/src/test/ReactTestUtils.js#L83-L91) for the above)
+* [`mount()`](http://airbnb.io/enzyme/docs/api/mount.html) in [Enzyme](http://airbnb.io/enzyme/index.html)
+
+In contrast, **jsdom is not needed** for the following APIs:
+
+* [`TestUtils.createRenderer()`](https://facebook.github.io/react/docs/test-utils.html#shallow-rendering) (shallow rendering)
+* [`shallow()`](http://airbnb.io/enzyme/docs/api/shallow.html) in [Enzyme](http://airbnb.io/enzyme/index.html)
+
+Finally, jsdom is also not needed for [snapshot testing](http://facebook.github.io/jest/blog/2016/07/27/jest-14.html).
+
+### Snapshot Testing
+
+Snapshot testing is a feature of Jest that automatically generates text snapshots of your components and saves them on the disk so if the UI output changes, you get notified without manually writing any assertions on the component output. [Read more about snapshot testing.](http://facebook.github.io/jest/blog/2016/07/27/jest-14.html)
+
+### Editor Integration
+
+If you use [Visual Studio Code](https://code.visualstudio.com), there is a [Jest extension](https://github.com/orta/vscode-jest) which works with Create React App out of the box. This provides a lot of IDE-like features while using a text editor: showing the status of a test run with potential fail messages inline, starting and stopping the watcher automatically, and offering one-click snapshot updates.
+
+
+
+## Developing Components in Isolation
+
+Usually, in an app, you have a lot of UI components, and each of them has many different states.
+For an example, a simple button component could have following states:
+
+* With a text label.
+* With an emoji.
+* In the disabled mode.
+
+Usually, it’s hard to see these states without running a sample app or some examples.
+
+Create React App doesn’t include any tools for this by default, but you can easily add [React Storybook](https://github.com/kadirahq/react-storybook) to your project. **It is a third-party tool that lets you develop components and see all their states in isolation from your app**.
+
+
+
+You can also deploy your Storybook as a static app. This way, everyone in your team can view and review different states of UI components without starting a backend server or creating an account in your app.
+
+**Here’s how to setup your app with Storybook:**
+
+First, install the following npm package globally:
+
+```sh
+npm install -g getstorybook
+```
+
+Then, run the following command inside your app’s directory:
+
+```sh
+getstorybook
+```
+
+After that, follow the instructions on the screen.
+
+Learn more about React Storybook:
+
+* Screencast: [Getting Started with React Storybook](https://egghead.io/lessons/react-getting-started-with-react-storybook)
+* [GitHub Repo](https://github.com/kadirahq/react-storybook)
+* [Documentation](https://getstorybook.io/docs)
+* [Snapshot Testing](https://github.com/kadirahq/storyshots) with React Storybook
+
+## Making a Progressive Web App
+
+You can turn your React app into a [Progressive Web App](https://developers.google.com/web/progressive-web-apps/) by following the steps in [this repository](https://github.com/jeffposnick/create-react-pwa).
+
+## Deployment
+
+`npm run build` creates a `build` directory with a production build of your app. Set up your favourite HTTP server so that a visitor to your site is served `index.html`, and requests to static paths like `/static/js/main..js` are served with the contents of the `/static/js/main..js` file. For example, Python contains a built-in HTTP server that can serve static files:
+
+```sh
+cd build
+python -m SimpleHTTPServer 9000
+```
+
+If you’re using [Node](https://nodejs.org/) and [Express](http://expressjs.com/) as a server, it might look like this:
+
+```javascript
+const express = require('express');
+const path = require('path');
+const app = express();
+
+app.use(express.static('./build'));
+
+app.get('/', function (req, res) {
+ res.sendFile(path.join(__dirname, './build', 'index.html'));
+});
+
+app.listen(9000);
+```
+
+Create React App is not opinionated about your choice of web server. Any static file server will do. The `build` folder with static assets is the only output produced by Create React App.
+
+However this is not quite enough if you use client-side routing. Read the next section if you want to support URLs like `/todos/42` in your single-page app.
+
+### Serving Apps with Client-Side Routing
+
+If you use routers that use the HTML5 [`pushState` history API](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries) under the hood (for example, [React Router](https://github.com/ReactTraining/react-router) with `browserHistory`), many static file servers will fail. For example, if you used React Router with a route for `/todos/42`, the development server will respond to `localhost:3000/todos/42` properly, but an Express serving a production build as above will not.
+
+This is because when there is a fresh page load for a `/todos/42`, the server looks for the file `build/todos/42` and does not find it. The server needs to be configured to respond to a request to `/todos/42` by serving `index.html`. For example, we can amend our Express example above to serve `index.html` for any unknown paths:
+
+```diff
+ app.use(express.static('./build'));
+
+-app.get('/', function (req, res) {
++app.get('/*', function (req, res) {
+ res.sendFile(path.join(__dirname, './build', 'index.html'));
+ });
+```
+
+Now requests to `/todos/42` will be handled correctly both in development and in production.
+
+### Building for Relative Paths
+
+By default, Create React App produces a build assuming your app is hosted at the server root.
+To override this, specify the `homepage` in your `package.json`, for example:
+
+```js
+ "homepage": "http://mywebsite.com/relativepath",
+```
+
+This will let Create React App correctly infer the root path to use in the generated HTML file.
+
+#### Serving the Same Build from Different Paths
+
+>Note: this feature is available with `react-scripts@0.9.0` and higher.
+
+If you are not using the HTML5 `pushState` history API or not using client-side routing at all, it is unnecessary to specify the URL from which your app will be served. Instead, you can put this in your `package.json`:
+
+```js
+ "homepage": ".",
+```
+
+This will make sure that all the asset paths are relative to `index.html`. You will then be able to move your app from `http://mywebsite.com` to `http://mywebsite.com/relativepath` or even `http://mywebsite.com/relative/path` without having to rebuild it.
+
+### Azure
+
+See [this](https://medium.com/@to_pe/deploying-create-react-app-on-microsoft-azure-c0f6686a4321) blog post on how to deploy your React app to [Microsoft Azure](https://azure.microsoft.com/).
+
+### Firebase
+
+Install the Firebase CLI if you haven’t already by running `npm install -g firebase-tools`. Sign up for a [Firebase account](https://console.firebase.google.com/) and create a new project. Run `firebase login` and login with your previous created Firebase account.
+
+Then run the `firebase init` command from your project’s root. You need to choose the **Hosting: Configure and deploy Firebase Hosting sites** and choose the Firebase project you created in the previous step. You will need to agree with `database.rules.json` being created, choose `build` as the public directory, and also agree to **Configure as a single-page app** by replying with `y`.
+
+```sh
+ === Project Setup
+
+ First, let's associate this project directory with a Firebase project.
+ You can create multiple project aliases by running firebase use --add,
+ but for now we'll just set up a default project.
+
+ ? What Firebase project do you want to associate as default? Example app (example-app-fd690)
+
+ === Database Setup
+
+ Firebase Realtime Database Rules allow you to define how your data should be
+ structured and when your data can be read from and written to.
+
+ ? What file should be used for Database Rules? database.rules.json
+ ✔ Database Rules for example-app-fd690 have been downloaded to database.rules.json.
+ Future modifications to database.rules.json will update Database Rules when you run
+ firebase deploy.
+
+ === Hosting Setup
+
+ Your public directory is the folder (relative to your project directory) that
+ will contain Hosting assets to uploaded with firebase deploy. If you
+ have a build process for your assets, use your build's output directory.
+
+ ? What do you want to use as your public directory? build
+ ? Configure as a single-page app (rewrite all urls to /index.html)? Yes
+ ✔ Wrote build/index.html
+
+ i Writing configuration info to firebase.json...
+ i Writing project information to .firebaserc...
+
+ ✔ Firebase initialization complete!
+```
+
+Now, after you create a production build with `npm run build`, you can deploy it by running `firebase deploy`.
+
+```sh
+ === Deploying to 'example-app-fd690'...
+
+ i deploying database, hosting
+ ✔ database: rules ready to deploy.
+ i hosting: preparing build directory for upload...
+ Uploading: [============================== ] 75%✔ hosting: build folder uploaded successfully
+ ✔ hosting: 8 files uploaded successfully
+ i starting release process (may take several minutes)...
+
+ ✔ Deploy complete!
+
+ Project Console: https://console.firebase.google.com/project/example-app-fd690/overview
+ Hosting URL: https://example-app-fd690.firebaseapp.com
+```
+
+For more information see [Add Firebase to your JavaScript Project](https://firebase.google.com/docs/web/setup).
+
+### GitHub Pages
+
+>Note: this feature is available with `react-scripts@0.2.0` and higher.
+
+#### Step 1: Add `homepage` to `package.json`
+
+**The step below is important!**
+**If you skip it, your app will not deploy correctly.**
+
+Open your `package.json` and add a `homepage` field:
+
+```js
+ "homepage": "https://myusername.github.io/my-app",
+```
+
+Create React App uses the `homepage` field to determine the root URL in the built HTML file.
+
+#### Step 2: Install `gh-pages` and add `deploy` to `scripts` in `package.json`
+
+Now, whenever you run `npm run build`, you will see a cheat sheet with instructions on how to deploy to GitHub Pages.
+
+To publish it at [https://myusername.github.io/my-app](https://myusername.github.io/my-app), run:
+
+```sh
+npm install --save-dev gh-pages
+```
+
+Add the following scripts in your `package.json`:
+
+```js
+ // ...
+ "scripts": {
+ // ...
+ "predeploy": "npm run build",
+ "deploy": "gh-pages -d build"
+ }
+```
+
+The `predeploy` script will run automatically before `deploy` is run.
+
+#### Step 3: Deploy the site by running `npm run deploy`
+
+Then run:
+
+```sh
+npm run deploy
+```
+
+#### Step 4: Ensure your project’s settings use `gh-pages`
+
+Finally, make sure **GitHub Pages** option in your GitHub project settings is set to use the `gh-pages` branch:
+
+
+
+#### Step 5: Optionally, configure the domain
+
+You can configure a custom domain with GitHub Pages by adding a `CNAME` file to the `public/` folder.
+
+#### Notes on client-side routing
+
+GitHub Pages doesn’t support routers that use the HTML5 `pushState` history API under the hood (for example, React Router using `browserHistory`). This is because when there is a fresh page load for a url like `http://user.github.io/todomvc/todos/42`, where `/todos/42` is a frontend route, the GitHub Pages server returns 404 because it knows nothing of `/todos/42`. If you want to add a router to a project hosted on GitHub Pages, here are a couple of solutions:
+
+* You could switch from using HTML5 history API to routing with hashes. If you use React Router, you can switch to `hashHistory` for this effect, but the URL will be longer and more verbose (for example, `http://user.github.io/todomvc/#/todos/42?_k=yknaj`). [Read more](https://github.com/reactjs/react-router/blob/master/docs/guides/Histories.md#histories) about different history implementations in React Router.
+* Alternatively, you can use a trick to teach GitHub Pages to handle 404 by redirecting to your `index.html` page with a special redirect parameter. You would need to add a `404.html` file with the redirection code to the `build` folder before deploying your project, and you’ll need to add code handling the redirect parameter to `index.html`. You can find a detailed explanation of this technique [in this guide](https://github.com/rafrex/spa-github-pages).
+
+### Heroku
+
+Use the [Heroku Buildpack for Create React App](https://github.com/mars/create-react-app-buildpack).
+You can find instructions in [Deploying React with Zero Configuration](https://blog.heroku.com/deploying-react-with-zero-configuration).
+
+#### Resolving Heroku Deployment Errors
+
+Sometimes `npm run build` works locally but fails during deploy via Heroku. Following are the most common cases.
+
+##### "Module not found: Error: Cannot resolve 'file' or 'directory'"
+
+If you get something like this:
+
+```
+remote: Failed to create a production build. Reason:
+remote: Module not found: Error: Cannot resolve 'file' or 'directory'
+MyDirectory in /tmp/build_1234/src
+```
+
+It means you need to ensure that the lettercase of the file or directory you `import` matches the one you see on your filesystem or on GitHub.
+
+This is important because Linux (the operating system used by Heroku) is case sensitive. So `MyDirectory` and `mydirectory` are two distinct directories and thus, even though the project builds locally, the difference in case breaks the `import` statements on Heroku remotes.
+
+##### "Could not find a required file."
+
+If you exclude or ignore necessary files from the package you will see a error similar this one:
+
+```
+remote: Could not find a required file.
+remote: Name: `index.html`
+remote: Searched in: /tmp/build_a2875fc163b209225122d68916f1d4df/public
+remote:
+remote: npm ERR! Linux 3.13.0-105-generic
+remote: npm ERR! argv "/tmp/build_a2875fc163b209225122d68916f1d4df/.heroku/node/bin/node" "/tmp/build_a2875fc163b209225122d68916f1d4df/.heroku/node/bin/npm" "run" "build"
+```
+
+In this case, ensure that the file is there with the proper lettercase and that’s not ignored on your local `.gitignore` or `~/.gitignore_global`.
+
+### Modulus
+
+See the [Modulus blog post](http://blog.modulus.io/deploying-react-apps-on-modulus) on how to deploy your react app to Modulus.
+
+## Netlify
+
+**To do a manual deploy to Netlify’s CDN:**
+
+```sh
+npm install netlify-cli
+netlify deploy
+```
+
+Choose `build` as the path to deploy.
+
+**To setup continuous delivery:**
+
+With this setup Netlify will build and deploy when you push to git or open a pull request:
+
+1. [Start a new netlify project](https://app.netlify.com/signup)
+2. Pick your Git hosting service and select your repository
+3. Click `Build your site`
+
+**Support for client-side routing:**
+
+To support `pushState`, make sure to create a `public/_redirects` file with the following rewrite rules:
+
+```
+/* /index.html 200
+```
+
+When you build the project, Create React App will place the `public` folder contents into the build output.
+
+### Now
+
+See [this example](https://github.com/xkawi/create-react-app-now) for a zero-configuration single-command deployment with [now](https://zeit.co/now).
+
+### S3 and CloudFront
+
+See this [blog post](https://medium.com/@omgwtfmarc/deploying-create-react-app-to-s3-or-cloudfront-48dae4ce0af) on how to deploy your React app to Amazon Web Services [S3](https://aws.amazon.com/s3) and [CloudFront](https://aws.amazon.com/cloudfront/).
+
+### Surge
+
+Install the Surge CLI if you haven’t already by running `npm install -g surge`. Run the `surge` command and log in you or create a new account. You just need to specify the *build* folder and your custom domain, and you are done.
+
+```sh
+ email: email@domain.com
+ password: ********
+ project path: /path/to/project/build
+ size: 7 files, 1.8 MB
+ domain: create-react-app.surge.sh
+ upload: [====================] 100%, eta: 0.0s
+ propagate on CDN: [====================] 100%
+ plan: Free
+ users: email@domain.com
+ IP Address: X.X.X.X
+
+ Success! Project is published and running at create-react-app.surge.sh
+```
+
+Note that in order to support routers that use HTML5 `pushState` API, you may want to rename the `index.html` in your build folder to `200.html` before deploying to Surge. This [ensures that every URL falls back to that file](https://surge.sh/help/adding-a-200-page-for-client-side-routing).
+
+## Advanced Configuration
+
+You can adjust various development and production settings by setting environment variables in your shell or with [.env](#adding-development-environment-variables-in-env).
+
+Variable | Development | Production | Usage
+:--- | :---: | :---: | :---
+BROWSER | :white_check_mark: | :x: | By default, Create React App will open the default system browser, favoring Chrome on macOS. Specify a [browser](https://github.com/sindresorhus/opn#app) to override this behavior, or set it to `none` to disable it completely.
+HOST | :white_check_mark: | :x: | By default, the development web server binds to `localhost`. You may use this variable to specify a different host.
+PORT | :white_check_mark: | :x: | By default, the development web server will attempt to listen on port 3000 or prompt you to attempt the next available port. You may use this variable to specify a different port.
+HTTPS | :white_check_mark: | :x: | When set to `true`, Create React App will run the development server in `https` mode.
+PUBLIC_URL | :x: | :white_check_mark: | Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in [`package.json` (`homepage`)](#building-for-relative-paths). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application.
+CI | :large_orange_diamond: | :white_check_mark: | When set to `true`, Create React App treats warnings as failures in the build. It also makes the test runner non-watching. Most CIs set this flag by default.
+
+## Troubleshooting
+
+### `npm start` doesn’t detect changes
+
+When you save a file while `npm start` is running, the browser should refresh with the updated code.
+If this doesn’t happen, try one of the following workarounds:
+
+* If your project is in a Dropbox folder, try moving it out.
+* If the watcher doesn’t see a file called `index.js` and you’re referencing it by the folder name, you [need to restart the watcher](https://github.com/facebookincubator/create-react-app/issues/1164) due to a Webpack bug.
+* Some editors like Vim and IntelliJ have a “safe write” feature that currently breaks the watcher. You will need to disable it. Follow the instructions in [“Working with editors supporting safe write”](https://webpack.github.io/docs/webpack-dev-server.html#working-with-editors-ides-supporting-safe-write).
+* If your project path contains parentheses, try moving the project to a path without them. This is caused by a [Webpack watcher bug](https://github.com/webpack/watchpack/issues/42).
+* On Linux and macOS, you might need to [tweak system settings](https://webpack.github.io/docs/troubleshooting.html#not-enough-watchers) to allow more watchers.
+* If the project runs inside a virtual machine such as (a Vagrant provisioned) VirtualBox, run `npm install --save-dev cross-env` in its root folder and then replace `"react-scripts start"` in the `scripts` section of its `package.json` with `"cross-env CHOKIDAR_USEPOLLING=true react-scripts start"`. This ensures that the next time you run `npm start`, the watcher uses the polling mode, as necessary inside a VM.
+
+If none of these solutions help please leave a comment [in this thread](https://github.com/facebookincubator/create-react-app/issues/659).
+
+### `npm test` hangs on macOS Sierra
+
+If you run `npm test` and the console gets stuck after printing `react-scripts test --env=jsdom` to the console there might be a problem with your [Watchman](https://facebook.github.io/watchman/) installation as described in [facebookincubator/create-react-app#713](https://github.com/facebookincubator/create-react-app/issues/713).
+
+We recommend deleting `node_modules` in your project and running `npm install` (or `yarn` if you use it) first. If it doesn't help, you can try one of the numerous workarounds mentioned in these issues:
+
+* [facebook/jest#1767](https://github.com/facebook/jest/issues/1767)
+* [facebook/watchman#358](https://github.com/facebook/watchman/issues/358)
+* [ember-cli/ember-cli#6259](https://github.com/ember-cli/ember-cli/issues/6259)
+
+It is reported that installing Watchman 4.7.0 or newer fixes the issue. If you use [Homebrew](http://brew.sh/), you can run these commands to update it:
+
+```
+watchman shutdown-server
+brew update
+brew reinstall watchman
+```
+
+You can find [other installation methods](https://facebook.github.io/watchman/docs/install.html#build-install) on the Watchman documentation page.
+
+If this still doesn’t help, try running `launchctl unload -F ~/Library/LaunchAgents/com.github.facebook.watchman.plist`.
+
+There are also reports that *uninstalling* Watchman fixes the issue. So if nothing else helps, remove it from your system and try again.
+
+### `npm run build` silently fails
+
+It is reported that `npm run build` can fail on machines with no swap space, which is common in cloud environments. If [the symptoms are matching](https://github.com/facebookincubator/create-react-app/issues/1133#issuecomment-264612171), consider adding some swap space to the machine you’re building on, or build the project locally.
+
+### `npm run build` fails on Heroku
+
+This may be a problem with case sensitive filenames.
+Please refer to [this section](#resolving-heroku-deployment-errors).
+
+## Something Missing?
+
+If you have ideas for more “How To” recipes that should be on this page, [let us know](https://github.com/facebookincubator/create-react-app/issues) or [contribute some!](https://github.com/facebookincubator/create-react-app/edit/master/packages/react-scripts/template/README.md)
diff --git a/app/adapters/application.js b/app/adapters/application.js
deleted file mode 100644
index c87b180..0000000
--- a/app/adapters/application.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * File: application.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import RESTAdapter from 'ember-data/adapters/rest';
-import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
-import ENV from '../config/environment';
-
-export default RESTAdapter.extend(DataAdapterMixin, {
- host: 'http://' + ENV.APP.API_HOST,
- namespace: 'api/v1',
- authorizer: 'authorizer:custom',
- headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
-
- urlForQueryRecord(query /*, modelName */) {
- // Fix for /users/me query
- let baseUrl = this.buildURL();
- return baseUrl + '/users/' + query;
- }
-});
diff --git a/app/app.js b/app/app.js
deleted file mode 100644
index 6921924..0000000
--- a/app/app.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * File: app.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import Resolver from './resolver';
-import loadInitializers from 'ember-load-initializers';
-import config from './config/environment';
-
-let App;
-
-Ember.MODEL_FACTORY_INJECTIONS = true;
-
-App = Ember.Application.extend({
- modulePrefix: config.modulePrefix,
- podModulePrefix: config.podModulePrefix,
- Resolver
-});
-
-loadInitializers(App, config.modulePrefix);
-
-export default App;
diff --git a/app/authenticators/custom.js b/app/authenticators/custom.js
deleted file mode 100644
index 017b976..0000000
--- a/app/authenticators/custom.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * File: custom.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import Base from 'ember-simple-auth/authenticators/base';
-import ENV from '../config/environment';
-
-export default Base.extend({
- tokenEndpoint: 'http://' + ENV.APP.API_HOST + '/api/v1/authenticate',
-
- restore(data) {
- return new Ember.RSVP.Promise(function(resolve, reject) {
- if (!Ember.isEmpty(data.token)) {
- resolve(data);
- } else {
- reject();
- }
- });
- },
-
- authenticate(username, password) {
- return new Ember.RSVP.Promise((resolve, reject) => {
- Ember.$.ajax({
- url: this.tokenEndpoint,
- type: 'POST',
- data: JSON.stringify({
- username: username,
- password: password
- }),
- contentType: 'application/json',
- dataType: 'json'
- }).then(function(response) {
- Ember.run(function() {
- resolve({
- token: response.token
- });
- });
- }, function(xhr) {
- var response = JSON.parse(xhr.responseText);
- Ember.run(function() {
- reject(response.message);
- });
- });
- });
- },
-
- invalidate() {
- console.log('invalidate...');
- return Ember.RSVP.resolve();
- }
-});
diff --git a/app/authorizers/custom.js b/app/authorizers/custom.js
deleted file mode 100644
index 2711f0d..0000000
--- a/app/authorizers/custom.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * File: custom.js
- * Author: Markus Grigull
- * Date: 04.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import Base from 'ember-simple-auth/authorizers/base';
-
-export default Base.extend({
- session: Ember.inject.service('session'),
-
- authorize(data, block) {
- if (this.get('session.isAuthenticated') && !Ember.isEmpty(data.token)) {
- block('x-access-token', data.token);
- }
- }
-});
diff --git a/app/components/.gitkeep b/app/components/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/app/components/draggable-dropzone.js b/app/components/draggable-dropzone.js
deleted file mode 100644
index 18cdbff..0000000
--- a/app/components/draggable-dropzone.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * File: draggable-dropzone.js
- * Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-var { set } = Ember;
-
-export default Ember.Component.extend({
- tagName: 'div',
- classNames: [ 'draggableDropzone' ],
- classNameBindings: [ 'dragClass' ],
- dragClass: 'deactivated',
-
- dragLeave(event) {
- event.preventDefault();
- set(this, 'dragClass', 'deactivated');
- },
-
- dragOver(event) {
- event.preventDefault();
- set(this, 'dragClass', 'activated');
- },
-
- drop(event) {
- var data = event.dataTransfer.getData('text/data');
- var position = {
- x: event.originalEvent.pageX - Ember.$(event.target).offset().left - parseFloat(event.dataTransfer.getData('offset/x')),
- y: event.originalEvent.pageY - Ember.$(event.target).offset().top - parseFloat(event.dataTransfer.getData('offset/y'))
- };
-
- this.sendAction('dropped', data, position);
-
- set(this, 'dragClass', 'deactivated');
- }
-});
diff --git a/app/components/draggable-item.js b/app/components/draggable-item.js
deleted file mode 100644
index c390d26..0000000
--- a/app/components/draggable-item.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * File: draggable-item.js
- * Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-var { get } = Ember;
-
-export default Ember.Component.extend({
- classNames: [ 'draggableItem' ],
- attributeBindings: [ 'draggable' ],
- draggable: 'true',
-
- dragStart(event) {
- event.dataTransfer.setData('offset/x', event.originalEvent.pageX - Ember.$(event.target).offset().left);
- event.dataTransfer.setData('offset/y', event.originalEvent.pageY - Ember.$(event.target).offset().top);
-
- return event.dataTransfer.setData('text/data', get(this, 'content'));
- }
-});
diff --git a/app/components/flow-plot.js b/app/components/flow-plot.js
deleted file mode 100644
index 01700ab..0000000
--- a/app/components/flow-plot.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Component.extend({
- tagName: 'div',
- classNames: [ 'flow-plot' ],
- attributeBindings: [ 'style' ],
-
- plot: null,
- data: [],
- options: {},
- height: '85%',
-
- setupPlot: Ember.on('didInsertElement', function() {
- var plot = Ember.$.plot('#' + this.get('element').id, this.get('data'), this.get('options'));
- this.set('plot', plot);
- }),
-
- updateData: Ember.observer('data.@each', function() {
- // update plot
- var plot = Ember.$.plot('#' + this.get('element').id, this.get('data'), this.get('options'));
- this.set('plot', plot);
- }),
-
- style: Ember.computed('height', function() {
- return Ember.String.htmlSafe("height: " + this.get('height') + ";");
- })
-});
diff --git a/app/components/widget-abstract.js b/app/components/widget-abstract.js
deleted file mode 100644
index 61af405..0000000
--- a/app/components/widget-abstract.js
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * File: widget-abstract.js
- * Author: Markus Grigull
- * Date: 15.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import Resizable from '../mixins/resizable';
-import Draggable from '../mixins/draggable';
-
-export default Ember.Component.extend(Resizable, Draggable, {
- tagName: 'div',
- classNames: [ 'widgetAbstract' ],
- classNameBindings: [ 'widgetEditing' ],
- attributeBindings: [ 'style' ],
-
- widget: null,
- widgetEditing: true,
- editing: false,
- grid: false,
- data: null,
-
- disabled_resize: false,
- autoHide_resize: true,
- grid_resize: [ 10, 10 ],
-
- disabled_drag: false,
- containment_drag: 'parent',
- grid_drag: [ 10, 10 ],
- scroll_drag: true,
-
- style: Ember.computed('widget', function() {
- return Ember.String.htmlSafe('width: ' + this.get('widget.width') + 'px; height: ' + this.get('widget.height') + 'px; left: ' + this.get('widget.x') + 'px; top: ' + this.get('widget.y') + 'px;');
- }),
-
- name: Ember.computed('widget', function() {
- return this.get('widget.name');
- }),
-
- stop_resize(event, ui) {
- var width = ui.size.width;
- var height = ui.size.height;
-
- this.set('widget.width', width);
- this.set('widget.height', height);
- },
-
- resize_resize(/* event, ui */) {
-
- },
-
- stop_drag(event, ui) {
- this.set('widget.x', ui.position.left);
- this.set('widget.y', ui.position.top);
- },
-
- drag_drag(/* event, ui */) {
-
- },
-
- _updateUI: Ember.on('init', Ember.observer('editing', 'grid', 'isShowingModal', function() {
- if (this.get('editing') === true) {
- this.set('disabled_resize', false);
- //this.set('autoHide_resize', false);
- this.set('disabled_drag', false);
-
- this.set('widgetEditing', true);
- } else {
- this.set('disabled_resize', true);
- //this.set('autoHide_resize', true);
- this.set('disabled_drag', true);
-
- this.set('widgetEditing', false);
- }
-
- if (this.get('grid') === true) {
- this.set('grid_resize', [ 10, 10 ]);
- this.set('grid_drag', [ 10, 10 ]);
- } else {
- this.set('grid_resize', false);
- this.set('grid_drag', false);
- }
- })),
-
- /*doubleClick() {
- if (this.get('editing')) {
- this.sendAction('showPlotDialog', this.get('plot'));
- }
- }*/
-});
diff --git a/app/components/widget-container.js b/app/components/widget-container.js
deleted file mode 100644
index c1dcdc1..0000000
--- a/app/components/widget-container.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * File: widget-container.js
- * Author: Markus Grigull
- * Date: 05.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Component.extend({
- tagName: 'div',
- classNames: [ 'widgets' ],
- attributeBindings: [ 'style' ],
-
- widgets: null,
- editing: false,
- grid: false,
- data: null,
-
- style: Ember.computed('widgets.@each.height', 'widgets.@each.y', function() {
- var height = this._calculateHeight();
- if (this.get('editing') === true && height < 400) {
- height = 400;
- }
-
- return Ember.String.htmlSafe('height: ' + height + 'px;');
- }),
-
- _calculateHeight() {
- var maxHeight = 0;
- var widgets = this.get('widgets');
-
- widgets.forEach(function(widget) {
- var widgetHeight = widget.get('y') + widget.get('height');
- if (widgetHeight > maxHeight) {
- maxHeight = widgetHeight;
- }
- });
-
- // add padding to height
- maxHeight += 40;
-
- return maxHeight;
- },
-
- actions: {
- showWidgetDialog(widget) {
- this.sendAction('showWidgetDialog', widget);
- }
- }
-});
diff --git a/app/components/widget-image.js b/app/components/widget-image.js
deleted file mode 100644
index b4f15f0..0000000
--- a/app/components/widget-image.js
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * File: widget-image.js
- * Author: Markus Grigull
- * Date: 05.12.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import WidgetAbstract from './widget-abstract';
-import Ember from 'ember';
-import ENV from '../config/environment';
-import EmberUploader from 'ember-uploader';
-
-const {
- inject: { service }
-} = Ember;
-
-export default WidgetAbstract.extend({
- classNames: [ 'widgetImage' ],
-
- session: service('session'),
- sessionUser: Ember.inject.service('session-user'),
- store: service(),
-
- url: 'http://' + ENV.APP.API_HOST,
- namespace: 'api/v1',
-
- doubleClick() {
- if (this.get('editing') === true) {
- // prepare modal
- this.set('name', this.get('widget.name'));
-
- // show modal
- this.set('isShowingModal', true);
- }
- },
-
- actions: {
- submitModal() {
- // verify properties
- let properties = this.getProperties('name');
- properties.widgetData = { path: this.get('image.path') };
-
- this.get('widget').setProperties(properties);
-
- let self = this;
-
- this.get('widget').save().then(function() {
- self.set('isShowingModal', false);
- });
- },
-
- cancelModal() {
- this.set('isShowingModal', false);
- },
-
- selectImage(image) {
- // get image by path
- var self = this;
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('owner').then((user) => {
- user.get('files').then((files) => {
- files.forEach(function(file) {
- if (file.get('name') === image) {
- // set image
- self.set('image', file);
- }
- });
- });
- });
- });
- });
- },
-
- upload() {
- // check if any files to upload
- let files = this.get('uploadFiles');
-
- if (!Ember.isEmpty(files)) {
- var uploadURL = this.get('url') + '/' + this.get('namespace') + '/upload';
-
- const uploader = EmberUploader.Uploader.create({
- multiple: true,
- url: uploadURL,
- ajaxSettings: {
- headers: {
- 'x-access-token': this.get('session.data.authenticated.token')
- }
- }
- });
-
- var self = this;
-
- uploader.upload(files).then(function() {
- // reload user
- var user = self.get('sessionUser.user');
- self.get('store').findRecord('user', user.get('id'));
- });
- }
- }
- }
-});
diff --git a/app/components/widget-label.js b/app/components/widget-label.js
deleted file mode 100644
index 5fd22fe..0000000
--- a/app/components/widget-label.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * File: widget-label.js
- * Author: Markus Grigull
- * Date: 03.11.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import WidgetAbstract from './widget-abstract';
-
-export default WidgetAbstract.extend({
- classNames: [ 'widgetLabel' ],
-
- minWidth_resize: 50,
- minHeight_resize: 20,
-
- doubleClick() {
- if (this.get('editing') === true) {
- // prepare modal
- this.set('name', this.get('widget.name'));
- this.set('errorMessage', null);
-
- // show modal
- this.set('isShowingModal', true);
- }
- },
-
- actions: {
- submitModal() {
- // verify properties
- let properties = this.getProperties('name');
-
- if (properties['name'] === null || properties['name'] === "") {
- this.set('errorMessage', 'Widget name is missing');
- return;
- }
-
- // save properties
- this.get('widget').setProperties(properties);
-
- let self = this;
-
- this.get('widget').save().then(function() {
- self.set('isShowingModal', false);
- });
- },
-
- cancelModal() {
- this.set('isShowingModal', false);
- },
-
- deleteModal() {
- // delete widget
- this.get('widget').destroyRecord();
-
- this.set('isShowingModal', false);
- },
- }
-});
diff --git a/app/components/widget-plot.js b/app/components/widget-plot.js
deleted file mode 100644
index 7574de0..0000000
--- a/app/components/widget-plot.js
+++ /dev/null
@@ -1,292 +0,0 @@
-/**
- * File: widget-value.js
- * Author: Markus Grigull
- * Date: 08.12.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import WidgetAbstract from './widget-abstract';
-
-export default WidgetAbstract.extend({
- classNames: [ 'widgetPlot' ],
-
- plotData: Ember.A([]),
-
- plotOptions: {
- series: {
- lines: {
- show: true,
- lineWidth: 2
- },
- shadowSize: 0
- },
- xaxis: {
- mode: 'time',
- timeformat: '%M:%S',
- axisLabel: 'time [min]',
- axisLabelUseCanvas: true
- }/*,
- yaxis: {
- tickDecimals: 1,
- axisLabel: this.data.get('type'),
- axisLabelUseCanvas: true
- }*/
- },
-
- signals: Ember.A([]),
- checkedSignals: {},
- plotType: "multiple",
- time: null,
- observeQuery: null,
- selectedSignal: null,
-
- _updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', 'widget.widgetData.type', 'widget.widgetData.signals', function() {
- // get query for observer
- let simulatorId = this.get('widget.widgetData.simulator');
- let query = 'data.' + simulatorId + '.sequence';
-
- // get plot settings
- let signals = this.get('widget.widgetData.signals');
- this.set('signals', signals);
-
- let plotType = this.get('widget.widgetData.type');
- this.set('plotType', plotType);
-
- if (plotType === 'table') {
- // set simulation model for table with signals
- var self = this;
- let simulatorid = this.get('widget.widgetData.simulator');
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- // find simulation model by simulatorid
- simulationModels.forEach(function(simulationModel) {
- simulationModel.get('simulator').then((simulator) => {
- if (simulator.get('simulatorid') === simulatorid) {
- // set simulation model
- self.set('simulationModel', simulationModel);
-
- if (self.get('selectedSignal') === null) {
- self.set('selectedSignal', simulationModel.get('mapping')[0]);
- }
- }
- });
- });
- });
- });
- });
- });
- }
-
- // update observer TODO: Only update when (query) changed
- let observeQuery = this.get('observeQuery');
- if (query !== observeQuery) {
- if (observeQuery != null) {
- this.removeObserver(observeQuery, this._updateData);
- }
-
- this.addObserver(query, this._updateData);
- this.set('observeQuery', query);
- }
- })),
-
- _updateData() {
- // get values from array
- let simulatorId = this.get('widget.widgetData.simulator');
- let values = this.get('data.' + simulatorId + '.flotValues');
- var updatedValues = Ember.A([]);
-
- // update plot options
- var plotOptions = this.get('plotOptions');
-
- // calculate diff for first and last timestamp
- var firstTimestamp = values[0][0][0];
- var lastTimestamp = values[0][values[0].length - 1][0];
-
- var diff = lastTimestamp - firstTimestamp;
- var diffValue = this.get('widget.widgetData.time') * 1000; // javascript timestamps are in milliseconds
-
- if (diff > diffValue) {
- firstTimestamp = lastTimestamp - diffValue;
- } else {
- lastTimestamp = firstTimestamp + diffValue;
- }
-
- plotOptions.xaxis.min = firstTimestamp;
- plotOptions.xaxis.max = lastTimestamp;
- this.set('plotOptions', plotOptions);
-
- // update values
- var index = 0;
-
- this.get('signals').forEach(function(signal) {
- updatedValues.replace(index, 1, Ember.A([ values[signal] ]));
- index += 1;
- });
-
- this.set('plotData', updatedValues);
- },
-
- doubleClick() {
- if (this.get('editing') === true) {
- // prepare modal
- this.set('name', this.get('widget.name'));
- this.set('plotType', this.get('widget.widgetData.type'));
- this.set('time', this.get('widget.widgetData.time'));
- this.set('errorMessage', null);
-
- // get signal mapping for simulation model
- let self = this;
- let simulatorid = this.get('widget.widgetData.simulator');
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- // find simulation model by simulatorid
- simulationModels.forEach(function(simulationModel) {
- simulationModel.get('simulator').then((simulator) => {
- if (simulator.get('simulatorid') === simulatorid) {
- // set simulation model
- self.set('simulationModel', simulationModel);
- self.set('simulationModelName', simulationModel.get('name'));
-
- // set signals
- let mapping = simulationModel.get('mapping');
- let checkedSignals = {};
-
- // uncheck all signals
- mapping.forEach(function(key) {
- checkedSignals[key] = false;
- });
-
- self.get('signals').forEach(function(signal) {
- checkedSignals[mapping[signal]] = true;
- });
-
- self.set('checkedSignals', checkedSignals);
- }
- });
- });
- });
- });
- });
- });
-
- // show modal
- this.set('isShowingModal', true);
- }
- },
-
- actions: {
- submitModal() {
- // verify properties
- let properties = this.getProperties('name');
-
- // set simulator by simulation model name
- let simulationModelName = this.get('simulationModelName');
- let self = this;
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- // find simulation model by name
- simulationModels.forEach(function(simulationModel) {
- if (simulationModel.get('name') === simulationModelName) {
- simulationModel.get('simulator').then((simulator) => {
- // set simulator
- let widgetData = {
- type: self.get('plotType')
- };
-
- widgetData.simulator = simulator.get('simulatorid');
- widgetData.time = self.get('time');
-
- // set signals
- let mapping = simulationModel.get('mapping');
- widgetData.signals = [];
-
- // uncheck all signals
- let checkedSignals = self.get('checkedSignals');
-
- for (var i = 0; i < mapping.length; i++) {
- if (checkedSignals[mapping[i]]) {
- widgetData.signals.push(i);
- }
- }
-
- // save properties
- properties['widgetData'] = widgetData;
-
- self.get('widget').setProperties(properties);
-
- self.get('widget').save().then(function() {
- self.set('isShowingModal', false);
- });
- });
- }
- });
- });
- });
- });
- });
- },
-
- cancelModal() {
- this.set('isShowingModal', false);
- },
-
- deleteModal() {
- // delete widget
- this.get('widget').destroyRecord();
-
- this.set('isShowingModal', false);
- },
-
- selectSimulationModel(simulationModelName) {
- // save simulation model
- this.set('simulationModelName', simulationModelName);
-
- // get signal mapping for simulation model
- let self = this;
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- // find simulation model by name
- simulationModels.forEach(function(simulationModel) {
- if (simulationModel.get('name') === simulationModelName) {
- self.set('simulationModel', simulationModel);
- }
- });
- });
- });
- });
- });
- },
-
- selectType(type) {
- this.set('plotType', type);
- },
-
- selectTableSignal(signal) {
- // display signal
- let mapping = this.get('simulationModel.mapping');
-
- for (var i = 0; i < mapping.length; i++) {
- if (mapping[i] === signal) {
- this.set('widget.widgetData.signals', [ i ]);
- }
- }
-
- this.set('selectedSignal', signal);
- }
- }
-});
diff --git a/app/components/widget-table.js b/app/components/widget-table.js
deleted file mode 100644
index 74c14bd..0000000
--- a/app/components/widget-table.js
+++ /dev/null
@@ -1,170 +0,0 @@
-/**
- * File: widget-table.js
- * Author: Markus Grigull
- * Date: 05.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import WidgetAbstract from './widget-abstract';
-import Ember from 'ember';
-
-export default WidgetAbstract.extend({
- classNames: [ 'widgetTable' ],
-
- minWidth_resize: 200,
- minHeight_resize: 60,
-
- signals: [],
-
- observeQuery: null,
-
- _updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', function() {
- // get query for observer
- let simulatorId = this.get('widget.widgetData.simulator');
- let query = 'data.' + simulatorId + '.sequence';
- let observeQuery = this.get('observeQuery');
- if (observeQuery != null) {
- this.removeObserver(observeQuery, this._updateData);
- }
-
- this.addObserver(query, this._updateData);
- this.set('observeQuery', query);
-
- // get signal names
- let self = this;
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- // get simulation model by simulatorId
- simulationModels.forEach((simulationModel) => {
- simulationModel.get('simulator').then((simulator) => {
- if (simulator.get('simulatorid') === simulatorId) {
- // set signal names
- let signals = [];
-
- simulationModel.get('mapping').forEach((signalName) => {
- signals.push({ name: signalName, value: null });
- });
-
- self.set('signals', signals);
- }
- });
- });
- });
- });
- });
- });
- })),
-
- _updateData() {
- // get signal names to fill data in
- let signals = this.get('signals');
- if (!signals) {
- // wait till names are loaded
- return;
- }
-
- // get values from array
- let values = this.get('data.' + this.get('widget.widgetData.simulator') + '.values');
- for (let i = 0; i < values.length; i++) {
- if (!signals[i]) {
- break;
- }
-
- Ember.set(signals[i], 'value', values[i]);
- }
- },
-
- doubleClick() {
- if (this.get('editing') === true) {
- // prepare modal
- this.set('name', this.get('widget.name'));
- this.set('errorMessage', null);
-
- // get simlator name from id
- let self = this;
- let simulatorid = this.get('widget.widgetData.simulator');
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- // find simulation model by simulatorid
- simulationModels.forEach((simulationModel) => {
- simulationModel.get('simulator').then((simulator) => {
- if (simulator.get('simulatorid') === simulatorid) {
- // set simulation model
- self.set('simulationModel', simulationModel);
- self.set('simulationModelName', simulationModel.get('name'));
- }
- });
- });
- });
- });
- });
- });
-
- // show modal
- this.set('isShowingModal', true);
- }
- },
-
- actions: {
- submitModal() {
- // verify properties
- let properties = this.getProperties('name');
-
- // set simulator by simulation model name
- let simulationModelName = this.get('simulationModelName');
- let self = this;
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- // find simulation model by name
- simulationModels.forEach(function(simulationModel) {
- if (simulationModel.get('name') === simulationModelName) {
- simulationModel.get('simulator').then((simulator) => {
- // set simulator
- let widgetData = {};
- widgetData.simulator = simulator.get('simulatorid');
-
- // save properties
- properties['widgetData'] = widgetData;
-
- self.get('widget').setProperties(properties);
-
- self.get('widget').save().then(function() {
- self.set('isShowingModal', false);
- });
- });
- }
- });
- });
- });
- });
- });
- },
-
- cancelModal() {
- this.set('isShowingModal', false);
- },
-
- deleteModal() {
- // delete widget
- this.get('widget').destroyRecord();
-
- this.set('isShowingModal', false);
- },
-
- selectSimulationModel(simulationModelName) {
- // save simulation model
- this.set('simulationModelName', simulationModelName);
- }
- }
-});
diff --git a/app/components/widget-value.js b/app/components/widget-value.js
deleted file mode 100644
index efcbfbe..0000000
--- a/app/components/widget-value.js
+++ /dev/null
@@ -1,167 +0,0 @@
-/**
- * File: widget-value.js
- * Author: Markus Grigull
- * Date: 04.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import WidgetAbstract from './widget-abstract';
-import Ember from 'ember';
-
-export default WidgetAbstract.extend({
- classNames: [ 'widgetValue' ],
-
- minWidth_resize: 50,
- minHeight_resize: 20,
-
- observeQuery: null,
-
- _updateDataObserver: Ember.on('init', Ember.observer('widget.widgetData.simulator', 'widget.widgetData.signal', function() {
- // update observer
- let query = 'data.' + this.get('widget.widgetData.simulator') + '.sequence';
- let observeQuery = this.get('observeQuery');
- if (observeQuery != null) {
- this.removeObserver(observeQuery, this._updateData);
- }
-
- this.addObserver(query, this._updateData);
- this.set('observeQuery', query);
- })),
-
- _updateData() {
- // get value from array
- let values = this.get('data.' + this.get('widget.widgetData.simulator') + '.values');
- if (values) {
- this.set('value', values[this.get('widget.widgetData.signal')]);
- } else {
- this.set('value', null);
- }
- },
-
- doubleClick() {
- if (this.get('editing') === true) {
- // prepare modal
- this.set('name', this.get('widget.name'));
- this.set('errorMessage', null);
-
- // get signal mapping for simulation model
- let self = this;
- let simulatorid = this.get('widget.widgetData.simulator');
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- // find simulation model by simulatorid
- simulationModels.forEach(function(simulationModel) {
- simulationModel.get('simulator').then((simulator) => {
- if (simulator.get('simulatorid') === simulatorid) {
- // set simulation model
- self.set('simulationModel', simulationModel);
- self.set('simulationModelName', simulationModel.get('name'));
-
- // set signal
- let mapping = simulationModel.get('mapping');
- self.set('signalName', mapping[self.get('widget.widgetData.signal')]);
- }
- });
- });
- });
- });
- });
- });
-
- // show modal
- this.set('isShowingModal', true);
- }
- },
-
- actions: {
- submitModal() {
- // verify properties
- let properties = this.getProperties('name');
-
- // set simulator by simulation model name
- let simulationModelName = this.get('simulationModelName');
- let self = this;
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- // find simulation model by name
- simulationModels.forEach(function(simulationModel) {
- if (simulationModel.get('name') === simulationModelName) {
- simulationModel.get('simulator').then((simulator) => {
- // set simulator
- let widgetData = {};
- widgetData.simulator = simulator.get('simulatorid');
-
- // set signal by name
- let mapping = simulationModel.get('mapping');
- let signalName = self.get('signalName');
-
- for (let i = 0; i < mapping.length; i++) {
- if (mapping[i] === signalName) {
- widgetData.signal = i;
- }
- }
-
- // save properties
- properties['widgetData'] = widgetData;
-
- self.get('widget').setProperties(properties);
-
- self.get('widget').save().then(function() {
- self.set('isShowingModal', false);
- });
- });
- }
- });
- });
- });
- });
- });
- },
-
- cancelModal() {
- this.set('isShowingModal', false);
- },
-
- deleteModal() {
- // delete widget
- this.get('widget').destroyRecord();
-
- this.set('isShowingModal', false);
- },
-
- selectSimulationModel(simulationModelName) {
- // save simulation model
- this.set('simulationModelName', simulationModelName);
-
- // get signal mapping for simulation model
- let self = this;
-
- this.get('widget.visualization').then((visualization) => {
- visualization.get('project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- // find simulation model by name
- simulationModels.forEach(function(simulationModel) {
- if (simulationModel.get('name') === simulationModelName) {
- self.set('simulationModel', simulationModel);
- }
- });
- });
- });
- });
- });
- },
-
- selectSignal(signalName) {
- this.set('signalName', signalName);
- }
- }
-});
diff --git a/app/controllers/.gitkeep b/app/controllers/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/app/controllers/login.js b/app/controllers/login.js
deleted file mode 100644
index 699eaa1..0000000
--- a/app/controllers/login.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * File: login.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- session: Ember.inject.service('session'),
-
- actions: {
- authenticate() {
- let { username, password } = this.getProperties('username', 'password');
- this.get('session').authenticate('authenticator:custom', username, password).catch((reason) => {
- this.set('errorMessage', reason);
- });
- }
- }
-});
diff --git a/app/controllers/me.js b/app/controllers/me.js
deleted file mode 100644
index 8897e12..0000000
--- a/app/controllers/me.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * File: me.js
- * Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- isAdmin: Ember.computed('model', function() {
- var level = this.get('model.adminLevel');
- return level >= 1;
- }),
-
- actions: {
- changeUser() {
- // save the changes
- var user = this.get('model');
- user.save();
- }
- }
-});
diff --git a/app/controllers/project/index.js b/app/controllers/project/index.js
deleted file mode 100644
index 80f931b..0000000
--- a/app/controllers/project/index.js
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * File: index.js
- * Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- isShowingNewModal: false,
- isShowingEditModal: false,
- isShowingDeleteModal: false,
-
- errorMessage: null,
-
- visualization: null,
-
- actions: {
- showNewModal() {
- // reset properties
- this.set('errorMessage', null);
- this.set('name', null);
-
- // show the dialog
- this.set('isShowingNewModal', true);
- },
-
- showEditModal(visualization) {
- // set properties
- this.set('errorMessage', null);
- this.set('visualization', visualization);
- this.set('name', visualization.get('name'));
-
- // show the dialog
- this.set('isShowingEditModal', true);
- },
-
- showDeleteModal(visualization) {
- // set properties
- this.set('visualization', visualization);
-
- // show the dialog
- this.set('isShowingDeleteModal', true);
- },
-
- submitNew() {
- // verify properties
- var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] === "") {
- this.set('errorMessage', 'Visualization name is missing');
- return;
- }
-
- // set project property
- properties['project'] = this.get('model.id');
-
- // create new project
- var visualization = this.store.createRecord('visualization', properties);
- var controller = this;
-
- // this change will not be saved, but it is nessecary otherwise ember will omit the project's id in the post request
- var project = this.get('model');
- project.get('visualizations').pushObject(visualization);
-
- visualization.save().then(function() {
- controller.set('isShowingNewModal', false);
- }, function() {
- Ember.debug('Error saving new visualization');
- });
- },
-
- cancelNew() {
- this.set('isShowingNewModal', false);
- },
-
- submitEdit() {
- // verify properties
- var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] === "") {
- this.set('errorMessage', 'Visualization name is missing');
- return;
- }
-
- // save properties
- this.get('visualization').setProperties(properties);
-
- var controller = this;
-
- this.get('visualization').save().then(function() {
- controller.set('isShowingEditModal', false);
- }, function() {
- Ember.debug('Error saving edit visualization');
- });
- },
-
- cancelEdit() {
- this.set('isShowingEditModal', false);
- },
-
- confirmDelete() {
- // delete the visualization
- var visualization = this.get('visualization');
- visualization.destroyRecord();
-
- // hide the dialog
- this.set('isShowingDeleteModal', false);
- },
-
- cancelDelete() {
- this.set('isShowingDeleteModal', false);
- }
- }
-});
diff --git a/app/controllers/projects.js b/app/controllers/projects.js
deleted file mode 100644
index 337bc46..0000000
--- a/app/controllers/projects.js
+++ /dev/null
@@ -1,151 +0,0 @@
-/**
- * File: projects.js
- * Author: Markus Grigull
- * Date: 01.10.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- sessionUser: Ember.inject.service('session-user'),
-
- isShowingNewModal: false,
- isShowingEditModal: false,
- isShowingDeleteModal: false,
-
- errorMessage: null,
-
- project: null,
- projectSimulation: null,
-
- _updateSimulations: Ember.observer('model', function() {
- if (this.get('model.simulations') != null && this.get('model.simulations.length') > 0) {
- var simulations = this.get('model.simulations');
- this.set('projectSimulation', simulations.toArray()[0]);
- }
- }),
-
- actions: {
- showNewModal() {
- // reset properties
- this.set('errorMessage', null);
- this.set('name', null);
-
- // show the dialog
- this.set('isShowingNewModal', true);
- },
-
- showEditModal(project) {
- // set properties
- this.set('errorMessage', null);
- this.set('project', project);
- this.set('name', project.get('name'));
- this.set('projectSimulation', project.get('simulation'));
-
- // show the dialog
- this.set('isShowingEditModal', true);
- },
-
- showDeleteModal(project) {
- // set properties
- this.set('project', project);
-
- // show the dialog
- this.set('isShowingDeleteModal', true);
- },
-
- submitNew() {
- // verify properties
- var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] === "") {
- this.set('errorMessage', 'Project name is missing');
- return;
- }
-
- // set owner property
- var user = this.get('sessionUser.user');
- properties['owner'] = user;
-
- // set simulation property
- properties['simulation'] = this.get('projectSimulation.id');
-
- // create new project
- var project = this.store.createRecord('project', properties);
-
- // this change will not be saved, but it is nessecary otherwise ember will omit the simulation's id in the post request
- this.get('projectSimulation.projects').pushObject(project);
-
- var controller = this;
-
- project.save().then(function() {
- controller.set('isShowingNewModal', false);
- }, function() {
- Ember.debug('Error saving new project');
- });
- },
-
- cancelNew() {
- this.set('isShowingNewModal', false);
- },
-
- submitEdit() {
- // verify properties
- var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] === "") {
- this.set('errorMessage', 'Project name is missing');
- return;
- }
-
- // remove from old simulation
-
-
- // save properties
- properties['simulation'] = this.get('projectSimulation.id');
-
- this.get('project').setProperties(properties);
-
- // this change will not be saved, but it is nessecary otherwise ember will omit the simulation's id in the post request
- this.get('projectSimulation.projects').pushObject(this.get('project'));
-
- var controller = this;
-
- this.get('project').save().then(function() {
- controller.set('isShowingEditModal', false);
- }, function() {
- Ember.debug('Error saving edit project');
- });
- },
-
- cancelEdit() {
- this.set('isShowingEditModal', false);
- },
-
- confirmDelete() {
- // delete the project
- var project = this.get('project');
- project.destroyRecord();
-
- // hide the dialog
- this.set('isShowingDeleteModal', false);
- },
-
- cancelDelete() {
- this.set('isShowingDeleteModal', false);
- },
-
- selectSimulation(simulationName) {
- // get simulation by name
- var simulations = this.get('model.simulations');
- var controller = this;
-
- simulations.forEach(function(simulation) {
- if (simulation.get('name') === simulationName) {
- controller.set('projectSimulation', simulation);
- }
- });
- }
- }
-});
diff --git a/app/controllers/simulation-model/index.js b/app/controllers/simulation-model/index.js
deleted file mode 100644
index 88463c1..0000000
--- a/app/controllers/simulation-model/index.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * File: index.js
- * Author: Markus Grigull
- * Date: 20.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- _setSignalNames: Ember.observer('model', 'model.length', function() {
- // loop through signals
- let length = this.get('model.length');
- let mapping = this.get('model.mapping');
-
- for (let i = 0; i < length; i++) {
- this.set('name' + i, mapping[i]);
- }
- }),
-
- actions: {
- saveMapping() {
- // save all signal names
- let length = this.get('model.length');
- let mapping = this.get('model.mapping');
-
- for (let i = 0; i < length; i++) {
- mapping[i] = this.get('name' + i);
- }
-
- this.set('model.mapping', mapping);
-
- // save the changed model
- let self = this;
-
- this.get('model').save().then(function() {
- // go back to simulation
- self.get('model.simulation').then((simulation) => {
- self.transitionToRoute('/simulation/' + simulation.get('id'));
- });
- }, function() {
- Ember.debug('Unable to save simulation model');
- });
- }
- }
-});
diff --git a/app/controllers/simulation/index.js b/app/controllers/simulation/index.js
deleted file mode 100644
index 86d063a..0000000
--- a/app/controllers/simulation/index.js
+++ /dev/null
@@ -1,193 +0,0 @@
-/**
- * File: index.js
- * Author: Markus Grigull
- * Date: 30.09.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- isShowingNewModal: false,
- isShowingEditModal: false,
- isShowingDeleteModal: false,
-
- errorMessage: null,
-
- simulationModel: null,
- simulatorName: null,
-
- _updateSimulators: Ember.observer('model', function() {
- if (this.get('model.simulators') != null && this.get('model.simulators.length') > 0) {
- let simulators = this.get('model.simulators');
- this.set('simulatorName', simulators.toArray()[0].get('name'));
- }
- }),
-
- actions: {
- showNewModal() {
- // reset properties
- this.set('errorMessage', null);
- this.set('name', null);
- this.set('length', 1);
-
- // show the dialog
- this.set('isShowingNewModal', true);
- },
-
- showEditModal(simulationModel) {
- // set properties
- this.set('errorMessage', null);
- this.set('simulationModel', simulationModel);
- this.set('name', simulationModel.get('name'));
- this.set('length', simulationModel.get('length'));
-
- let simulators = this.get('model.simulators');
- let simulatorId = simulationModel.get('simulator.id');
- let simulatorName = null;
-
- simulators.forEach(function(simulator) {
- if (simulator.get('id') === simulatorId) {
- simulatorName = simulator.get('name');
- }
- });
-
- this.set('simulatorName', simulatorName);
-
- // show the dialog
- this.set('isShowingEditModal', true);
- },
-
- showDeleteModal(simulationModel) {
- // set properties
- this.set('simulationModel', simulationModel);
-
- // show the dialog
- this.set('isShowingDeleteModal', true);
- },
-
- submitNew() {
- // verify properties
- let properties = this.getProperties('name', 'length');
- if (properties['name'] == null || properties['name'] === "") {
- this.set('errorMessage', 'Simulation model name is missing');
- return;
- }
-
- // set simuatlion properties
- let simulation = this.get('model.simulation');
- properties['simulation'] = simulation;
-
- // get the simulator by simulator name
- let simulators = this.get('model.simulators');
- let simulatorName = this.get('simulatorName');
-
- simulators.forEach(function(simulator) {
- if (simulator.get('name') === simulatorName) {
- properties['simulator'] = simulator;
- }
- });
-
- // create mapping
- let mapping = [];
-
- for (let i = 0; i < properties['length']; i++) {
- mapping.push('Signal ' + (i + 1));
- }
-
- properties['mapping'] = mapping;
-
- // create new model
- let simulationModel = this.store.createRecord('simulation-model', properties);
-
- // this change will not be saved, but it is nessecary otherwise ember will omit the simulation's id in the post request
- simulation.get('models').pushObject(simulationModel);
-
- let controller = this;
-
- simulationModel.save().then(function() {
- controller.set('isShowingNewModal', false);
- }, function() {
- Ember.debug('Error saving new model');
- });
- },
-
- cancelNew() {
- this.set('isShowingNewModal', false);
- },
-
- submitEdit() {
- // verify properties
- let properties = this.getProperties('name', 'length');
- if (properties['name'] == null || properties['name'] === "") {
- this.set('errorMessage', 'Simulation model name is missing');
- return;
- }
-
- // set simuatlion properties
- let simulation = this.get('model.simulation');
- properties['simulation'] = simulation;
-
- // get the simulator by simulator name
- let simulators = this.get('model.simulators');
- let simulatorName = this.get('simulatorName');
-
- simulators.forEach(function(simulator) {
- if (simulator.get('name') === simulatorName) {
- properties['simulator'] = simulator;
- }
- });
-
- // change mapping
- let mapping = this.get('simulationModel.mapping');
-
- if (mapping.length < properties['length']) {
- // add more signals
- for (let i = mapping.length; i < properties['length']; i++) {
- mapping.push('Signal ' + (i + 1));
- }
- } else if (mapping.length > properties['length']) {
- // remove signals
- mapping = mapping.slice(0, Number(properties['length']));
- }
-
- console.log(mapping);
-
- properties['mapping'] = mapping;
-
- // save properties
- let controller = this;
-
- this.get('simulationModel').setProperties(properties);
-
- this.get('simulationModel').save().then(function() {
- controller.set('isShowingEditModal', false);
- }, function() {
- Ember.debug('Error saving edit simulation model');
- });
- },
-
- cancelEdit() {
- this.set('isShowingEditModal', false);
- },
-
- confirmDelete() {
- // delete the model
- let simulationModel = this.get('simulationModel');
- simulationModel.destroyRecord();
-
- // hide the dialog
- this.set('isShowingDeleteModal', false);
- },
-
- cancelDelete() {
- this.set('isShowingDeleteModal', false);
- },
-
- selectSimulator(simulator) {
- this.set('simulatorName', simulator);
- }
- }
-});
diff --git a/app/controllers/simulations.js b/app/controllers/simulations.js
deleted file mode 100644
index 0be9ecf..0000000
--- a/app/controllers/simulations.js
+++ /dev/null
@@ -1,153 +0,0 @@
-/**
- * File: simulation.js
- * Author: Markus Grigull
- * Date: 30.09.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- sessionUser: Ember.inject.service('session-user'),
-
- isShowingNewModal: false,
- isShowingEditModal: false,
- isShowingDeleteModal: false,
-
- errorMessage: null,
-
- simulation: null,
- simulationRunning: true,
-
- actions: {
- showNewModal() {
- // reset properties
- this.set('errorMessage', null);
- this.set('name', null);
-
- // show the dialog
- this.set('isShowingNewModal', true);
- },
-
- showEditModal(simulation) {
- // set properties
- this.set('errorMessage', null);
- this.set('simulation', simulation);
- this.set('name', simulation.get('name'));
-
- // show the dialog
- this.set('isShowingEditModal', true);
- },
-
- showDeleteModal(simulation) {
- // set properties
- this.set('simulation', simulation);
-
- // show the dialog
- this.set('isShowingDeleteModal', true);
- },
-
- showRunningModal(simulation) {
- // set properties
- this.set('simulation', simulation);
- this.set('simulationRunning', simulation.get('running'));
-
- // show the dialog
- this.set('isShowingRunningModal', true);
- },
-
- submitNew() {
- // verify properties
- var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] === "") {
- this.set('errorMessage', 'Simulation name is missing');
- return;
- }
-
- // set owner properties
- var user = this.get('sessionUser.user');
- properties['owner'] = user;
-
- // create new simulation
- var simulation = this.store.createRecord('simulation', properties);
- var controller = this;
-
- simulation.save().then(function() {
- controller.set('isShowingNewModal', false);
- }, function() {
- Ember.debug('Error saving new simulation');
- });
- },
-
- cancelNew() {
- this.set('isShowingNewModal', false);
- },
-
- submitEdit() {
- // verify properties
- var properties = this.getProperties('name');
- if (properties['name'] == null || properties['name'] === "") {
- this.set('errorMessage', 'Simulation name is missing');
- return;
- }
-
- // save properties
- this.get('simulation').set('name', properties['name']);
-
- var controller = this;
-
- this.get('simulation').save().then(function() {
- controller.set('isShowingEditModal', false);
- }, function() {
- Ember.debug('Error saving edit simulation');
- });
- },
-
- cancelEdit() {
- this.set('isShowingEditModal', false);
- },
-
- confirmDelete() {
- // delete the simulation
- var simulation = this.get('simulation');
- simulation.destroyRecord();
-
- // hide the dialog
- this.set('isShowingDeleteModal', false);
- },
-
- cancelDelete() {
- this.set('isShowingDeleteModal', false);
- },
-
- confirmRunningSimulation() {
- // set the property
- var simulation = this.get('simulation');
- simulation.set('running', this.get('simulationRunning'));
-
- // save property
- var controller = this;
-
- simulation.save().then(function() {
- controller.set('isShowingRunningModal', false);
- }, function() {
- Ember.debug('Error saving running simulation');
- });
- },
-
- cancelRunningSimulation() {
- this.set('isShowingRunningModal', false);
- },
-
- selectRunning(running) {
- // NOTE: running is a string and not a boolean value
- if (running === 'true') {
- this.set('simulationRunning', true);
- } else {
- this.set('simulationRunning', false);
- }
- }
- }
-});
diff --git a/app/controllers/simulators.js b/app/controllers/simulators.js
deleted file mode 100644
index 2163e3c..0000000
--- a/app/controllers/simulators.js
+++ /dev/null
@@ -1,158 +0,0 @@
-/**
- * File: simulators.js
- * Author: Markus Grigull
- * Date: 30.09.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- isShowingNewModal: false,
- isShowingDeleteModal: false,
- isShowingEditModal: false,
- isShowingRunningModal: false,
-
- simulatorid: 1,
- errorMessage: null,
- simulator: null,
- simulatorName: null,
- simulatorEdit: null,
- simulatorRunning: true,
-
- actions: {
- showNewModal() {
- // reset the properties
- this.set('errorMessage', null);
- this.set('simulatorid', 1);
- this.set('name', null);
- this.set('endpoint', null);
-
- // show the modal dialog
- this.set('isShowingNewModal', true);
- },
-
- showDeleteModal(simulator) {
- this.set('isShowingDeleteModal', true);
- this.set('simulator', simulator);
- },
-
- showEditModal(simulator) {
- // set properties
- this.set('errorMessage', null);
- this.set('simulator', simulator);
- this.set('simulatorid', simulator.get('simulatorid'));
- this.set('simulatorName', simulator.get('name'));
- this.set('simulatorEndpoint', simulator.get('endpoint'));
-
- // show the modal dialog
- this.set('isShowingEditModal', true);
- },
-
- showRunningModal(simulator) {
- // set properties
- this.set('simulator', simulator);
- this.set('simulatorRunning', simulator.get('running'));
-
- // show the dialog
- this.set('isShowingRunningModal', true);
- },
-
- newSimulator() {
- // verify properties
- var properties = this.getProperties('name', 'simulatorid', 'endpoint');
- if (properties['name'] == null) {
- this.set('errorMessage', 'Simulator name is missing');
- return;
- } else if (properties['endpoint'] == null) {
- this.set('errorMessage', 'Simulator endpoint is missing');
- return;
- }
-
- // create new simulator from properties
- var simulator = this.store.createRecord('simulator', properties);
- var controller = this;
-
- simulator.save().then(function() {
- controller.set('isShowingNewModal', false);
- }, function() {
- Ember.debug('Error saving new simulator');
- });
- },
-
- cancelNewSimulator() {
- this.set('isShowingNewModal', false);
- },
-
- cancelDeleteSimulator() {
- this.set('isShowingDeleteModal', false);
- },
-
- confirmDeleteSimulator() {
- // delete the simulator
- var simulator = this.get('simulator');
- simulator.destroyRecord();
-
- // hide the modal dialog
- this.set('isShowingDeleteModal', false);
- },
-
- editSimulator() {
- // verify new properties
- if (this.get('simulatorName') == null) {
- this.set('errorMessage', 'Simulator name is missing');
- return;
- } else if (this.get('simulatorEndpoint') == null) {
- this.set('errorMessage', 'Simulator endpoint is missing');
- return;
- }
-
- // save property changes
- this.get('simulator').set('name', this.get('simulatorName'));
- this.get('simulator').set('simulatorid', this.get('simulatorid'));
- this.get('simulator').set('endpoint', this.get('simulatorEndpoint'));
-
- var controller = this;
-
- this.get('simulator').save().then(function() {
- controller.set('isShowingEditModal', false);
- }, function() {
- Ember.debug('Error saving edit simulator');
- });
- },
-
- cancelEditSimulator() {
- this.set('isShowingEditModal', false);
- },
-
- confirmRunningSimulation() {
- // set the property
- var simulator = this.get('simulator');
- simulator.set('running', this.get('simulatorRunning'));
-
- // save property
- var controller = this;
-
- simulator.save().then(function() {
- controller.set('isShowingRunningModal', false);
- }, function() {
- Ember.debug('Error saving running simulator');
- });
- },
-
- cancelRunningSimulation() {
- this.set('isShowingRunningModal', false);
- },
-
- selectRunning(running) {
- // NOTE: running is a string and not a boolean value
- if (running === 'true') {
- this.set('simulatorRunning', true);
- } else {
- this.set('simulatorRunning', false);
- }
- }
- }
-});
diff --git a/app/controllers/user/delete.js b/app/controllers/user/delete.js
deleted file mode 100644
index 19046dc..0000000
--- a/app/controllers/user/delete.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * File: delete.js
- * Author: Markus Grigull
- * Date: 11.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- sessionUser: Ember.inject.service('session-user'),
-
- actions: {
- cancelDelete() {
- this.transitionToRoute('/user/');
- },
-
- confirmDelete() {
- // delete all projects
- var user = this.get('model');
- user.destroyRecord();
-
- this.transitionToRoute('/user/');
- }
- }
-});
diff --git a/app/controllers/user/edit.js b/app/controllers/user/edit.js
deleted file mode 100644
index b44440a..0000000
--- a/app/controllers/user/edit.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * File: edit.js
- * Author: Markus Grigull
- * Date: 11.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- actions: {
- saveEdit() {
- // save the changes
- var user = this.get('model');
- var controller = this;
-
- user.save().then(function() {
- controller.transitionToRoute('/user/');
- });
- },
-
- cancelEdit() {
- this.transitionToRoute('/user/');
- }
- }
-});
diff --git a/app/controllers/user/index.js b/app/controllers/user/index.js
deleted file mode 100644
index 021b80b..0000000
--- a/app/controllers/user/index.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * File: index.js
- * Author: Markus Grigull
- * Date: 11.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- users: Ember.computed('model.@each', function() {
- var filteredUsers = this.get('model');
- filteredUsers.forEach(function(user) {
- // catch undefined user
- if (user) {
- if (user.get('id') === 'me') {
- filteredUsers.removeObject(user);
- }
- }
- });
-
- return filteredUsers;
- })
-});
diff --git a/app/controllers/user/new.js b/app/controllers/user/new.js
deleted file mode 100644
index 249f448..0000000
--- a/app/controllers/user/new.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * File: new.js
- * Author: Markus Grigull
- * Date: 11.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
- actions: {
- newUser() {
- // create new user from properties
- var properties = this.getProperties('username', 'password');
-
- var user = this.store.createRecord('user', properties);
- var controller = this;
-
- user.save().then(function() {
- controller.transitionToRoute('/user');
- });
- },
-
- cancelNewUser() {
- this.transitionToRoute('/user');
- }
- }
-});
diff --git a/app/controllers/visualization/edit.js b/app/controllers/visualization/edit.js
deleted file mode 100644
index 3478d7e..0000000
--- a/app/controllers/visualization/edit.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * File: edit.js
- * Author: Markus Grigull
- * Date: 05.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import FetchLiveDataMixin from '../../mixins/fetch-live-data';
-
-export default Ember.Controller.extend(FetchLiveDataMixin, {
- isShowingWidgetValueModal: false,
-
- errorMessage: null,
-
- widget: null,
- name: null,
- simulator: null,
- simulatorName: null,
- signal: null,
-
- actions: {
- addWidget(name, position) {
- // get first simulator id
- let defaultSimulatorid = 0;
-
- this.get('model.project').then((project) => {
- project.get('simulation').then((simulation) => {
- simulation.get('models').then((simulationModels) => {
- simulationModels.toArray()[0].get('simulator').then((simulator) => {
- defaultSimulatorid = simulator.get('simulatorid');
-
- // create widget
- let widget = null;
- let properties = {
- x: position.x,
- y: position.y,
- name: 'widget',
- type: null
- };
-
- if (name === 'label') {
- properties.type = 'widget-label';
- properties.width = 100;
- properties.height = 20;
- properties.name = 'Label';
- } else if (name === 'table') {
- properties.type = 'widget-table';
- properties.name = "Table";
- properties.width = 500;
- properties.height = 200;
- properties.widgetData = { simulator: defaultSimulatorid };
- } else if (name === 'value') {
- properties.type = 'widget-value';
- properties.name = 'Value';
- properties.width = 250;
- properties.height = 20;
- properties.widgetData = { signal: 0, simulator: defaultSimulatorid };
- } else if (name === 'plot') {
- properties.type = 'widget-plot';
- properties.name = 'Plot';
- properties.width = 500;
- properties.height = 400;
- properties.widgetData = { signals: [0], simulator: defaultSimulatorid, type: 'multiple', time: 300 };
- } else if (name === 'image') {
- properties.type = 'widget-image';
- properties.name = 'Image';
- properties.width = 300;
- properties.height = 300;
- properties.widgetData = { path: null };
- } else {
- // DEBUG
- console.log('Add unknown widget ' + name);
- return;
- }
-
- if (properties.type != null) {
- // create widget
- widget = this.store.createRecord('widget', properties);
-
- // add widget to visualization
- this.get('model.widgets').pushObject(widget);
-
- // save new widget
- var visualization = this.get('model');
-
- widget.save().then(function() {
- // save the widget in the visualization
- visualization.get('widgets').pushObject(widget);
- visualization.save();
- });
- } else {
- console.error('Unknown widget type: ' + name);
- }
- });
- });
- });
- });
- },
-
- saveEdit() {
- // save changes to store
- var widgets = this.get('model.widgets');
- widgets.forEach(function(widget) {
- widget.save();
- });
-
- // go back to index
- var id = this.get('model.id');
- this.transitionToRoute('/visualization/' + id);
- },
-
- cancelEdit() {
- // TODO: revert changes
-
- let id = this.get('model.id');
- this.transitionToRoute('/visualization/' + id);
- },
-
- showWidgetDialog(widget) {
- // show dialog by widget type
- let widgetType = widget.get('type');
- if (widgetType === 'value') {
- // set properties
- this.set('widget', widget);
- /*this.set('name', plot.get('name'));
- this.set('signal', plot.get('signal'));*/
-
- //this.set('simulatorName', simulatorName);
-
- this.set('isShowingWidgetValueModal', true);
- }
- }
- }
-});
diff --git a/app/helpers/.gitkeep b/app/helpers/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/app/index.html b/app/index.html
deleted file mode 100644
index f0991a2..0000000
--- a/app/index.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
- VillaswebFrontend
-
-
-
- {{content-for "head"}}
-
-
-
-
- {{content-for "head-footer"}}
-
-
- {{content-for "body"}}
-
-
-
-
- {{content-for "body-footer"}}
-
-
diff --git a/app/mixins/draggable.js b/app/mixins/draggable.js
deleted file mode 100644
index 811b31e..0000000
--- a/app/mixins/draggable.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * File: draggable.js
- * Author: Markus Grigull
- * Date: 15.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Mixin.create({
- uiDragOptions: [ 'disabled_drag', 'addClasses_drag', 'appendTo_drag', 'axis_drag',
- 'cancel_drag', 'connectToSortable_drag', 'containment_drag', 'cursor_drag',
- 'delay_drag', 'distance_drag', 'grid_drag', 'handle_drag','helper_drag',
- 'iframeFix_drag','opacity_drag','scope_drag', 'snap_drag', 'snapMode_drag', 'stack_drag' ],
- uiDragEvents: [ 'create_drag', 'start_drag', 'drag_drag', 'stop_drag' ],
-
- didInsertElement() {
- this._super();
-
- // get available options and events
- var options = this._gatherDragOptions();
- this._gatherDragEvents(options);
-
- // create a new jQuery UI widget
- var ui = Ember.$.ui['draggable'](options, this.get('element'));
- this.set('ui', ui);
- },
-
- willDestroyElement() {
- var ui = this.get('ui');
-
- if (ui) {
- // remove all observers for jQuery UI widget
- var observers = this._observers;
- for (var property in observers) {
- this.removeObserver(property, observers[property]);
- }
-
- ui.destroy();
- }
- },
-
- _gatherDragOptions() {
- // parse all options and add observers for them
- var uiDragOptions = this.get('uiDragOptions') || [];
- var options = {};
-
- uiDragOptions.forEach(function(key) {
- // save the drag option without the prefix
- options[key.split('_')[0]] = this.get(key);
-
- // create an observer for this option
- var observer = function() {
- var value = this.get(key);
- this.get('ui').option(key.split('_')[0], value);
- };
-
- this.addObserver(key, observer);
-
- // save observer to remove it later on
- this._observers = this._observers || {};
- this._observers[key] = observer;
- }, this);
-
- return options;
- },
-
- _gatherDragEvents(options) {
- // register callbacks for each event
- var uiDragEvents = this.get('uiDragEvents') || [];
- var _this = this;
-
- uiDragEvents.forEach(function(event) {
- var callback = _this[event];
- if (callback) {
- options[event.split('_')[0]] = function(event, ui) {
- callback.call(_this, event, ui);
- };
- }
- });
- }
-});
diff --git a/app/mixins/droppable.js b/app/mixins/droppable.js
deleted file mode 100644
index 7e557e8..0000000
--- a/app/mixins/droppable.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * File: droppable.js
- * Author: Markus Grigull
- * Date: 15.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Mixin.create({
- uiDropOptions: [ 'accept_drop', 'addClasses_drop', 'disabled_drop', 'greedy_drop',
- 'hoverClass_drop', 'scope_drop' ],
- uiDropEvents: [ 'create_drop', 'activate_drop', 'deactivate_drop', 'over_drop',
- 'out_drop', 'drop_drop' ],
-
- didInsertElement() {
- this._super();
-
- // get available options and events
- var options = this._gatherDropOptions();
- this._gatherDropEvents(options);
-
- // create a new jQuery UI widget
- var ui = Ember.$.ui['droppable'](options, this.get('element'));
- this.set('ui', ui);
- },
-
- willDestroyElement() {
- var ui = this.get('ui');
-
- if (ui) {
- // remove all observers for jQuery UI widget
- var observers = this._observers;
- for (var property in observers) {
- this.removeObserver(property, observers[property]);
- }
-
- ui.destroy();
- }
- },
-
- _gatherDropOptions() {
- // parse all options and add observers for them
- var uiDropOptions = this.get('uiDropOptions') || [];
- var options = {};
-
- uiDropOptions.forEach(function(key) {
- // save the drop option without the postfix
- options[key.split('_')[0]] = this.get(key);
-
- // create an observer for this option
- var observer = function() {
- var value = this.get(key);
- this.get('ui').option(key.split('_')[0], value);
- };
-
- this.addObserver(key, observer);
-
- // save observer to remove it later on
- this._observers = this._observers || {};
- this._observers[key] = observer;
- }, this);
-
- return options;
- },
-
- _gatherDropEvents(options) {
- // register callbacks for each event
- var uiDropEvents = this.get('uiDropEvents') || [];
- var _this = this;
-
- uiDropEvents.forEach(function(event) {
- var callback = _this[event];
- if (callback) {
- options[event.split('_')[0]] = function(event, ui) {
- callback.call(_this, event, ui);
- };
- }
- });
- }
-});
diff --git a/app/mixins/fetch-live-data.js b/app/mixins/fetch-live-data.js
deleted file mode 100644
index a3d2b06..0000000
--- a/app/mixins/fetch-live-data.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * File: fetch-live-data.js
- * Author: Markus Grigull
- * Date: 12.10.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Mixin.create({
- data: Ember.Object.create(),
-
- _getData: Ember.observer('model', function() {
- // check if simulation is running
- let self = this;
-
- this.get('model.project').then((project) => {
- project.get('simulation').then((simulation) => {
- if (simulation.get('running')) {
- // get all models to access data
- simulation.get('models').then((simulationModels) => {
- simulationModels.forEach(function(simulationModel) {
- // get simulator
- simulationModel.get('simulator').then((simulator) => {
- let simulatorID = simulator.get('simulatorid');
- if (simulatorID) {
- // add simulation data to list
- self._loadDataForSimulator(simulatorID);
- } else {
- Ember.debug('undefined simulator id');
- }
- });
- });
- });
- } else {
- // check again if simulation is running
- Ember.run.later(this, function() {
- // trigger _getData observer
- this.notifyPropertyChange('model');
- }, 1000);
- }
- });
- });
- }),
-
- _loadDataForSimulator(simulatorID) {
- // get data by simulator id
- let simulationData = this.store.peekRecord('simulation-data', simulatorID);
- if (simulationData) {
- // add data to list
- this.set('data.' + simulatorID, simulationData);
- } else {
- // try to load data later
- Ember.run.later(this, function() {
- this._loadDataForSimulator(simulatorID);
- }, 1000);
- }
- }
-});
diff --git a/app/mixins/live-data.js b/app/mixins/live-data.js
deleted file mode 100644
index 059c2a4..0000000
--- a/app/mixins/live-data.js
+++ /dev/null
@@ -1,186 +0,0 @@
-/**
- * File: live-data.js
- * Author: Markus Grigull
- * Date: 06.10.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-const { service } = Ember.inject;
-
-export default Ember.Mixin.create({
- store: service(),
- sessionUser: service('session-user'),
-
- INTERVAL: 5000,
-
- _sockets: {},
-
- init: function() {
- this._super();
-
- // fetch the simulations for the first time
- this._fetchRunningSimulations();
-
- // start the polling loop
- setInterval((function(self) {
- return function() {
- self._fetchRunningSimulations();
- };
- })(this), this.INTERVAL);
- },
-
- _fetchRunningSimulations: function() {
- // check if the user is logged in
- if (this.get('sessionUser.user') != null) {
- // get all simulations to find all running ones
- var self = this;
-
- this.get('store').findAll('simulation').then(function(simulations) {
- simulations.forEach(function(simulation) {
- // check if the simulation is running
- if (simulation.get('running')) {
- // get all models for this simulation
- simulation.get('models').then((models) => {
- models.forEach(function(simulationModel) {
- self._addSocket(simulationModel);
- });
- });
- }
- });
- });
- }
- },
-
- _addSocket(simulationModel) {
- // check if socket is already open
- simulationModel.get('simulator').then((simulator) => {
- let id = simulator.get('simulatorid');
- if (this.get('_sockets')[id] !== undefined) {
- //Ember.debug('skip ' + simulationModel.get('name'));
- return;
- }
-
- // get simulator endpoint
- simulationModel.get('simulator').then((simulator) => {
- // get simulator endpoint
- let endpoint = simulator.get('endpoint');
- if (endpoint) {
- // add new socket
- let socket = new WebSocket('ws://' + endpoint, 'live');
- socket.binaryType = 'arraybuffer';
-
- // register callbacks
- let self = this;
-
- socket.onopen = function(event) { self._onSocketOpen.apply(self, [event]); };
- socket.onclose = function(event) { self._onSocketClose.apply(self, [event]); };
- socket.onmessage = function(event) { self._onSocketMessage.apply(self, [event]); };
- socket.onerror = function(event) { self._onSocketError.apply(self, [event]); };
-
- // add socket to list of known sockets
- this.get('_sockets')[id] = socket;
-
- //Ember.debug('Socket created for ' + simulationModel.get('name') + ': ws://' + endpoint);
- } else {
- Ember.debug('Undefined endpoint for ' + simulationModel.get('name'));
- }
- });
- });
- },
-
- _removeSocket(socket) {
- // search through all sockets
- let sockets = this.get('_sockets');
-
- for (let id in sockets) {
- if (sockets[id] === socket) {
- // remove socket from list
- delete sockets[id];
- }
- }
- },
-
- _onSocketOpen(/* event */) {
- //Ember.debug('websocket opened');
- },
-
- _onSocketClose(event) {
- if (event.wasClean) {
- Ember.debug('websocket closed');
- } else {
- Ember.debug('websocket closed: ' + event.code);
- }
-
- // remove socket from array
- this._removeSocket(event.target);
- },
-
- _onSocketMessage(event) {
- // read the message into JSON
- var message = this._messageToJSON(event.data);
-
- // set simulator by socket
- if (message.simulator === 0) {
- // search for socket in list
- let sockets = this.get('_sockets');
-
- for (let id in sockets) {
- if (sockets[id] === event.target) {
- // set id as simulator
- message.simulator = id;
- break;
- }
- }
- }
-
- // create or update simulation data object
- var simulationData = this.store.peekRecord('simulation-data', message.simulator);
- if (simulationData != null) {
- simulationData.set('sequence', message.sequence);
- simulationData.set('timestamp', new Date(message.timestamp).getTime());
- simulationData.set('values', message.values);
- } else {
- this.store.createRecord('simulation-data', {
- sequence: message.sequence,
- timestamp: new Date(message.timestamp).getTime(),
- values: message.values,
- id: message.simulator
- });
- }
- },
-
- _onSocketError(/* event */) {
- Ember.debug('websocket error');
- },
-
- _messageToJSON(blob) {
- // parse incoming message into usable data
- var data = new DataView(blob);
-
- let OFFSET_ENDIAN = 1;
- let OFFSET_TYPE = 2;
- let OFFSET_VERSION = 4;
-
- var bits = data.getUint8(0);
- var simulator = data.getUint8(0x01);
- var endian = (bits >> OFFSET_ENDIAN) & 0x1 ? 0 : 1;
- var length = data.getUint16(0x02, endian);
-
- var values = new Float32Array(data.buffer, data.byteOffset + 0x10, length);
-
- return {
- endian: endian,
- version: (bits >> OFFSET_VERSION) & 0xF,
- type: (bits >> OFFSET_TYPE) & 0x3,
- length: length,
- sequence: data.getUint32(0x04, endian),
- timestamp: data.getUint32(0x08, endian) * 1e3 + data.getUint32(0x0C, endian) * 1e-6,
- values: values,
- simulator: simulator
- };
- }
-});
diff --git a/app/mixins/resizable.js b/app/mixins/resizable.js
deleted file mode 100644
index 28a1073..0000000
--- a/app/mixins/resizable.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * File: resizable.js
- * Author: Markus Grigull
- * Date: 12.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Mixin.create({
- uiResizeOptions: [ 'disabled_resize', 'alsoResize_resize', 'animate_resize',
- 'animateDuration_resize', 'animateEasing_resize', 'aspectRatio_resize',
- 'autoHide_resize', 'cancel_resize', 'containment_resize', 'delay_resize',
- 'distance_resize', 'ghost_resize', 'grid_resize', 'handles_resize', 'helper_resize',
- 'maxHeight_resize', 'maxWidth_resize', 'minHeight_resize', 'minWidth_resize' ],
- uiResizeEvents: [ 'create_resize', 'start_resize', 'resize_resize', 'stop_resize' ],
-
- didInsertElement() {
- this._super();
-
- // get available options and events
- var options = this._gatherResizeOptions();
- this._gatherResizeEvents(options);
-
- // create a new jQuery UI widget
- var ui = Ember.$.ui['resizable'](options, this.get('element'));
- this.set('ui', ui);
- },
-
- willDestroyElement() {
- var ui = this.get('ui');
-
- if (ui) {
- // remove all observers for jQuery UI widget
- var observers = this._observers;
- for (var prop in observers) {
- if (observers.hasOwnProperty(prop)) {
- this.removeObserver(prop, observers[prop]);
- }
- }
-
- ui.destroy();
- }
- },
-
- _gatherResizeOptions() {
- // parse all options and add observers for them
- var uiResizeOptions = this.get('uiResizeOptions') || [];
- var options = {};
-
- uiResizeOptions.forEach(function(key) {
- // save the resize option without the postfix
- options[key.split('_')[0]] = this.get(key);
-
- // create an observer for this option
- var observer = function() {
- var value = this.get(key);
- //console.log(key + ': ' + value);
- this.get('ui').option(key.split('_')[0], value);
- };
-
- this.addObserver(key, observer);
-
- // save observer to remove it later on
- this._observers = this._observers || {};
- this._observers[key] = observer;
- }, this);
-
- return options;
- },
-
- _gatherResizeEvents(options) {
- // register callbacks for each event
- var uiResizeEvents = this.get('uiResizeEvents') || [];
- var _this = this;
-
- uiResizeEvents.forEach(function(event) {
- var callback = _this[event];
- if (callback) {
- options[event.split('_')[0]] = function(event, ui) {
- callback.call(_this, event, ui);
- };
- }
- });
- }
-});
diff --git a/app/mixins/sortable.js b/app/mixins/sortable.js
deleted file mode 100644
index 737367f..0000000
--- a/app/mixins/sortable.js
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * File: sortable.js
- * Author: Markus Grigull
- * Date: 15.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Mixin.create({
- uiSortOptions: [ 'appendTo_sort', 'axis_sort', 'cancel_sort', 'connectWith_sort',
- 'containment_sort', 'cursor_sort', 'cursorAt_sort', 'delay_sort', 'disabled_sort',
- 'distance_sort', 'dropOnEmpty_sort', 'forceHelperSize_sort', 'forcePlaceholderSize_sort',
- 'grid_sort', 'handle_sort', 'helper_sort', 'items_sort', 'opacity_sort',
- 'placeholder_sort', 'revert_sort', 'scroll_sort', 'scrollSensitivity_sort',
- 'scrollSpeed_sort', 'tolerance_sort', 'zIndex_sort' ],
- uiSortEvents: [ 'activate_sort', 'beforeStop_sort', 'change_sort', 'create_sort',
- 'deactivate_sort', 'out_sort', 'over_sort', 'receive_sort', 'remove_sort',
- 'sort_sort', 'start_sort', 'stop_sort', 'update_sort' ],
-
- didInsertElement() {
- this._super();
-
- // get available options and events
- var options = this._gatherSortOptions();
- this._gatherSortEvents(options);
-
- // create a new jQuery UI widget
- var ui = Ember.$.ui['sortable'](options, this.get('element'));
- this.set('ui', ui);
- },
-
- willDestroyElement() {
- var ui = this.get('ui');
-
- if (ui) {
- // remove all observers for jQuery UI widget
- var observers = this._observers;
- for (var prop in observers) {
- if (observers.hasOwnProperty(prop)) {
- this.removeObserver(prop, observers[prop]);
- }
- }
-
- ui.destroy();
- }
- },
-
- _gatherSortOptions() {
- // parse all options and add observers for them
- var uiSortOptions = this.get('uiSortOptions') || [];
- var options = {};
-
- uiSortOptions.forEach(function(key) {
- // save the sort option without the postfix
- options[key.split('_')[0]] = this.get(key);
-
- // create an observer for this option
- var observer = function() {
- var value = this.get(key);
- //console.log(key + ': ' + value);
- this.get('ui').option(key.split('_')[0], value);
- };
-
- this.addObserver(key, observer);
-
- // save observer to remove it later on
- this._observers = this._observers || {};
- this._observers[key] = observer;
- }, this);
-
- return options;
- },
-
- _gatherSortEvents(options) {
- // register callbacks for each event
- var uiSortEvents = this.get('uiSortEvents') || [];
- var _this = this;
-
- uiSortEvents.forEach(function(event) {
- var callback = _this[event];
- if (callback) {
- options[event.split('_')[0]] = function(event, ui) {
- callback.call(_this, event, ui);
- };
- }
- });
- }
-});
diff --git a/app/models/.gitkeep b/app/models/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/app/models/file.js b/app/models/file.js
deleted file mode 100644
index fc7e63a..0000000
--- a/app/models/file.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * File: file.js
- * Author: Markus Grigull
- * Date: 25.01.2017
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import DS from 'ember-data';
-
-export default DS.Model.extend({
- name: DS.attr('string'),
- path: DS.attr('string'),
- type: DS.attr('string'),
- user: DS.belongsTo('user', { async: true }),
- date: DS.attr('date')
-});
diff --git a/app/models/project.js b/app/models/project.js
deleted file mode 100644
index 9e1da03..0000000
--- a/app/models/project.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * File: project.js
- * Author: Markus Grigull
- * Date: 04.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Model from 'ember-data/model';
-import attr from 'ember-data/attr';
-import { hasMany, belongsTo } from 'ember-data/relationships';
-
-export default Model.extend({
- name: attr('string'),
- owner: belongsTo('user', { async: true }),
- visualizations: hasMany('visualization', { async: true }),
- simulation: belongsTo('simulation', { async: true })
-});
diff --git a/app/models/simulation-data.js b/app/models/simulation-data.js
deleted file mode 100644
index 37744dc..0000000
--- a/app/models/simulation-data.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * File: simulation-data.js
- * Author: Markus Grigull
- * Date: 20.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import Model from 'ember-data/model';
-import attr from 'ember-data/attr';
-// import { belongsTo, hasMany } from 'ember-data/relationships';
-
-export default Model.extend({
- simulator: Ember.computed.alias('id'),
- sequence: attr('number'),
- timestamp: attr('number'),
- values: attr('array'),
-
- flotValues: Ember.computed('_flotValues', function() {
- return this._flotValues;
- }),
-
- _flotValues: [],
-
- _updateHistories: Ember.observer('values', function() {
- // update flot values
- let values = this.get('values');
-
- // add empty arrays for each value
- while (this._flotValues.length < values.length) {
- this._flotValues.push([]);
- }
-
- for (var i = 0; i < values.length; i++) {
- this._flotValues[i].push([this.get('timestamp'), values[i]]);
-
- // discard old values
- while (this._flotValues[i].length > 1200) {
- this._flotValues[i].shift();
- }
- }
- })
-});
diff --git a/app/models/simulation-model.js b/app/models/simulation-model.js
deleted file mode 100644
index 199991a..0000000
--- a/app/models/simulation-model.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * File: simulation-model.js
- * Author: Markus Grigull
- * Date: 20.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Model from 'ember-data/model';
-import attr from 'ember-data/attr';
-import { belongsTo/*, hasMany*/ } from 'ember-data/relationships';
-
-export default Model.extend({
- name: attr('string'),
- simulator: belongsTo('simulator', { async: true }),
- length: attr('number'),
- mapping: attr('array'),
- simulation: belongsTo('simulation', { async: true })
-});
diff --git a/app/models/simulation.js b/app/models/simulation.js
deleted file mode 100644
index e705768..0000000
--- a/app/models/simulation.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * File: simulation.js
- * Author: Markus Grigull
- * Date: 26.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Model from 'ember-data/model';
-import attr from 'ember-data/attr';
-import { belongsTo, hasMany } from 'ember-data/relationships';
-
-export default Model.extend({
- name: attr('string'),
- running: attr('boolean'),
- owner: belongsTo('user', { async: true }),
- models: hasMany('simulation-model', { aync: true }),
- projects: hasMany('project', { async: true })
-});
diff --git a/app/models/simulator-status.js b/app/models/simulator-status.js
deleted file mode 100644
index ca6bd1b..0000000
--- a/app/models/simulator-status.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import DS from 'ember-data';
-
-export default DS.Model.extend({
-
-});
diff --git a/app/models/simulator.js b/app/models/simulator.js
deleted file mode 100644
index 5e45673..0000000
--- a/app/models/simulator.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * File: simulator.js
- * Author: Markus Grigull
- * Date: 28.09.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import DS from 'ember-data';
-import attr from 'ember-data/attr';
-
-export default DS.Model.extend({
- name: attr('string'),
- running: attr('boolean'),
- simulatorid: attr('number'),
- endpoint: attr('string')
-});
diff --git a/app/models/user.js b/app/models/user.js
deleted file mode 100644
index b2bf6d4..0000000
--- a/app/models/user.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * File: user.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Model from 'ember-data/model';
-import attr from 'ember-data/attr';
-import { hasMany } from 'ember-data/relationships';
-
-export default Model.extend({
- username: attr('string'),
- password: attr('string'),
- adminLevel: attr('number'),
- projects: hasMany('project', { async: true }),
- simulations: hasMany('simulation', { async: true }),
- mail: attr('string'),
- files: hasMany('file', { async: true })
-});
diff --git a/app/models/visualization.js b/app/models/visualization.js
deleted file mode 100644
index 439d526..0000000
--- a/app/models/visualization.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * File: visualization.js
- * Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Model from 'ember-data/model';
-import attr from 'ember-data/attr';
-import { belongsTo, hasMany } from 'ember-data/relationships';
-
-export default Model.extend({
- name: attr('string'),
- widgets: hasMany('widget', { async: true }),
- project: belongsTo('project', { async: true })
-});
diff --git a/app/models/widget.js b/app/models/widget.js
deleted file mode 100644
index 32846f6..0000000
--- a/app/models/widget.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * File: widget.js
- * Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Model from 'ember-data/model';
-import attr from 'ember-data/attr';
-import { belongsTo } from 'ember-data/relationships';
-
-export default Model.extend({
- name: attr('string'),
- widgetData: attr(),
- width: attr('number', { defaultValue: 100 }),
- height: attr('number', { defaultValue: 100 }),
- type: attr('string'),
- x: attr('number', { defaultValue: 0 }),
- y: attr('number', { defaultValue: 0 }),
- visualization: belongsTo('Visualization', { async: true })
-});
diff --git a/app/resolver.js b/app/resolver.js
deleted file mode 100644
index 2fb563d..0000000
--- a/app/resolver.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import Resolver from 'ember-resolver';
-
-export default Resolver;
diff --git a/app/router.js b/app/router.js
deleted file mode 100644
index 8fbc33a..0000000
--- a/app/router.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * File: router.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import config from './config/environment';
-
-const Router = Ember.Router.extend({
- location: config.locationType,
- rootURL: config.rootURL
-});
-
-Router.map(function() {
- this.route('login');
- this.route('logout');
-
- this.route('projects');
- this.route('project', function() {
- this.route('index', { path: '/:projectid' });
- });
-
- this.route('me');
-
- this.route('visualization', function() {
- this.route('index', { path: '/:visualizationid' });
- this.route('edit', { path: '/edit/:visualizationid' });
- });
-
- this.route('user', function() {
- this.route('edit', { path: '/edit/:userid' });
- this.route('new');
- this.route('delete', { path: '/delete/:userid' });
- });
-
- this.route('404', { path: '/*path' });
-
- this.route('simulation-model', function() {
- this.route('index', { path: '/:modelid' });
- });
-
- this.route('simulations');
- this.route('simulation', function() {
- this.route('index', { path: '/:simulationid' });
- });
-
- this.route('simulators');
- this.route('simulator');
-});
-
-export default Router;
diff --git a/app/routes/.gitkeep b/app/routes/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/app/routes/application.js b/app/routes/application.js
deleted file mode 100644
index e68dd55..0000000
--- a/app/routes/application.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * File: application.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
-
-const { service } = Ember.inject;
-
-export default Ember.Route.extend(ApplicationRouteMixin, {
- sessionUser: service('session-user'),
-
- beforeModel() {
- return this._loadCurrentUser();
- },
-
- sessionAuthenticated() {
- this._loadCurrentUser().then(() => {
- this.transitionTo('/');
- }).catch(function(/* reason */) {
- //console.log(reason);
- this.get('session').invalidate();
- });
- },
-
- _loadCurrentUser() {
- return this.get('sessionUser').loadCurrentUser();
- }
-});
diff --git a/app/routes/dialog/plot/value.js b/app/routes/dialog/plot/value.js
deleted file mode 100644
index 26d9f31..0000000
--- a/app/routes/dialog/plot/value.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import Ember from 'ember';
-
-export default Ember.Route.extend({
-});
diff --git a/app/routes/index.js b/app/routes/index.js
deleted file mode 100644
index ca13931..0000000
--- a/app/routes/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * File: index.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-import LiveDataMixin from '../mixins/live-data';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, LiveDataMixin, {
-});
diff --git a/app/routes/login.js b/app/routes/login.js
deleted file mode 100644
index 21647e9..0000000
--- a/app/routes/login.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * File: login.js
- * Author: Markus Grigull
- * Date: 25.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import UnauthenticatedRouteMixin from 'ember-simple-auth/mixins/unauthenticated-route-mixin';
-
-export default Ember.Route.extend(UnauthenticatedRouteMixin, {
-});
diff --git a/app/routes/logout.js b/app/routes/logout.js
deleted file mode 100644
index 2f18620..0000000
--- a/app/routes/logout.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: logout.js
- * Author: Markus Grigull
- * Date: 05.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- beforeModel() {
- this.get('session').invalidate();
- }
-});
diff --git a/app/routes/me.js b/app/routes/me.js
deleted file mode 100644
index d9e456c..0000000
--- a/app/routes/me.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * File: me.js
- * Author: Markus Grigull
- * Date: 27.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model() {
- // get session user
- return this.store.findRecord('user', 'me');
- }
-});
diff --git a/app/routes/project/index.js b/app/routes/project/index.js
deleted file mode 100644
index 10bd7ed..0000000
--- a/app/routes/project/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: index.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return this.store.findRecord('project', params.projectid);
- }
-});
diff --git a/app/routes/projects.js b/app/routes/projects.js
deleted file mode 100644
index 9c31feb..0000000
--- a/app/routes/projects.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * File: project.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- sessionUser: Ember.inject.service('session-user'),
-
- model() {
- // get projects for current user, simulations are needed for the simulation picker
- var user = this.get('sessionUser.user');
-
- return Ember.RSVP.hash({
- projects: user.get('projects'),
- simulations: this.store.findAll('simulation')
- });
- }
-});
diff --git a/app/routes/simulation-model/index.js b/app/routes/simulation-model/index.js
deleted file mode 100644
index d520ee0..0000000
--- a/app/routes/simulation-model/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: index.js
- * Author: Markus Grigull
- * Date: 20.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return this.store.findRecord('simulation-model', params.modelid);
- }
-});
diff --git a/app/routes/simulation/index.js b/app/routes/simulation/index.js
deleted file mode 100644
index 567b7e3..0000000
--- a/app/routes/simulation/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * File: index.js
- * Author: Markus Grigull
- * Date: 26.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return Ember.RSVP.hash({
- simulation: this.store.findRecord('simulation', params.simulationid),
- simulators: this.store.findAll('simulator')
- });
- }
-});
diff --git a/app/routes/simulations.js b/app/routes/simulations.js
deleted file mode 100644
index ce9f752..0000000
--- a/app/routes/simulations.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * File: simulations.js
- * Author: Markus Grigull
- * Date: 26.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- sessionUser: Ember.inject.service('session-user'),
-
- model() {
- // get simulations for current user
- var user = this.get('sessionUser.user');
- return user.get('simulations');
- }
-});
diff --git a/app/routes/simulators.js b/app/routes/simulators.js
deleted file mode 100644
index 8c32bcc..0000000
--- a/app/routes/simulators.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * File: simulators.js
- * Author: Markus Grigull
- * Date: 28.09.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model() {
- // get simulators
- return this.store.findAll('simulator');
- }
-});
diff --git a/app/routes/user/delete.js b/app/routes/user/delete.js
deleted file mode 100644
index 8ac9611..0000000
--- a/app/routes/user/delete.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: delete.js
- * Author: Markus Grigull
- * Date: 11.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return this.store.findRecord('user', params.userid);
- }
-});
diff --git a/app/routes/user/edit.js b/app/routes/user/edit.js
deleted file mode 100644
index 3918d6d..0000000
--- a/app/routes/user/edit.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: edit.js
- * Author: Markus Grigull
- * Date: 11.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return this.store.findRecord('user', params.userid);
- }
-});
diff --git a/app/routes/user/index.js b/app/routes/user/index.js
deleted file mode 100644
index 7d89a0c..0000000
--- a/app/routes/user/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: index.js
- * Author: Markus Grigull
- * Date: 11.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model() {
- return this.store.findAll('user');
- }
-});
diff --git a/app/routes/user/new.js b/app/routes/user/new.js
deleted file mode 100644
index 38c73e5..0000000
--- a/app/routes/user/new.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * File: new.js
- * Author: Markus Grigull
- * Date: 11.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
-});
diff --git a/app/routes/visualization/edit.js b/app/routes/visualization/edit.js
deleted file mode 100644
index e665763..0000000
--- a/app/routes/visualization/edit.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: edit.js
- * Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return this.store.findRecord('visualization', params.visualizationid);
- }
-});
diff --git a/app/routes/visualization/index.js b/app/routes/visualization/index.js
deleted file mode 100644
index 35a7beb..0000000
--- a/app/routes/visualization/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: index.js
- * Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
-
-export default Ember.Route.extend(AuthenticatedRouteMixin, {
- model(params) {
- return this.store.findRecord('visualization', params.visualizationid);
- }
-});
diff --git a/app/serializers/application.js b/app/serializers/application.js
deleted file mode 100644
index 913c92f..0000000
--- a/app/serializers/application.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * File: application.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import RESTSerializer from 'ember-data/serializers/rest';
-import DS from 'ember-data';
-
-export default RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
- primaryKey: '_id'
-});
diff --git a/app/serializers/project.js b/app/serializers/project.js
deleted file mode 100644
index f0bd705..0000000
--- a/app/serializers/project.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: project.js
- * Author: Markus Grigull
- * Date: 04.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import ApplicationSerializer from './application';
-
-export default ApplicationSerializer.extend({
- attrs: {
- owner: { serialize: 'ids' },
- visualizations: { serialize: 'ids' }
- }
-});
diff --git a/app/serializers/simulation-model.js b/app/serializers/simulation-model.js
deleted file mode 100644
index cb91820..0000000
--- a/app/serializers/simulation-model.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * File: simulation-model.js
- * Author: Markus Grigull
- * Date: 20.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import ApplicationSerializer from './application';
-
-export default ApplicationSerializer.extend({
- attrs: {
- simulation: { serialize: 'ids' }
- }
-});
diff --git a/app/serializers/simulation.js b/app/serializers/simulation.js
deleted file mode 100644
index 6fe4c66..0000000
--- a/app/serializers/simulation.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * File: simulation.js
- * Author: Markus Grigull
- * Date: 26.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import ApplicationSerializer from './application';
-
-export default ApplicationSerializer.extend({
- attrs: {
- owner: { serialize: 'ids' },
- models: { serialize: 'ids' },
- projects: { serialize: 'ids' }
- }
-});
diff --git a/app/serializers/user.js b/app/serializers/user.js
deleted file mode 100644
index 677cee0..0000000
--- a/app/serializers/user.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * File: user.js
- * Author: Markus Grigull
- * Date: 27.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import ApplicationSerializer from './application';
-
-export default ApplicationSerializer.extend({
- attrs: {
- projects: { serialize: 'ids' }
- }
-});
diff --git a/app/serializers/visualization.js b/app/serializers/visualization.js
deleted file mode 100644
index 950c341..0000000
--- a/app/serializers/visualization.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * File: visualization.js
- * Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import ApplicationSerializer from './application';
-
-export default ApplicationSerializer.extend({
- attrs: {
- project: { serialize: 'ids' },
- widgets: { serialize: 'ids' }
- }
-});
diff --git a/app/services/session-user.js b/app/services/session-user.js
deleted file mode 100644
index 06b94b9..0000000
--- a/app/services/session-user.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * File: session-user.js
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import Ember from 'ember';
-
-const {
- inject: { service },
- RSVP
-} = Ember;
-
-export default Ember.Service.extend({
- session: service('session'),
- store: service(),
-
- loadCurrentUser() {
- var _this = this;
-
- return new RSVP.Promise((resolve, reject) => {
- const token = this.get('session.data.authenticated.token');
- if (!Ember.isEmpty(token)) {
- return this.get('store').queryRecord('user', 'me').then(function(user) {
- _this.set('user', user);
- resolve();
- }, function() {
- _this.get('session').invalidate();
- reject();
- });
- } else {
- resolve();
- }
- });
- }
-});
diff --git a/app/styles/app.scss b/app/styles/app.scss
deleted file mode 100644
index e1309ef..0000000
--- a/app/styles/app.scss
+++ /dev/null
@@ -1,277 +0,0 @@
-/**
- * File: app.css
- * Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-@import 'widgets';
-@import 'models';
-@import 'simulations';
-@import 'projects';
-@import 'simulators';
-@import 'simulation-models';
-
-@import "ember-modal-dialog/ember-modal-structure";
-@import "ember-modal-dialog/ember-modal-appearance";
-
-* {
- margin: 0;
- padding: 0;
-}
-
-/**
- * Application skeleton
- */
-.ember-application {
- min-width: 800px;
-
- background: #ddd;
- color: #4d4d4d;
-
- font: 16px 'Helvetica Neue', Helvetica, Arial, sans-serif;
- font-weight: 300;
- font-smoothing: antialiased;
- -webkit-font-smoothing: antialiased;
- -moz-font-smoothing: antialiased;
-}
-
-header {
- width: 100%;
- height: 50px;
-
- padding: 10px 0 0 0;
-
- color: #fff;
- background-color: #151;
-}
-
-header h1 {
- width: 100%;
-
- text-align: center
-}
-
-footer {
- width: 100%;
-
- color: #666;
-
- margin-top: 20px;
-
- text-align: center;
-
- clear: both;
-}
-
-/**
- * Main layout
- */
-#main-menu {
- float: left;
-
- width: 125px;
-
- background-color: #fff;
- box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
- 0 9px 18px 0 rgba(0, 0, 0, 0.1);
-
- margin: 20px 0 0 20px;
- padding: 20px 20px 20px 30px;
-}
-
-#wrapper {
- min-height: 100px;
-
- background-color: #fff;
- box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
- 0 9px 18px 0 rgba(0, 0, 0, 0.1);
-
- margin: 20px 20px 20px 220px;
- padding: 20px;
-}
-
-/**
- * Login layout
- */
-#login-container {
- width: 320px;
- height: 180px;
-
- background-color: #fff;
- box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
- 0 9px 18px 0 rgba(0, 0, 0, 0.1);
-
- margin: 80px auto;
- padding: 0px;
-}
-
-#login-container h1 {
- background-color: #cdcdcd;
-
- text-align: center;
-
- font-size: 24;
-
- padding: 10px 0;
-}
-
-#login {
-
-}
-
-#login-form {
- padding: 20px 20px;
-}
-
-/**
- * Visualization
- */
-.draggableDropzone {
- display: block;
-
- min-height: 400px;
-
- border: 3px dashed #aaa;
-
- &.activated {
- border-color: #2ecc71;
- }
- &.deactivated {
- border-color: #e1e1e1;
- }
-}
-
-.draggableItem[draggable=true] {
- display: inline-block;
- background: #e1e1e1;
- cursor: move;
-
- padding: 5px 10px;
-
- border: 1px solid gray;
-
- &:hover {
- background-color: #aaa;
- }
-}
-
-/**
- * Table
- */
-.column-center {
- text-align: center;
-}
-
-/**
- * Table full width
- */
-.table-full-width {
- width: 100%;
-
- border: 0;
- border-collapse: collapse;
-
- background-color: #f6f6f6;
-}
-
-.table-full-width th, td {
- padding: 5px;
-
- text-align: left;
-
- border: none;
-}
-
-.table-full-width th {
- background-color: #151;
- color: #fff;
-}
-
-.table-full-width tr:nth-child(even) {
- background-color: #ddd;
-}
-
-/**
- * Form create record
- */
-.form-create-record {
- padding: 0;
-
- width: 400px;
-}
-
-.form-create-record table {
- border: none;
-}
-
-.form-create-record td {
- padding: 5px 10px 5px 0;
-}
-
-.form-create-record input {
- padding: 2px 4px;
-
- width: 100%;
-}
-
-.form-create-record input[type=number] {
- width: 60px;
-
- padding: 0;
-}
-
-.form-create-record button {
- background-color: #151;
- color: #fff;
-
- font-size: 14px;
-
- padding: 4px 8px;
-
- border: none;
-
- cursor: pointer;
-}
-
-.form-create-record button:hover {
- background: #373;
-}
-
-button {
- background-color: #151;
- color: #fff;
-
- font-size: 14px;
-
- margin-top: 10px;
- padding: 4px 8px;
-
- border: none;
-
- cursor: pointer;
-}
-
-button:hover {
- background: #373;
-}
-
-/**
- *
- */
-.popover {
- z-index: 1010;
-
- width: 120px;
- height: 100px;
-}
-
-.arrow {
- border-right-color: red !important;
-}
-
-.hidden {
- visibility: hidden;
-}
diff --git a/app/styles/models.scss b/app/styles/models.scss
deleted file mode 100644
index e2fe0c3..0000000
--- a/app/styles/models.scss
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * File: models.css
- * Author: Markus Grigull
- * Date: 20.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-/**
- * Route: simulation-models
- */
-.simulation-models-container {
- margin-top: 20px;
-}
-
-.simulation-models-container table {
- width: 100%;
-
- border: 0;
- border-collapse: collapse;
-}
-
-.simulation-models-container th, td {
- padding: 5px;
-
- text-align: left;
-
- border: 0;
-}
-
-.simulation-models-container th {
- background-color: #151;
- color: #fff;
-}
-
-.simulation-models-row-controls {
- float: right;
-}
-
-.simulation-models-row-controls a {
- margin-left: 10px;
-}
-
-.simulation-models-container tr:nth-child(even) {
- background-color: #ddd;
-}
-
-.simulation-models-new-container {
- margin-top: 20px;
-}
diff --git a/app/styles/projects.scss b/app/styles/projects.scss
deleted file mode 100644
index 5f4e5ec..0000000
--- a/app/styles/projects.scss
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * File: projects.css
- * Author: Markus Grigull
- * Date: 26.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-/**
- * Route: projects
- */
-.projects-container {
- margin-top: 20px;
-}
-
-.projects-row-controls {
- float: right;
-}
-
-.projects-row-controls a {
- margin-left: 10px;
-}
-
-.projects-new-container {
- margin-top: 20px;
-}
-
-/**
- * Route: project.index
- */
-.project-index-container {
- margin-top: 20px;
-}
-
-.project-index-row-controls {
- float: right;
-}
-
-.project-index-row-controls a {
- margin-left: 10px;
-}
-
-.project-index-new-visualization {
- margin-top: 20px;
-}
diff --git a/app/styles/simulation-models.scss b/app/styles/simulation-models.scss
deleted file mode 100644
index 04aea01..0000000
--- a/app/styles/simulation-models.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * File: simulation-models.css
- * Author: Markus Grigull
- * Date: 12.10.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-/**
- * Route: simulation-model/index
- */
-.simulation-model-index-mapping {
- margin-top: 20px;
-}
-
-.simulation-model-index-buttons {
- margin-top: 20px;
-}
diff --git a/app/styles/simulations.scss b/app/styles/simulations.scss
deleted file mode 100644
index 0580e36..0000000
--- a/app/styles/simulations.scss
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * File: simulations.css
- * Author: Markus Grigull
- * Date: 26.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-/**
- * Route: simulations
- */
-.simulations-container {
- margin-top: 20px;
-}
-
-.simulations-row-controls {
- float: right;
-}
-
-.simulations-row-controls a {
- margin-left: 10px;
-}
-
-.simulations-new-container {
- margin-top: 20px;
-}
-
-/**
- * Route: simulation/index
- */
-.simulation-index-models-container {
- margin-top: 20px;
-}
-
-.simulation-index-row-controls {
- float: right;
-}
-
-.simulation-index-row-controls a {
- margin-left: 10px;
-}
-
-.simulation-index-new-model {
- margin-top: 20px;
-}
diff --git a/app/styles/simulators.scss b/app/styles/simulators.scss
deleted file mode 100644
index 2943dc2..0000000
--- a/app/styles/simulators.scss
+++ /dev/null
@@ -1,27 +0,0 @@
-/**
- * File: simulators.css
- * Author: Markus Grigull
- * Date: 30.09.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-/**
- * Route: simulators
- */
-.simulators-container {
- margin-top: 20px;
-}
-
-.simulators-row-controls {
- float: right;
-}
-
-.simulators-row-controls a {
- margin-left: 10px;
-}
-
-.simulators-new-container {
- margin-top: 50px;
-}
diff --git a/app/styles/widgets.scss b/app/styles/widgets.scss
deleted file mode 100644
index 3d49d68..0000000
--- a/app/styles/widgets.scss
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * File: widgets.css
- * Author: Markus Grigull
- * Date: 19.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-/**
- * Component: widget-container
- */
-.widgets {
- overflow: scroll;
-
- position: relative;
-}
-
-/**
- * Component: widget-toolbox
- */
-.widget-toolbox {
- margin: 20px 0;
-}
-
-/**
- * Component: widget-abstract
- */
-.widgetAbstract {
- position: absolute;
-}
-
-.widget-editing {
- border: 1px solid lightgray;
-
- padding: 5px 10px;
- margin: 10px;
-}
-
-/**
- * Component: widget-value
- */
-.widgetValue {
-
-}
-
-.widget-edit-container {
- width: 200px !important;
-
- background-color: #ddd;
-
- border: 1px dotted black;
-}
-
-.widget-edit-form {
-
-}
-
-/**
- * Component: widget-table
- */
-.widgetTable {
-
-}
-
-.widgetTable table {
- width: 100%;
- /*height: 100%;*/
-
- border: 1px solid gray;
- border-collapse: collapse;
-}
-
-.widgetTable td, th {
- border: 1px solid gray;
-
- padding: 2px 5px;
-}
-
-/**
- * Component: widget-plot
- */
-.widgetPlot-signal-table {
- border: 1px solid gray;
-
- padding: 2px 5px;
-}
-
-.widgetPlot-signal-table th {
- border: 0;
-}
diff --git a/app/templates/404.hbs b/app/templates/404.hbs
deleted file mode 100644
index 9a83fd7..0000000
--- a/app/templates/404.hbs
+++ /dev/null
@@ -1 +0,0 @@
-404 - Not found
diff --git a/app/templates/application.hbs b/app/templates/application.hbs
deleted file mode 100644
index 4e8c036..0000000
--- a/app/templates/application.hbs
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-{{#if session.isAuthenticated}}
-
-
Menu
-
-
- {{#link-to 'index'}}Home{{/link-to}}
- {{#link-to 'projects'}}Projects{{/link-to}}
- {{#link-to 'simulations'}}Simulations{{/link-to}}
- {{#link-to 'simulators'}}Simulators{{/link-to}}
- {{#link-to 'me'}}Account{{/link-to}}
- {{#link-to 'logout'}}Logout{{/link-to}}
-
-
-
-
-{{else}}
- {{outlet}}
-{{/if}}
-
-
diff --git a/app/templates/components/.gitkeep b/app/templates/components/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/app/templates/components/draggable-dropzone.hbs b/app/templates/components/draggable-dropzone.hbs
deleted file mode 100644
index 889d9ee..0000000
--- a/app/templates/components/draggable-dropzone.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{yield}}
diff --git a/app/templates/components/draggable-item.hbs b/app/templates/components/draggable-item.hbs
deleted file mode 100644
index 889d9ee..0000000
--- a/app/templates/components/draggable-item.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{yield}}
diff --git a/app/templates/components/file-upload.hbs b/app/templates/components/file-upload.hbs
deleted file mode 100644
index 889d9ee..0000000
--- a/app/templates/components/file-upload.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{yield}}
diff --git a/app/templates/components/flow-plot.hbs b/app/templates/components/flow-plot.hbs
deleted file mode 100644
index 889d9ee..0000000
--- a/app/templates/components/flow-plot.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{yield}}
diff --git a/app/templates/components/widget-abstract.hbs b/app/templates/components/widget-abstract.hbs
deleted file mode 100644
index 889d9ee..0000000
--- a/app/templates/components/widget-abstract.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{yield}}
diff --git a/app/templates/components/widget-chart.hbs b/app/templates/components/widget-chart.hbs
deleted file mode 100644
index 889d9ee..0000000
--- a/app/templates/components/widget-chart.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{yield}}
diff --git a/app/templates/components/widget-container.hbs b/app/templates/components/widget-container.hbs
deleted file mode 100644
index 818abe5..0000000
--- a/app/templates/components/widget-container.hbs
+++ /dev/null
@@ -1,3 +0,0 @@
-{{#each widgets as |widget|}}
- {{component widget.type widget=widget editing=editing grid=grid data=data showWidgetDialog=showWidgetDialog}}
-{{/each}}
diff --git a/app/templates/components/widget-image.hbs b/app/templates/components/widget-image.hbs
deleted file mode 100644
index b9b4f0c..0000000
--- a/app/templates/components/widget-image.hbs
+++ /dev/null
@@ -1,51 +0,0 @@
-{{#if widget.widgetData.path}}
-
-{{/if}}
-
-{{#if isShowingModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Image
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter widget name' value=name}}
-
-
-
-
- Image
-
-
-
- {{#each widget.visualization.project.owner.files as |imageFile|}}
- {{imageFile.name}}
- {{/each}}
-
-
-
-
-
-
-
- {{file-upload files=uploadFiles}} Upload
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
diff --git a/app/templates/components/widget-label.hbs b/app/templates/components/widget-label.hbs
deleted file mode 100644
index 1c0aefe..0000000
--- a/app/templates/components/widget-label.hbs
+++ /dev/null
@@ -1,27 +0,0 @@
-{{widget.name}}
-
-{{#if isShowingModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Label
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter widget name' value=name}}
-
-
-
-
- Cancel
- Save
- Delete
-
-
-
-
- {{/modal-dialog}}
-{{/if}}
diff --git a/app/templates/components/widget-plot.hbs b/app/templates/components/widget-plot.hbs
deleted file mode 100644
index 8e95dda..0000000
--- a/app/templates/components/widget-plot.hbs
+++ /dev/null
@@ -1,112 +0,0 @@
-{{widget.name}}
-
-{{#if (eq plotType "table")}}
-
-
-
- {{flow-plot data=plotData options=plotOptions}}
-
-{{/if}}
-
-{{#if (eq plotType "multiple")}}
- {{flow-plot data=plotData options=plotOptions}}
-{{/if}}
-
-{{#if isShowingModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Plot
-
- {{#if errorMessage}}
-
- Error: {{errorMessage}}
-
- {{/if}}
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter widget name' value=name}}
-
-
-
-
- Simulator
-
-
-
- {{#each widget.visualization.project.simulation.models as |simulationModel|}}
- {{simulationModel.name}}
- {{/each}}
-
-
-
-
-
- Time in sec
-
-
- {{input type='number' id='time' placeholder='Enter time length' value=time}}
-
-
-
-
- Type
-
-
-
- Multiple
- Table
-
-
-
- {{#if (eq plotType "multiple")}}
-
-
- Signals
-
-
- {{#each simulationModel.mapping as |signal|}}
- {{input type='checkbox' name=signal checked=(mut (get checkedSignals signal))}} {{signal}}
-
- {{/each}}
-
-
- {{/if}}
-
- {{#if (eq plotType "table")}}
-
- {{/if}}
-
-
- Cancel
- Save
- Delete
-
-
-
-
- {{/modal-dialog}}
-{{/if}}
diff --git a/app/templates/components/widget-table.hbs b/app/templates/components/widget-table.hbs
deleted file mode 100644
index bb84841..0000000
--- a/app/templates/components/widget-table.hbs
+++ /dev/null
@@ -1,56 +0,0 @@
-{{widget.name}}
-
-
-
-{{#if isShowingModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Table
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter widget name' value=name}}
-
-
-
-
- Simulator
-
-
-
- {{#each widget.visualization.project.simulation.models as |simulationModel|}}
- {{simulationModel.name}}
- {{/each}}
-
-
-
-
-
- Cancel
- Save
- Delete
-
-
-
-
- {{/modal-dialog}}
-{{/if}}
diff --git a/app/templates/components/widget-value.hbs b/app/templates/components/widget-value.hbs
deleted file mode 100644
index 00c246b..0000000
--- a/app/templates/components/widget-value.hbs
+++ /dev/null
@@ -1,55 +0,0 @@
-{{name}}{{#if name}}:{{/if}} {{value}}
-
-{{#if isShowingModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Value
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter widget name' value=name}}
-
-
-
-
- Simulator
-
-
-
- {{#each widget.visualization.project.simulation.models as |simulationModel|}}
- {{simulationModel.name}}
- {{/each}}
-
-
-
-
-
- Signal
-
-
-
- {{#each simulationModel.mapping as |signal|}}
- {{signal}}
- {{/each}}
-
-
-
-
-
- Cancel
- Save
- Delete
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
diff --git a/app/templates/dialog/project.hbs b/app/templates/dialog/project.hbs
deleted file mode 100644
index 5d45882..0000000
--- a/app/templates/dialog/project.hbs
+++ /dev/null
@@ -1,68 +0,0 @@
-{{#if isShowingNewModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New visualization
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter visualization name' value=name}}
-
-
-
-
- Cancel
- Create
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingEditModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Edit visualization
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter visualization name' value=name}}
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingDeleteModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Delete visualization
-
- Are you sure you want to delete the visualization {{visualization.name}} ?
-
- Cancel
- Delete
- {{/modal-dialog}}
-{{/if}}
diff --git a/app/templates/dialog/projects.hbs b/app/templates/dialog/projects.hbs
deleted file mode 100644
index 83dae43..0000000
--- a/app/templates/dialog/projects.hbs
+++ /dev/null
@@ -1,92 +0,0 @@
-{{#if isShowingNewModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New project
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter project name' value=name}}
-
-
-
-
- Simulation
-
-
-
- {{#each model.simulations as |simulation|}}
- {{simulation.name}}
- {{/each}}
-
-
-
-
-
- Cancel
- Create
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingEditModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Edit project
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter project name' value=name}}
-
-
-
-
- Simulation
-
-
-
- {{#each model.simulations as |simulation|}}
- {{simulation.name}}
- {{/each}}
-
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingDeleteModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Delete project
-
- Are you sure you want to delete the project {{project.name}} ?
-
- Cancel
- Delete
- {{/modal-dialog}}
-{{/if}}
diff --git a/app/templates/dialog/simulation.hbs b/app/templates/dialog/simulation.hbs
deleted file mode 100644
index 9e2bfb6..0000000
--- a/app/templates/dialog/simulation.hbs
+++ /dev/null
@@ -1,108 +0,0 @@
-{{#if isShowingNewModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New model
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter model name' value=name}}
-
-
-
-
- Simulator
-
-
-
- {{#each model.simulators as |simulator|}}
- {{simulator.name}}
- {{/each}}
-
-
-
-
-
- Length
-
-
- {{input id='length' type='number' value=length min='1'}}
-
-
-
-
- Cancel
- Create
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingEditModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Edit model
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter model name' value=name}}
-
-
-
-
- Simulator
-
-
-
- {{#each model.simulators as |simulator|}}
- {{simulator.name}}
- {{/each}}
-
-
-
-
-
- Length
-
-
- {{input id='length' type='number' value=length min='1'}}
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingDeleteModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Delete simulation-model
-
- Are you sure you want to delete the simulation-model {{simulationModel.name}} ?
-
- Cancel
- Delete
- {{/modal-dialog}}
-{{/if}}
diff --git a/app/templates/dialog/simulations.hbs b/app/templates/dialog/simulations.hbs
deleted file mode 100644
index 96f847d..0000000
--- a/app/templates/dialog/simulations.hbs
+++ /dev/null
@@ -1,86 +0,0 @@
-{{#if isShowingNewModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New simulation
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter simulation name' value=name}}
-
-
-
-
- Cancel
- Create
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingEditModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Edit simulator
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter simulation name' value=name}}
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingDeleteModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Delete simulation
-
- Are you sure you want to delete the simulation {{simulation.name}} ?
-
- Cancel
- Delete
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingRunningModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Simulation running
-
- {{simulation.name}}:
-
-
- running
- not running
-
-
-
-
- Cancel
- Save
- {{/modal-dialog}}
-{{/if}}
diff --git a/app/templates/dialog/simulators.hbs b/app/templates/dialog/simulators.hbs
deleted file mode 100644
index ff43682..0000000
--- a/app/templates/dialog/simulators.hbs
+++ /dev/null
@@ -1,118 +0,0 @@
-{{#if isShowingNewModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New simulator
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter simulator name' value=name}}
-
-
-
-
- Simulator ID
-
-
- {{input id='simulatorid' type='number' value=simulatorid min='1' max='255'}}
-
-
-
-
- Endpoint
-
-
- {{input id='endpoint' placeholder='Enter endpoint' value=endpoint}}
-
-
-
-
- Cancel
- Create
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingDeleteModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Delete simulator
-
- Are you sure you want to delete the simulator {{simulator.name}} ?
-
- Cancel
- Delete
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingEditModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- New simulator
-
-
-
-
-
- Name
-
-
- {{input id='name' placeholder='Enter simulator name' value=simulatorName}}
-
-
-
-
- Simulator ID
-
-
- {{input id='simulatorid' type='number' value=simulatorid min='1' max='255'}}
-
-
-
-
- Endpoint
-
-
- {{input id='endpoint' placeholder='Enter endpoint' value=simulatorEndpoint}}
-
-
-
-
- Cancel
- Save
-
-
-
-
-
- {{#if errorMessage}}
- Error: {{errorMessage}}
- {{/if}}
- {{/modal-dialog}}
-{{/if}}
-
-{{#if isShowingRunningModal}}
- {{#modal-dialog attachment="middle center" translucentOverlay=true}}
- Simulator running
-
- {{simulator.name}}:
-
-
- running
- not running
-
-
-
-
- Cancel
- Save
- {{/modal-dialog}}
-{{/if}}
diff --git a/app/templates/index.hbs b/app/templates/index.hbs
deleted file mode 100644
index 700204b..0000000
--- a/app/templates/index.hbs
+++ /dev/null
@@ -1 +0,0 @@
-Main Content
diff --git a/app/templates/login.hbs b/app/templates/login.hbs
deleted file mode 100644
index 734af5e..0000000
--- a/app/templates/login.hbs
+++ /dev/null
@@ -1,19 +0,0 @@
-
- Login
-
-
-
- Username
- {{input id='username' placeholder='Enter username' value=username}}
-
-
- Password
- {{input id='password' placeholder='Enter password' type='password' value=password}}
-
- Login
-
- {{#if errorMessage}}
- {{errorMessage}}
- {{/if}}
-
-
diff --git a/app/templates/logout.hbs b/app/templates/logout.hbs
deleted file mode 100644
index c24cd68..0000000
--- a/app/templates/logout.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{outlet}}
diff --git a/app/templates/me.hbs b/app/templates/me.hbs
deleted file mode 100644
index eeb3fb9..0000000
--- a/app/templates/me.hbs
+++ /dev/null
@@ -1,20 +0,0 @@
-Preferences
-
-
-
- Username
- {{input id='username' value=model.username readonly=true}}
-
-
- Mail
- {{input id='mail' value=model.mail placeholder='Enter e-mail'}}
-
-
- Save
-
-
-{{#if isAdmin}}
-
- {{#link-to 'user'}}Users{{/link-to}}
-
-{{/if}}
diff --git a/app/templates/project/index.hbs b/app/templates/project/index.hbs
deleted file mode 100644
index ce4c826..0000000
--- a/app/templates/project/index.hbs
+++ /dev/null
@@ -1,31 +0,0 @@
-{{#link-to 'projects'}}Back to projects{{/link-to}}
-
-{{model.name}}
-
-
-
-
- Name
-
-
- {{#each model.visualizations as |visualization|}}
-
-
- {{#link-to 'visualization.index' visualization.id}}{{visualization.name}}{{/link-to}}
-
-
-
-
-
- {{/each}}
-
-
-
-
- New visualization
-
-
-{{partial "dialog/project"}}
diff --git a/app/templates/projects.hbs b/app/templates/projects.hbs
deleted file mode 100644
index ff264cd..0000000
--- a/app/templates/projects.hbs
+++ /dev/null
@@ -1,33 +0,0 @@
-Projects
-
-
-
-
- Name
- Simulation
-
-
- {{#each model.projects as |project|}}
-
-
- {{#link-to "project.index" project.id}}{{project.name}}{{/link-to}}
-
-
- {{project.simulation.name}}
-
-
-
-
-
- {{/each}}
-
-
-
-
- New Project
-
-
-{{partial "dialog/projects"}}
diff --git a/app/templates/simulation-model/index.hbs b/app/templates/simulation-model/index.hbs
deleted file mode 100644
index 91872be..0000000
--- a/app/templates/simulation-model/index.hbs
+++ /dev/null
@@ -1,31 +0,0 @@
-{{#link-to 'simulation.index' model.simulation.id}}Back to {{model.simulation.name}}{{/link-to}}
-
-{{model.name}}
-
-
- Mapping
-
-
-
-
- Signal
- Name
-
- {{#each-in model.mapping as |signal name|}}
-
-
- {{signal}}
-
-
- {{input value=(mut (get this (concat 'name' signal)))}}
-
-
- {{/each-in}}
-
-
-
-
-
- Save
-
-
diff --git a/app/templates/simulation/index.hbs b/app/templates/simulation/index.hbs
deleted file mode 100644
index a938a9b..0000000
--- a/app/templates/simulation/index.hbs
+++ /dev/null
@@ -1,35 +0,0 @@
-{{#link-to 'simulations'}}Back to simulations{{/link-to}}
-
-{{model.simulation.name}}
-
-
-
-
- Name
- Simulator
-
-
- {{#each model.simulation.models as |simulationModel|}}
-
-
- {{#link-to "simulation-model.index" simulationModel.id}}{{simulationModel.name}}{{/link-to}}
-
-
- {{simulationModel.simulator.name}}
-
-
-
-
-
- {{/each}}
-
-
-
-
- New model
-
-
-{{partial "dialog/simulation"}}
diff --git a/app/templates/simulations.hbs b/app/templates/simulations.hbs
deleted file mode 100644
index 698d9a7..0000000
--- a/app/templates/simulations.hbs
+++ /dev/null
@@ -1,34 +0,0 @@
-Simulations
-
-
-
-
- Name
- Running
-
-
- {{#each model as |simulation|}}
-
-
- {{#link-to "simulation.index" simulation.id}}{{simulation.name}}{{/link-to}}
-
-
- {{simulation.running}}
-
-
-
-
-
- {{/each}}
-
-
-
-
- New Simulation
-
-
-{{partial "dialog/simulations"}}
diff --git a/app/templates/simulators.hbs b/app/templates/simulators.hbs
deleted file mode 100644
index d70e298..0000000
--- a/app/templates/simulators.hbs
+++ /dev/null
@@ -1,43 +0,0 @@
-Simulators
-
-
-
-
- Name
- ID
- Running
- Endpoint
-
-
-
- {{#each model as |simulator|}}
-
-
- {{simulator.name}}
-
-
- {{simulator.simulatorid}}
-
-
- {{simulator.running}}
-
-
- {{simulator.endpoint}}
-
-
-
-
-
- {{/each}}
-
-
-
-
- New Simulator
-
-
-{{partial "dialog/simulators"}}
diff --git a/app/templates/user/delete.hbs b/app/templates/user/delete.hbs
deleted file mode 100644
index b8173d5..0000000
--- a/app/templates/user/delete.hbs
+++ /dev/null
@@ -1,10 +0,0 @@
-Delete User
-
-
- Are you sure you want to delete the user "{{model.username}}"?
-
- This will also delete all projects belonging to this user!
-
-
-Cancel
-Delete
diff --git a/app/templates/user/edit.hbs b/app/templates/user/edit.hbs
deleted file mode 100644
index b44372f..0000000
--- a/app/templates/user/edit.hbs
+++ /dev/null
@@ -1,14 +0,0 @@
-Edit
-
-
-
- Username
- {{input id='username' value=model.username}}
-
-
- Mail
- {{input id='mail' value=model.mail placeholder='Enter e-mail'}}
-
-
- Save
-
diff --git a/app/templates/user/index.hbs b/app/templates/user/index.hbs
deleted file mode 100644
index 9a7c1cb..0000000
--- a/app/templates/user/index.hbs
+++ /dev/null
@@ -1,11 +0,0 @@
-Users
-
-{{#link-to 'user.new'}}New user{{/link-to}}
-
-
-
- {{#each users as |user|}}
- {{#link-to 'user.edit' user.id}}{{user.username}}{{/link-to}} {{#link-to 'user.delete' user.id}}X{{/link-to}}
- {{/each}}
-
-
diff --git a/app/templates/user/new.hbs b/app/templates/user/new.hbs
deleted file mode 100644
index 0e8598b..0000000
--- a/app/templates/user/new.hbs
+++ /dev/null
@@ -1,21 +0,0 @@
-New user
-
-
-
-
- Name
- {{input id='username' placeholder='Enter username' value=username}}
-
-
- Name
- {{input id='password' placeholder='Enter password' type='password' value=password}}
-
-
- Cancel
- Create
-
- {{#if errorMessage}}
- {{errorMessage.message}}
- {{/if}}
-
-
diff --git a/app/templates/visualization/edit.hbs b/app/templates/visualization/edit.hbs
deleted file mode 100644
index c15d593..0000000
--- a/app/templates/visualization/edit.hbs
+++ /dev/null
@@ -1,37 +0,0 @@
-{{model.name}}
-
-
-
-{{#draggable-dropzone dropped='addWidget'}}
- {{widget-container widgets=model.widgets editing=true data=data showWidgetDialog='showWidgetDialog'}}
-{{/draggable-dropzone}}
-
-
- Cancel
- Save
-
diff --git a/app/templates/visualization/index.hbs b/app/templates/visualization/index.hbs
deleted file mode 100644
index c728663..0000000
--- a/app/templates/visualization/index.hbs
+++ /dev/null
@@ -1,9 +0,0 @@
-{{#link-to 'project.index' model.project.id}}Back to {{model.project.name}}{{/link-to}}
-
-{{model.name}}
-
-{{widget-container widgets=model.widgets data=data}}
-
-
- {{#link-to "visualization.edit" model.id}}Edit layout{{/link-to}}
-
diff --git a/app/transforms/array.js b/app/transforms/array.js
deleted file mode 100644
index 7e1093f..0000000
--- a/app/transforms/array.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import Ember from 'ember';
-import Transform from 'ember-data/transform';
-
-export default Transform.extend({
- deserialize(serialized) {
- if (Ember.isArray(serialized)) {
- return serialized;
- } else {
- return [];
- }
- },
-
- serialize(deserialized) {
- if (Ember.isArray(deserialized)) {
- return deserialized;
- } else {
- return [];
- }
- }
-});
diff --git a/bower.json b/bower.json
deleted file mode 100644
index adf3c54..0000000
--- a/bower.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "name": "villasweb-frontend",
- "dependencies": {
- "jquery-ui": "1.11.4",
- "bootstrap": "~3.3.5",
- "flot": "~0.8.3"
- }
-}
diff --git a/config/environment.js b/config/environment.js
deleted file mode 100644
index 0783652..0000000
--- a/config/environment.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/* jshint node: true */
-
-module.exports = function(environment) {
- var ENV = {
- modulePrefix: 'villasweb-frontend',
- environment: environment,
- rootURL: '/',
- locationType: 'auto',
- EmberENV: {
- FEATURES: {
- // Here you can enable experimental features on an ember canary build
- // e.g. 'with-controller': true
- },
- EXTEND_PROTOTYPES: {
- // Prevent Ember Data from overriding Date.parse.
- Date: false
- }
- },
-
- APP: {
- API_HOST: 'localhost:3000'
- }
- };
-
- if (environment === 'development') {
- // ENV.APP.LOG_RESOLVER = true;
- // ENV.APP.LOG_ACTIVE_GENERATION = true;
- // ENV.APP.LOG_TRANSITIONS = true;
- // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
- // ENV.APP.LOG_VIEW_LOOKUPS = true;
- }
-
- if (environment === 'test') {
- // Testem prefers this...
- ENV.locationType = 'none';
-
- // keep test console output quieter
- ENV.APP.LOG_ACTIVE_GENERATION = false;
- ENV.APP.LOG_VIEW_LOOKUPS = false;
-
- ENV.APP.rootElement = '#ember-testing';
- }
-
- if (environment === 'production') {
-
- }
-
- return ENV;
-};
diff --git a/ember-cli-build.js b/ember-cli-build.js
deleted file mode 100644
index 3418f9e..0000000
--- a/ember-cli-build.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/*jshint node:true*/
-/* global require, module */
-var EmberApp = require('ember-cli/lib/broccoli/ember-app');
-
-module.exports = function(defaults) {
- var app = new EmberApp(defaults, {
- // Add options here
- });
-
- // Use `app.import` to add additional libraries to the generated
- // output files.
- //
- // If you need to use different assets in different
- // environments, specify an object as the first parameter. That
- // object's keys should be the environment name and the values
- // should be the asset to use in that environment.
- //
- // If the library that you are including contains AMD or ES6
- // modules that you would like to import into your application
- // please specify an object with the list of modules as keys
- // along with the exports of each module as its value.
-
- app.import('bower_components/bootstrap/dist/js/bootstrap.js');
- app.import('bower_components/flot/jquery.flot.time.js');
- app.import('bower_components/jquery-ui/jquery-ui.js');
-
- app.import('bower_components/jquery-ui/themes/smoothness/jquery-ui.css');
-
- app.import('bower_components/jquery-ui/themes/smoothness/images/ui-icons_222222_256x240.png', { destDir: 'assets/images' });
-
- return app.toTree();
-};
diff --git a/package.json b/package.json
index 1a3bcb0..e8b8119 100644
--- a/package.json
+++ b/package.json
@@ -1,53 +1,29 @@
{
"name": "villasweb-frontend",
- "version": "0.0.0",
- "description": "Small description for villasweb-frontend goes here",
- "license": "MIT",
- "author": "",
- "directories": {
- "doc": "doc",
- "test": "tests"
- },
- "repository": "",
- "scripts": {
- "build": "ember build",
- "start": "ember server",
- "test": "ember test"
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "bootstrap": "^3.3.7",
+ "classnames": "^2.2.5",
+ "es6-promise": "^4.0.5",
+ "flux": "^3.1.2",
+ "immutable": "^3.8.1",
+ "react": "^15.4.2",
+ "react-bootstrap": "^0.30.7",
+ "react-d3": "^0.4.0",
+ "react-dnd": "^2.2.4",
+ "react-dnd-html5-backend": "^2.2.4",
+ "react-dom": "^15.4.2",
+ "react-router": "^3.0.2",
+ "superagent": "^3.5.0"
},
"devDependencies": {
- "broccoli-asset-rev": "^2.4.5",
- "ember-ajax": "^2.4.1",
- "ember-cli": "2.11.0",
- "ember-cli-app-version": "^2.0.0",
- "ember-cli-babel": "^5.1.7",
- "ember-cli-dependency-checker": "^1.3.0",
- "ember-cli-flot": "0.0.3",
- "ember-cli-htmlbars": "^1.1.1",
- "ember-cli-htmlbars-inline-precompile": "^0.3.3",
- "ember-cli-inject-live-reload": "^1.4.1",
- "ember-cli-jshint": "^2.0.1",
- "ember-cli-qunit": "^3.0.1",
- "ember-cli-release": "^0.2.9",
- "ember-cli-sass": "5.5.2",
- "ember-cli-shims": "^1.0.2",
- "ember-cli-sri": "^2.1.0",
- "ember-cli-test-loader": "^1.1.0",
- "ember-cli-uglify": "^1.2.0",
- "ember-data": "^2.11.0",
- "ember-export-application-global": "^1.0.5",
- "ember-load-initializers": "^0.6.0",
- "ember-modal-dialog": "^0.9.0",
- "ember-resolver": "^2.0.3",
- "ember-simple-auth": "^1.1.0",
- "ember-source": "^2.11.0",
- "ember-tether": "0.3.1",
- "ember-truth-helpers": "1.2.0",
- "ember-uploader": "1.2.3",
- "ember-welcome-page": "^2.0.2",
- "loader.js": "^4.0.10"
+ "react-scripts": "0.9.3"
},
- "engines": {
- "node": ">= 0.12.0"
- },
- "private": true
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test --env=jsdom",
+ "eject": "react-scripts eject"
+ }
}
diff --git a/public/crossdomain.xml b/public/crossdomain.xml
deleted file mode 100644
index 0c16a7a..0000000
--- a/public/crossdomain.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..5c125de5d897c1ff5692a656485b3216123dcd89
GIT binary patch
literal 24838
zcmeI4X^>UL6@VY56)S&I{`6Nu0RscWCdj@GJHx(%?6_-;yKy1n;EEf9f}pr1CW5HA
zYt$%U#C=}?jWH&%G@BaHBxsWAoUb3}&6%Ei@4Ii_JRa1`RQ23*yU)_wJ$?H0>6gj0
z${d_I^w5kvTW3xYEc?FvyP3>p$!py@`@T`|dVepIsjbbvR}af%KKy7YuQ%SDC^zmNWPYR^7avI5P-@dKev}UZ^aDAOyci9Nn
zwR4qEz~tSvrp|#ACvWzo9`3B;`}^{t18dxaH;?xT7#hmJiKAaI;|O=$yxzXNOHGw~
z^!5pE^SW`av%t_$22LFPsM^l%=PSp!3r`>9w%s+^ZQYnnTQ*Ggd9-1~kj_o$YdW@b
ztCkJ(ZGYjusqV5L4{^)R9Gt@gzU1t|?xhE&c^q(|(R#oa*}Sj5c({A$mhrB8*Y@tc
zr)K#C{KOp-eHl35ZWJ1&zkmI>9DL%!KJE@_!=W?aH;i?ZDb0O1HPFy6
zcV0Kf)eZ0BHmz9vowF7EA{z*aue9M)iJP&Zd)qYlfJ-c^sS1qY^?>s)!!Ta@x
zr@Lz|80r)7<{QVk9Z$}5SDaVtz*Rc?oH5~Wcjoc^eA&EdJ^h@aZ-BvL{K2s_7Cvfr
zFL&(R?D&(9OxsS%z_BzI9^Ai^AOF$PUpGk~oO(=OpMc3@Zh&KH1a9>G%%0rC)t@oQ
z4d~M`hX+g^Wf8P>A&&qjq|tZe*44Laq7qVPK#QIc)s*Qj34P`NL`Q{xBI`SnR!RC?
zlGdTvC%oVZ@0BgcH>}qc!uzul@{i@sH}L0|=eZBJ9qF!HHaw?`s0(_DJj(v`(memI
z6jH}=BfGlSlRV4)ouv#h*65yRR>G
zo;I#~BVK&l&{+H=_~Nq$d%bFLh7GE5pS&>Fr{RMe>)MM19~z6F1oQo_y>vtlpEZF#
zIc82TpMc3z9;{Q)=zG5B#4+96yHCvYy8p4;C%6x`%y$2HccC9|#vGVD)**C0xX|R|
z%h)}ze!Tnrvvb@RZ!GX@2lMEq`=`08b`9$%FnN@*zJLo2wD5?MbE&LN)Z>Kty*;m=
zt{Cn0>Q3nk)`bR^{dVf!3ECg6Yz4YcskI>$XH*L8E)MsudhnkP0B>+M(XEcErHUBKi~
z1`fEP&WPhp{@Ew?cPlR(ma9iw8NbJWHqp=btCtM*FnP*@ZwwlJ&-Y|LEjgvJzUtPc
zz5CrWNBRV8d0-bpWAl<=zM1PU8lJseDxBK^QuuCj2fg{&2#*IG5ezf1B(o%lU+OZx7So4D?yi2*h
zFBkr5pG3AJs83uy!~C3mQZLp~ss7-N9oAY>t)!eC#s)CrPukK!(!G*)H?v(~JCoj#
zfvgTxMV{4?zL1neQ;ITVBAdFDf`1yG$o{g7^1sR_n{RZ7tnXio?tM%240}(z9xFY0
zlz{^-G*RET;-`7`>e0b{{`!2kM)t7Si9ZqD$~wh*hyGC>z~qs@0T&u*;h}hiKGEga
zHkJ;%7aNc^o_0(>Z{Gp069H;TwPTUnvvX0SJ+kGGZ0lFBWocl>kaa)AoiMta+x_-J-?#KHFnJ*!
zwD1V?)4s#|?O)DlMBhVv4IgZs?d>b<6%xK3<{o91H?-%8?PK!_fm#3d>{{gQ
z?*8`b{G6?bZKdO{_9IVlz{R$PcGjeL|3*|@upby()_Lf^eQ&XQe)CjsbJ3Uolrgt<
zweld3GH|fZpn(=1@PencO_a_)v6tU?WV-w8wfXLbOGae0{<*C?Ead$6v+>
z|EQKThJTmwXK!c6AOD+FgtDv7i<48{-OPce!KDVkzR+XKOcREPha(;$}iUb!*)f-Fb}Y4@r9z-_{OIg
z`xn^T#ZtEPv_T$M*Sr+=Z{q#~8$|7Y{0!*2u${D*Jj%dfOrS~FzpH*_|55J!7kl4w
z?LT!7T(!3!632pmZh?dh`n-z$_ts42pn6;c`}hx;TSYd0idsqal5&0uGV=UM{c9xQ
z1KK6&TS+a^H|6B_hPo1W3
zh+Dun!`UkP%H3}*@IE18q{7&MH2f3?T6o}Jf+xI@fh=SyUOArw`*w1_-PUlHZTHc@
z--yqIxPtI}IjPRzLIZ8cPv4P=>?A&=E~~0)>&J#V;TwAR*6}`01iu~U$@prtzW6YS
ze}E>gUX+0YuF}B+Uhw2x7a7Q+oOzMNFHTNN<)40Rzg#`pABKF18@l}5A>RL`?Ri;Z
zC8ExD$)im1@R{N7(wIog8$Yn(6%q$yd9(zKe};OnH%;mWBs7)>ls~T3Wi6!Xqw6+dpJLVS1P|
z9qV%io-nE*rYcPxiS31>U_>mbPTXxkC*!?*zefr#2vF|qr8{|4|u^7-pD|f
z&OPc->UKu)=iHgIpysp;Lsbyj}GJWoBkufOA={CRTUjr%af
zc5pUH9{pg?M5%+)oN`q9yBbBt@+3xHV)qGm8b)Cp-w7~CwEhtBUk0rbjrqM
zTb|tQ3-5-pw^cul`T+X&s?O;?V(FD!(Q9Qg@(LTCNz{0-vBM^SX5lti3|GpxFn4;Ax6pGc~t)R!Bo${lYH(*
z!F&5X*?S&}YoDCyzwv1H+XI(+rL`;RN9}iLxlfr-r&vGG8OQa@=>+a)+Ij)sd_{wu
z1Am(+3-RFr4&N8N6+hqo19S#;SA1-hG>07p3}&*j4CR+rqdV)^6n;
z_vFr!(a%-=#=kb{pYmNL@6|DWkw~%E2V2jYl*e1}c{e$fib?(O+hs}eoBLRo&9(;J}YV}0Mi;LZAe{U$(s=
zT<-IaV$Z+q-P!~3{HxN>Kbw30jXzM&I(S<6Ksx^}HvU2Vntb!etSsm0>)j}Me^+L5{2yz--)?W`Q?az
z!WLG4UNP}+#C+NKH+ZG-Q=E>IPp%LuKLx$$8NAOGr(#~P>!EA
zDYlpXDR=xM?Xv5(-qp74Cw3LzBeASHSBY`OezkbOyjP!G%WSymju_C$VBl--z
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
diff --git a/public/robots.txt b/public/robots.txt
deleted file mode 100644
index f591645..0000000
--- a/public/robots.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-# http://www.robotstxt.org
-User-agent: *
-Disallow:
diff --git a/src/App.test.js b/src/App.test.js
new file mode 100644
index 0000000..b84af98
--- /dev/null
+++ b/src/App.test.js
@@ -0,0 +1,8 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import App from './App';
+
+it('renders without crashing', () => {
+ const div = document.createElement('div');
+ ReactDOM.render( , div);
+});
diff --git a/src/api/rest-api.js b/src/api/rest-api.js
new file mode 100644
index 0000000..0b3008c
--- /dev/null
+++ b/src/api/rest-api.js
@@ -0,0 +1,46 @@
+/**
+ * File: rest-api.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import request from 'superagent/lib/client';
+import Promise from 'es6-promise';
+
+const API_URL = 'http://localhost:4000/api/v1';
+
+function makeURL(part) {
+ // TODO: Add / if missing at front of part
+ return API_URL + part;
+}
+
+class RestAPI {
+ get(url) {
+ return new Promise(function (resolve, reject) {
+ request.get(makeURL(url)).end(function (error, res) {
+ if (res.status !== 200) {
+ reject();
+ } else {
+ resolve(JSON.parse(res.text));
+ }
+ });
+ });
+ }
+
+ post(url, body) {
+ return new Promise(function (resolve, reject) {
+ request.post(makeURL(url)).send(body).end(function (error, res) {
+ if (res.status !== 200) {
+ reject();
+ } else {
+ resolve(JSON.parse(res.text));
+ }
+ });
+ });
+ }
+}
+
+export default new RestAPI();
diff --git a/app/controllers/application.js b/src/app-dispatcher.js
similarity index 59%
rename from app/controllers/application.js
rename to src/app-dispatcher.js
index 37164b4..689348d 100644
--- a/app/controllers/application.js
+++ b/src/app-dispatcher.js
@@ -1,14 +1,14 @@
/**
- * File: application.js
+ * File: app-dispatcher.js
* Author: Markus Grigull
- * Date: 26.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-import Ember from 'ember';
+import { Dispatcher } from 'flux';
-export default Ember.Controller.extend({
- session: Ember.inject.service('session')
-});
+const dispatcher: Dispatcher = new Dispatcher();
+
+export default dispatcher;
diff --git a/app/components/file-upload.js b/src/components/footer.js
similarity index 51%
rename from app/components/file-upload.js
rename to src/components/footer.js
index 12c0dd0..cc84ea7 100644
--- a/app/components/file-upload.js
+++ b/src/components/footer.js
@@ -1,18 +1,22 @@
/**
- * File: file-upload.js
+ * File: footer.js
* Author: Markus Grigull
- * Date: 05.12.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-import EmberUploader from 'ember-uploader';
+import React, { Component } from 'react';
-export default EmberUploader.FileField.extend({
- files: null,
-
- filesDidChange: function(files) {
- this.set('files', files);
+class Footer extends Component {
+ render() {
+ return (
+
+ Copyright © {new Date().getFullYear()}
+
+ );
}
-});
+}
+
+export default Footer;
diff --git a/src/components/header.js b/src/components/header.js
new file mode 100644
index 0000000..b246f9d
--- /dev/null
+++ b/src/components/header.js
@@ -0,0 +1,24 @@
+/**
+ * File: header.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+
+import '../styles/app.css';
+
+class Header extends Component {
+ render() {
+ return (
+
+ );
+ }
+}
+
+export default Header;
diff --git a/src/components/menu-sidebar.js b/src/components/menu-sidebar.js
new file mode 100644
index 0000000..c6df652
--- /dev/null
+++ b/src/components/menu-sidebar.js
@@ -0,0 +1,30 @@
+/**
+ * File: menu-sidebar.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Link } from 'react-router';
+
+class SidebarMenu extends Component {
+ render() {
+ return (
+
+
Menu
+
+
+ Home
+ Projects
+ Simulations
+ Simulators
+
+
+ );
+ }
+}
+
+export default SidebarMenu;
diff --git a/src/components/table.js b/src/components/table.js
new file mode 100644
index 0000000..fab3bfe
--- /dev/null
+++ b/src/components/table.js
@@ -0,0 +1,53 @@
+/**
+ * File: table.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+
+class Table extends Component {
+ render() {
+ // create sorted rows
+ var rows = this.props.data.map(row => {
+ // add cells by column keys
+ var rowArray = [];
+
+ for (var i = 0; i < this.props.columns.length; i++) {
+ if (row[this.props.columns[i].key] != null) {
+ rowArray.push(row[this.props.columns[i].key].toString());
+ } else {
+ rowArray.push("");
+ }
+ }
+
+ return rowArray;
+ });
+
+ return (
+
+
+
+ {this.props.columns.map(column => (
+ {column.title}
+ ))}
+
+
+
+ {rows.map((row, index) => (
+
+ {row.map((cell, index) => (
+ {cell}
+ ))}
+
+ ))}
+
+
+ );
+ }
+}
+
+export default Table;
diff --git a/src/containers/app.js b/src/containers/app.js
new file mode 100644
index 0000000..b1b8a57
--- /dev/null
+++ b/src/containers/app.js
@@ -0,0 +1,55 @@
+/**
+ * File: app.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Container } from 'flux/utils';
+
+// import AppDispatcher from '../app-dispatcher';
+import VillasStore from '../stores/villas-store';
+
+import Header from '../components/header';
+import Footer from '../components/footer';
+import SidebarMenu from '../components/menu-sidebar';
+import Home from './home';
+import '../styles/app.css';
+
+class App extends Component {
+ static getStores() {
+ return [ VillasStore ];
+ }
+
+ static calculateState() {
+ return {
+ villas: VillasStore.getState()
+ };
+ }
+
+ render() {
+ // get children
+ var children = this.props.children;
+ if (this.props.location.pathname === "/") {
+ children =
+ }
+
+ return (
+
+
+
+
+
+ {children}
+
+
+
+
+ );
+ }
+}
+
+export default Container.create(App);
diff --git a/src/containers/home.js b/src/containers/home.js
new file mode 100644
index 0000000..81ead97
--- /dev/null
+++ b/src/containers/home.js
@@ -0,0 +1,36 @@
+/**
+ * File: home.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Container } from 'flux/utils';
+
+// import AppDispatcher from '../app-dispatcher';
+import VillasStore from '../stores/villas-store';
+
+import '../styles/home.css';
+
+class Home extends Component {
+ static getStores() {
+ return [ VillasStore ];
+ }
+
+ static calculateState() {
+ return {
+ villas: VillasStore.getState()
+ };
+ }
+
+ render() {
+ return (
+ Home
+ );
+ }
+}
+
+export default Container.create(Home);
diff --git a/src/containers/projects.js b/src/containers/projects.js
new file mode 100644
index 0000000..bf87dbc
--- /dev/null
+++ b/src/containers/projects.js
@@ -0,0 +1,39 @@
+/**
+ * File: projects.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Container } from 'flux/utils';
+
+// import AppDispatcher from '../app-dispatcher';
+import VillasStore from '../stores/villas-store';
+
+import '../styles/projects.css';
+
+class Projects extends Component {
+ static getStores() {
+ return [ VillasStore ];
+ }
+
+ static calculateState() {
+ return {
+ villas: VillasStore.getState()
+ };
+ }
+
+ render() {
+ return (
+
+
Projects
+
+
+ );
+ }
+}
+
+export default Container.create(Projects);
diff --git a/src/containers/simulators.js b/src/containers/simulators.js
new file mode 100644
index 0000000..f9687da
--- /dev/null
+++ b/src/containers/simulators.js
@@ -0,0 +1,72 @@
+/**
+ * File: simulators.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Container } from 'flux/utils';
+
+import AppDispatcher from '../app-dispatcher';
+import VillasStore from '../stores/villas-store';
+import SimulatorStore from '../stores/simulator-store';
+
+import Table from '../components/table';
+import '../styles/projects.css';
+
+class Simulators extends Component {
+ static getStores() {
+ return [ VillasStore, SimulatorStore ];
+ }
+
+ static calculateState() {
+ return {
+ villas: VillasStore.getState(),
+ simulators: SimulatorStore.getState(),
+
+ onButton
+ };
+ }
+
+ componentWillMount() {
+ AppDispatcher.dispatch({
+ type: 'simulators/start-load'
+ });
+ }
+
+ render() {
+ var columns = [
+ { title: 'Name', key: 'name' },
+ { title: 'ID', key: 'simulatorid', width: 80 },
+ { title: 'Running', key: 'running', width: 80 },
+ { title: 'Endpoint', key: 'endpoint', width: 120 }
+ ];
+
+ return (
+
+
Simulators
+
+
+
+
New Simulator
+
+ );
+ }
+}
+
+function onButton() {
+ AppDispatcher.dispatch({
+ type: 'simulators/start-add',
+ simulator: {
+ name: 'Virtual',
+ running: false,
+ simulatorid: 3,
+ endpoint: '1.1.1.1:1234'
+ }
+ });
+}
+
+export default Container.create(Simulators);
diff --git a/src/data-managers/simulators-data-manager.js b/src/data-managers/simulators-data-manager.js
new file mode 100644
index 0000000..bba01a1
--- /dev/null
+++ b/src/data-managers/simulators-data-manager.js
@@ -0,0 +1,43 @@
+/**
+ * File: simulators-data-manager.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import RestAPI from '../api/rest-api';
+import AppDispatcher from '../app-dispatcher';
+
+const SimulatorsDataManager = {
+ loadSimulators() {
+ RestAPI.get('/simulators').then(response => {
+ AppDispatcher.dispatch({
+ type: 'simulators/loaded',
+ simulators: response.simulators
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: 'simulators/load-error',
+ error: error
+ });
+ });
+ });
+ },
+
+ addSimulator(simulator) {
+ RestAPI.post('/simulators', { simulator: simulator }).then(response => {
+ AppDispatcher.dispatch({
+ type: 'simulators/added',
+ simulator: response.simulator
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: 'simulators/add-error',
+ error: error
+ });
+ });
+ });
+ }
+}
+
+export default SimulatorsDataManager;
diff --git a/app/controllers/visualization/index.js b/src/index.js
similarity index 56%
rename from app/controllers/visualization/index.js
rename to src/index.js
index bf51cbe..37758bb 100644
--- a/app/controllers/visualization/index.js
+++ b/src/index.js
@@ -1,15 +1,19 @@
/**
* File: index.js
* Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-import Ember from 'ember';
-import FetchLiveDataMixin from '../../mixins/fetch-live-data';
+import React from 'react';
+import ReactDOM from 'react-dom';
-export default Ember.Controller.extend(FetchLiveDataMixin, {
+import Router from './router';
+import './styles/index.css';
-});
+ReactDOM.render(
+ ,
+ document.getElementById('root')
+);
diff --git a/src/router.js b/src/router.js
new file mode 100644
index 0000000..fca3355
--- /dev/null
+++ b/src/router.js
@@ -0,0 +1,32 @@
+/**
+ * File: router.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Router, Route, hashHistory } from 'react-router';
+
+import App from './containers/app';
+import Home from './containers/home';
+import Projects from './containers/projects';
+import Simulators from './containers/simulators';
+
+class Root extends Component {
+ render() {
+ return (
+
+
+
+
+
+
+
+ );
+ }
+}
+
+export default Root;
diff --git a/src/stores/simulator-store.js b/src/stores/simulator-store.js
new file mode 100644
index 0000000..f8ff715
--- /dev/null
+++ b/src/stores/simulator-store.js
@@ -0,0 +1,60 @@
+/**
+ * File: villas-store.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import { ReduceStore } from 'flux/utils';
+
+import AppDispatcher from '../app-dispatcher';
+import SimulatorsDataManager from '../data-managers/simulators-data-manager';
+
+class SimulatorStore extends ReduceStore {
+ constructor() {
+ super(AppDispatcher);
+ }
+
+ getInitialState() {
+ return [];
+ }
+
+ reduce(state, action) {
+ console.log(action.type);
+
+ switch (action.type) {
+ case 'simulators/start-load':
+ SimulatorsDataManager.loadSimulators();
+ return state;
+
+ case 'simulators/loaded':
+ return action.simulators;
+
+ case 'simulators/load-error':
+ // TODO: Add error message
+ return state;
+
+ case 'simulators/start-add':
+ SimulatorsDataManager.addSimulator(action.simulator);
+ return state;
+
+ case 'simulators/added':
+ // state should always be immutable, thus make new copy
+ var simulators = state.slice();
+ simulators.push(action.simulator);
+
+ return simulators;
+
+ case 'simulators/add-error':
+ // TODO: Add error message
+ return state;
+
+ default:
+ return state;
+ }
+ }
+}
+
+export default new SimulatorStore();
diff --git a/src/stores/villas-store.js b/src/stores/villas-store.js
new file mode 100644
index 0000000..3fc05bf
--- /dev/null
+++ b/src/stores/villas-store.js
@@ -0,0 +1,31 @@
+/**
+ * File: villas-store.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import { ReduceStore } from 'flux/utils';
+
+import AppDispatcher from '../app-dispatcher';
+
+class VillasStore extends ReduceStore {
+ constructor() {
+ super(AppDispatcher);
+ }
+
+ getInitialState() {
+ return {};
+ }
+
+ reduce(state, action) {
+ switch (action.type) {
+ default:
+ return state;
+ }
+ }
+}
+
+export default new VillasStore();
diff --git a/src/styles/app.css b/src/styles/app.css
new file mode 100644
index 0000000..6ee6c69
--- /dev/null
+++ b/src/styles/app.css
@@ -0,0 +1,138 @@
+/**
+ * File: app.css
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+/**
+ * Application container
+ */
+body {
+ background-color: #6EA2B0;
+}
+
+.app {
+ min-width: 800px;
+
+ color: #4d4d4d;
+
+ font: 16px 'Helvetica Neue', Helvetica, Arial, sans-serif;
+}
+
+.app header {
+ width: 100%;
+ height: 50px;
+
+ padding: 10px 0 0 0;
+
+ color: #103B7D;
+ background-color: #fff;
+}
+
+.app header h1 {
+ width: 100%;
+
+ text-align: center;
+}
+
+.app footer {
+ width: 100%;
+
+ margin-top: 20px;
+
+ text-align: center;
+
+ clear: both;
+}
+
+.app-content {
+ min-height: 200px;
+
+ margin: 20px 20px 20px 170px;
+ padding: 15px 20px;
+
+ background-color: #fff;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
+ 0 9px 18px 0 rgba(0, 0, 0, 0.1);
+}
+
+/**
+ * Menus
+ */
+.menu-sidebar {
+ float: left;
+
+ margin: 20px 0 0 20px;
+ padding: 20px 25px 20px 25px;
+
+ background-color: #fff;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
+ 0 9px 18px 0 rgba(0, 0, 0, 0.1);
+}
+
+.menu-sidebar a {
+ color: #4d4d4d;
+}
+
+.active {
+ font-weight: bold;
+}
+
+.menu-sidebar ul {
+ padding-top: 10px;
+
+ list-style: none;
+}
+
+/**
+ * Tables
+ */
+.table {
+ margin-top: 20px;
+
+ border: 0;
+ border-collapse: collapse;
+
+ background-color: #f6f6f6;
+}
+
+.table th, td {
+ padding: 5px;
+
+ text-align: left;
+
+ border: none;
+}
+
+.table th {
+ background-color: #527984;
+ color: #fff;
+}
+
+.table tr:nth-child(even) {
+ background-color: #ddd;
+}
+
+/**
+ * Buttons
+ */
+button {
+ margin-top: 10px;
+ padding: 4px 8px;
+
+ border: none;
+
+ background-color: #527984;
+ color: #fff;
+
+ font-size: 14px;
+
+ cursor: pointer;
+}
+
+button:hover {
+ background: #6EA2B0;
+}
diff --git a/app/routes/404.js b/src/styles/home.css
similarity index 66%
rename from app/routes/404.js
rename to src/styles/home.css
index b93ac29..5a74ef5 100644
--- a/app/routes/404.js
+++ b/src/styles/home.css
@@ -1,13 +1,8 @@
/**
- * File: 404.js
+ * File: home.css
* Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Route.extend({
-});
diff --git a/src/styles/index.css b/src/styles/index.css
new file mode 100644
index 0000000..830576d
--- /dev/null
+++ b/src/styles/index.css
@@ -0,0 +1,4 @@
+* {
+ margin: 0;
+ padding: 0;
+}
diff --git a/app/controllers/dialog/widget/value.js b/src/styles/projects.css
similarity index 65%
rename from app/controllers/dialog/widget/value.js
rename to src/styles/projects.css
index 427431e..304b952 100644
--- a/app/controllers/dialog/widget/value.js
+++ b/src/styles/projects.css
@@ -1,13 +1,8 @@
/**
- * File: value.js
+ * File: projects.css
* Author: Markus Grigull
- * Date: 12.07.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Controller.extend({
-});
diff --git a/app/components/widget-chart.js b/src/styles/simulators.css
similarity index 64%
rename from app/components/widget-chart.js
rename to src/styles/simulators.css
index 0e61a7e..8cc54ed 100644
--- a/app/components/widget-chart.js
+++ b/src/styles/simulators.css
@@ -1,13 +1,8 @@
/**
- * File: widget-chart.js
+ * File: simulators.css
* Author: Markus Grigull
- * Date: 28.06.2016
- * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-
-import Ember from 'ember';
-
-export default Ember.Component.extend({
-});
diff --git a/testem.js b/testem.js
deleted file mode 100644
index 26044b2..0000000
--- a/testem.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/*jshint node:true*/
-module.exports = {
- "framework": "qunit",
- "test_page": "tests/index.html?hidepassed",
- "disable_watching": true,
- "launch_in_ci": [
- "PhantomJS"
- ],
- "launch_in_dev": [
- "PhantomJS",
- "Chrome"
- ]
-};
diff --git a/tests/.jshintrc b/tests/.jshintrc
deleted file mode 100644
index d2bd113..0000000
--- a/tests/.jshintrc
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "predef": [
- "document",
- "window",
- "location",
- "setTimeout",
- "$",
- "-Promise",
- "define",
- "console",
- "visit",
- "exists",
- "fillIn",
- "click",
- "keyEvent",
- "triggerEvent",
- "find",
- "findWithAssert",
- "wait",
- "DS",
- "andThen",
- "currentURL",
- "currentPath",
- "currentRouteName"
- ],
- "node": false,
- "browser": false,
- "boss": true,
- "curly": true,
- "debug": false,
- "devel": false,
- "eqeqeq": true,
- "evil": true,
- "forin": false,
- "immed": false,
- "laxbreak": false,
- "newcap": true,
- "noarg": true,
- "noempty": false,
- "nonew": false,
- "nomen": false,
- "onevar": false,
- "plusplus": false,
- "regexp": false,
- "undef": true,
- "sub": true,
- "strict": false,
- "white": false,
- "eqnull": true,
- "esversion": 6,
- "unused": true
-}
diff --git a/tests/helpers/destroy-app.js b/tests/helpers/destroy-app.js
deleted file mode 100644
index c3d4d1a..0000000
--- a/tests/helpers/destroy-app.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import Ember from 'ember';
-
-export default function destroyApp(application) {
- Ember.run(application, 'destroy');
-}
diff --git a/tests/helpers/module-for-acceptance.js b/tests/helpers/module-for-acceptance.js
deleted file mode 100644
index 76996fd..0000000
--- a/tests/helpers/module-for-acceptance.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { module } from 'qunit';
-import Ember from 'ember';
-import startApp from '../helpers/start-app';
-import destroyApp from '../helpers/destroy-app';
-
-const { RSVP: { Promise } } = Ember;
-
-export default function(name, options = {}) {
- module(name, {
- beforeEach() {
- this.application = startApp();
-
- if (options.beforeEach) {
- return options.beforeEach.apply(this, arguments);
- }
- },
-
- afterEach() {
- let afterEach = options.afterEach && options.afterEach.apply(this, arguments);
- return Promise.resolve(afterEach).then(() => destroyApp(this.application));
- }
- });
-}
diff --git a/tests/helpers/resolver.js b/tests/helpers/resolver.js
deleted file mode 100644
index b208d38..0000000
--- a/tests/helpers/resolver.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import Resolver from '../../resolver';
-import config from '../../config/environment';
-
-const resolver = Resolver.create();
-
-resolver.namespace = {
- modulePrefix: config.modulePrefix,
- podModulePrefix: config.podModulePrefix
-};
-
-export default resolver;
diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js
deleted file mode 100644
index e098f1d..0000000
--- a/tests/helpers/start-app.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import Ember from 'ember';
-import Application from '../../app';
-import config from '../../config/environment';
-
-export default function startApp(attrs) {
- let application;
-
- let attributes = Ember.merge({}, config.APP);
- attributes = Ember.merge(attributes, attrs); // use defaults, but you can override;
-
- Ember.run(() => {
- application = Application.create(attributes);
- application.setupForTesting();
- application.injectTestHelpers();
- });
-
- return application;
-}
diff --git a/tests/index.html b/tests/index.html
deleted file mode 100644
index 4def306..0000000
--- a/tests/index.html
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
- VillaswebFrontend Tests
-
-
-
- {{content-for "head"}}
- {{content-for "test-head"}}
-
-
-
-
-
- {{content-for "head-footer"}}
- {{content-for "test-head-footer"}}
-
-
- {{content-for "body"}}
- {{content-for "test-body"}}
-
-
-
-
-
-
-
- {{content-for "body-footer"}}
- {{content-for "test-body-footer"}}
-
-
diff --git a/tests/integration/.gitkeep b/tests/integration/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/integration/components/draggable-dropzone-test.js b/tests/integration/components/draggable-dropzone-test.js
deleted file mode 100644
index 68c8c69..0000000
--- a/tests/integration/components/draggable-dropzone-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('draggable-dropzone', 'Integration | Component | draggable dropzone', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{draggable-dropzone}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#draggable-dropzone}}
- template block text
- {{/draggable-dropzone}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/draggable-item-test.js b/tests/integration/components/draggable-item-test.js
deleted file mode 100644
index 93830ba..0000000
--- a/tests/integration/components/draggable-item-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('draggable-item', 'Integration | Component | draggable item', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{draggable-item}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#draggable-item}}
- template block text
- {{/draggable-item}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/file-upload-test.js b/tests/integration/components/file-upload-test.js
deleted file mode 100644
index 3c7b795..0000000
--- a/tests/integration/components/file-upload-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('file-upload', 'Integration | Component | file upload', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{file-upload}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#file-upload}}
- template block text
- {{/file-upload}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/flow-plot-test.js b/tests/integration/components/flow-plot-test.js
deleted file mode 100644
index 949b9a7..0000000
--- a/tests/integration/components/flow-plot-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('flow-plot', 'Integration | Component | flow plot', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{flow-plot}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#flow-plot}}
- template block text
- {{/flow-plot}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/plot-abstract-test.js b/tests/integration/components/plot-abstract-test.js
deleted file mode 100644
index 392a7fb..0000000
--- a/tests/integration/components/plot-abstract-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('plot-abstract', 'Integration | Component | plot abstract', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{plot-abstract}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#plot-abstract}}
- template block text
- {{/plot-abstract}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/plot-chart-test.js b/tests/integration/components/plot-chart-test.js
deleted file mode 100644
index 17234e4..0000000
--- a/tests/integration/components/plot-chart-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('plot-chart', 'Integration | Component | plot chart', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{plot-chart}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#plot-chart}}
- template block text
- {{/plot-chart}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/plot-container-test.js b/tests/integration/components/plot-container-test.js
deleted file mode 100644
index a929846..0000000
--- a/tests/integration/components/plot-container-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('plot-container', 'Integration | Component | plot container', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{plot-container}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#plot-container}}
- template block text
- {{/plot-container}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/plot-table-test.js b/tests/integration/components/plot-table-test.js
deleted file mode 100644
index 927514e..0000000
--- a/tests/integration/components/plot-table-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('plot-table', 'Integration | Component | plot table', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{plot-table}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#plot-table}}
- template block text
- {{/plot-table}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/plot-value-test.js b/tests/integration/components/plot-value-test.js
deleted file mode 100644
index 5a65558..0000000
--- a/tests/integration/components/plot-value-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('plot-value', 'Integration | Component | plot value', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{plot-value}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#plot-value}}
- template block text
- {{/plot-value}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/widget-image-test.js b/tests/integration/components/widget-image-test.js
deleted file mode 100644
index 8eace27..0000000
--- a/tests/integration/components/widget-image-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('widget-image', 'Integration | Component | widget image', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{widget-image}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#widget-image}}
- template block text
- {{/widget-image}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/widget-label-test.js b/tests/integration/components/widget-label-test.js
deleted file mode 100644
index 7312395..0000000
--- a/tests/integration/components/widget-label-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('widget-label', 'Integration | Component | widget label', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{widget-label}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#widget-label}}
- template block text
- {{/widget-label}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/integration/components/widget-plot-test.js b/tests/integration/components/widget-plot-test.js
deleted file mode 100644
index 1b38f7a..0000000
--- a/tests/integration/components/widget-plot-test.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { moduleForComponent, test } from 'ember-qunit';
-import hbs from 'htmlbars-inline-precompile';
-
-moduleForComponent('widget-plot', 'Integration | Component | widget plot', {
- integration: true
-});
-
-test('it renders', function(assert) {
- // Set any properties with this.set('myProperty', 'value');
- // Handle any actions with this.on('myAction', function(val) { ... });
-
- this.render(hbs`{{widget-plot}}`);
-
- assert.equal(this.$().text().trim(), '');
-
- // Template block usage:
- this.render(hbs`
- {{#widget-plot}}
- template block text
- {{/widget-plot}}
- `);
-
- assert.equal(this.$().text().trim(), 'template block text');
-});
diff --git a/tests/test-helper.js b/tests/test-helper.js
deleted file mode 100644
index e6cfb70..0000000
--- a/tests/test-helper.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import resolver from './helpers/resolver';
-import {
- setResolver
-} from 'ember-qunit';
-
-setResolver(resolver);
diff --git a/tests/unit/.gitkeep b/tests/unit/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/unit/adapters/application-test.js b/tests/unit/adapters/application-test.js
deleted file mode 100644
index f0a2101..0000000
--- a/tests/unit/adapters/application-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('adapter:application', 'Unit | Adapter | application', {
- // Specify the other units that are required for this test.
- // needs: ['serializer:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let adapter = this.subject();
- assert.ok(adapter);
-});
diff --git a/tests/unit/controllers/application-test.js b/tests/unit/controllers/application-test.js
deleted file mode 100644
index b71b4a5..0000000
--- a/tests/unit/controllers/application-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:application', 'Unit | Controller | application', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/dialog/plot/value-test.js b/tests/unit/controllers/dialog/plot/value-test.js
deleted file mode 100644
index 7b1555b..0000000
--- a/tests/unit/controllers/dialog/plot/value-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:dialog/plot/value', 'Unit | Controller | dialog/plot/value', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/login-test.js b/tests/unit/controllers/login-test.js
deleted file mode 100644
index b68f797..0000000
--- a/tests/unit/controllers/login-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:login', 'Unit | Controller | login', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/project/index-test.js b/tests/unit/controllers/project/index-test.js
deleted file mode 100644
index b72dc07..0000000
--- a/tests/unit/controllers/project/index-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:project/index', 'Unit | Controller | project/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/projects-test.js b/tests/unit/controllers/projects-test.js
deleted file mode 100644
index 174083b..0000000
--- a/tests/unit/controllers/projects-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:projects', 'Unit | Controller | projects', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/projects/new-test.js b/tests/unit/controllers/projects/new-test.js
deleted file mode 100644
index 1a5e3ea..0000000
--- a/tests/unit/controllers/projects/new-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:projects/new', 'Unit | Controller | projects/new', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/simulation-model/index-test.js b/tests/unit/controllers/simulation-model/index-test.js
deleted file mode 100644
index 023e3c5..0000000
--- a/tests/unit/controllers/simulation-model/index-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:simulation-model/index', 'Unit | Controller | simulation-model/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/simulation/index-test.js b/tests/unit/controllers/simulation/index-test.js
deleted file mode 100644
index c060398..0000000
--- a/tests/unit/controllers/simulation/index-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:simulation/index', 'Unit | Controller | simulation/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/simulations-test.js b/tests/unit/controllers/simulations-test.js
deleted file mode 100644
index 9b64642..0000000
--- a/tests/unit/controllers/simulations-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:simulations', 'Unit | Controller | simulations', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/simulators-test.js b/tests/unit/controllers/simulators-test.js
deleted file mode 100644
index 285361d..0000000
--- a/tests/unit/controllers/simulators-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:simulators', 'Unit | Controller | simulators', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/user/edit-test.js b/tests/unit/controllers/user/edit-test.js
deleted file mode 100644
index f06d390..0000000
--- a/tests/unit/controllers/user/edit-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:user/edit', 'Unit | Controller | user/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/users/delete-test.js b/tests/unit/controllers/users/delete-test.js
deleted file mode 100644
index 68f802f..0000000
--- a/tests/unit/controllers/users/delete-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:users/delete', 'Unit | Controller | users/delete', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/users/edit-test.js b/tests/unit/controllers/users/edit-test.js
deleted file mode 100644
index debcf46..0000000
--- a/tests/unit/controllers/users/edit-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:users/edit', 'Unit | Controller | users/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/users/index-test.js b/tests/unit/controllers/users/index-test.js
deleted file mode 100644
index 2395bc6..0000000
--- a/tests/unit/controllers/users/index-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:users/index', 'Unit | Controller | users/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/users/new-test.js b/tests/unit/controllers/users/new-test.js
deleted file mode 100644
index 113f11e..0000000
--- a/tests/unit/controllers/users/new-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:users/new', 'Unit | Controller | users/new', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/visualization/edit-test.js b/tests/unit/controllers/visualization/edit-test.js
deleted file mode 100644
index e0a5451..0000000
--- a/tests/unit/controllers/visualization/edit-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:visualization/edit', 'Unit | Controller | visualization/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/controllers/visualization/index-test.js b/tests/unit/controllers/visualization/index-test.js
deleted file mode 100644
index d2ee03f..0000000
--- a/tests/unit/controllers/visualization/index-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('controller:visualization/index', 'Unit | Controller | visualization/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let controller = this.subject();
- assert.ok(controller);
-});
diff --git a/tests/unit/mixins/draggable-test.js b/tests/unit/mixins/draggable-test.js
deleted file mode 100644
index e13c254..0000000
--- a/tests/unit/mixins/draggable-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Ember from 'ember';
-import DraggableMixin from 'villasweb-frontend/mixins/draggable';
-import { module, test } from 'qunit';
-
-module('Unit | Mixin | draggable');
-
-// Replace this with your real tests.
-test('it works', function(assert) {
- let DraggableObject = Ember.Object.extend(DraggableMixin);
- let subject = DraggableObject.create();
- assert.ok(subject);
-});
diff --git a/tests/unit/mixins/droppable-test.js b/tests/unit/mixins/droppable-test.js
deleted file mode 100644
index 41976f3..0000000
--- a/tests/unit/mixins/droppable-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Ember from 'ember';
-import DroppableMixin from 'villasweb-frontend/mixins/droppable';
-import { module, test } from 'qunit';
-
-module('Unit | Mixin | droppable');
-
-// Replace this with your real tests.
-test('it works', function(assert) {
- let DroppableObject = Ember.Object.extend(DroppableMixin);
- let subject = DroppableObject.create();
- assert.ok(subject);
-});
diff --git a/tests/unit/mixins/fetch-live-data-test.js b/tests/unit/mixins/fetch-live-data-test.js
deleted file mode 100644
index de5b41e..0000000
--- a/tests/unit/mixins/fetch-live-data-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Ember from 'ember';
-import FetchLiveDataMixin from 'villasweb-frontend/mixins/fetch-live-data';
-import { module, test } from 'qunit';
-
-module('Unit | Mixin | fetch live data');
-
-// Replace this with your real tests.
-test('it works', function(assert) {
- let FetchLiveDataObject = Ember.Object.extend(FetchLiveDataMixin);
- let subject = FetchLiveDataObject.create();
- assert.ok(subject);
-});
diff --git a/tests/unit/mixins/live-data-test.js b/tests/unit/mixins/live-data-test.js
deleted file mode 100644
index 804897f..0000000
--- a/tests/unit/mixins/live-data-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Ember from 'ember';
-import LiveDataMixin from 'villasweb-frontend/mixins/live-data';
-import { module, test } from 'qunit';
-
-module('Unit | Mixin | live data');
-
-// Replace this with your real tests.
-test('it works', function(assert) {
- let LiveDataObject = Ember.Object.extend(LiveDataMixin);
- let subject = LiveDataObject.create();
- assert.ok(subject);
-});
diff --git a/tests/unit/mixins/resizable-test.js b/tests/unit/mixins/resizable-test.js
deleted file mode 100644
index eaec854..0000000
--- a/tests/unit/mixins/resizable-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Ember from 'ember';
-import ResizableMixin from 'villasweb-frontend/mixins/resizable';
-import { module, test } from 'qunit';
-
-module('Unit | Mixin | resizable');
-
-// Replace this with your real tests.
-test('it works', function(assert) {
- let ResizableObject = Ember.Object.extend(ResizableMixin);
- let subject = ResizableObject.create();
- assert.ok(subject);
-});
diff --git a/tests/unit/mixins/sortable-test.js b/tests/unit/mixins/sortable-test.js
deleted file mode 100644
index 2efc2c2..0000000
--- a/tests/unit/mixins/sortable-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Ember from 'ember';
-import SortableMixin from 'villasweb-frontend/mixins/sortable';
-import { module, test } from 'qunit';
-
-module('Unit | Mixin | sortable');
-
-// Replace this with your real tests.
-test('it works', function(assert) {
- let SortableObject = Ember.Object.extend(SortableMixin);
- let subject = SortableObject.create();
- assert.ok(subject);
-});
diff --git a/tests/unit/models/file-test.js b/tests/unit/models/file-test.js
deleted file mode 100644
index 225d072..0000000
--- a/tests/unit/models/file-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('file', 'Unit | Model | file', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/models/plot-test.js b/tests/unit/models/plot-test.js
deleted file mode 100644
index 50a2df7..0000000
--- a/tests/unit/models/plot-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('plot', 'Unit | Model | plot', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/models/project-test.js b/tests/unit/models/project-test.js
deleted file mode 100644
index 2dddcd6..0000000
--- a/tests/unit/models/project-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('project', 'Unit | Model | project', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/models/simulation-data-test.js b/tests/unit/models/simulation-data-test.js
deleted file mode 100644
index 8faab14..0000000
--- a/tests/unit/models/simulation-data-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('simulation-data', 'Unit | Model | simulation data', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/models/simulation-model-test.js b/tests/unit/models/simulation-model-test.js
deleted file mode 100644
index 01f173b..0000000
--- a/tests/unit/models/simulation-model-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('simulation-model', 'Unit | Model | simulation-model', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/models/simulation-test.js b/tests/unit/models/simulation-test.js
deleted file mode 100644
index fa6a585..0000000
--- a/tests/unit/models/simulation-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('simulation', 'Unit | Model | simulation', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/models/simulator-status-test.js b/tests/unit/models/simulator-status-test.js
deleted file mode 100644
index 48c8a99..0000000
--- a/tests/unit/models/simulator-status-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('simulator-status', 'Unit | Model | simulator status', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/models/simulator-test.js b/tests/unit/models/simulator-test.js
deleted file mode 100644
index 8a6206a..0000000
--- a/tests/unit/models/simulator-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('simulator', 'Unit | Model | simulator', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/models/user-test.js b/tests/unit/models/user-test.js
deleted file mode 100644
index ba21110..0000000
--- a/tests/unit/models/user-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('user', 'Unit | Model | user', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/models/visualization-test.js b/tests/unit/models/visualization-test.js
deleted file mode 100644
index f84f9bc..0000000
--- a/tests/unit/models/visualization-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('visualization', 'Unit | Model | visualization', {
- // Specify the other units that are required for this test.
- needs: []
-});
-
-test('it exists', function(assert) {
- let model = this.subject();
- // let store = this.store();
- assert.ok(!!model);
-});
diff --git a/tests/unit/routes/404-test.js b/tests/unit/routes/404-test.js
deleted file mode 100644
index 260a5bc..0000000
--- a/tests/unit/routes/404-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:404', 'Unit | Route | 404', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/application-test.js b/tests/unit/routes/application-test.js
deleted file mode 100644
index 9808c43..0000000
--- a/tests/unit/routes/application-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:application', 'Unit | Route | application', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/dialog/plot/value-test.js b/tests/unit/routes/dialog/plot/value-test.js
deleted file mode 100644
index 259de45..0000000
--- a/tests/unit/routes/dialog/plot/value-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:dialog/plot/value', 'Unit | Route | dialog/plot/value', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/index-test.js b/tests/unit/routes/index-test.js
deleted file mode 100644
index 5d0f50d..0000000
--- a/tests/unit/routes/index-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:index', 'Unit | Route | index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/login-test.js b/tests/unit/routes/login-test.js
deleted file mode 100644
index e78ebad..0000000
--- a/tests/unit/routes/login-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:login', 'Unit | Route | login', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/logout-test.js b/tests/unit/routes/logout-test.js
deleted file mode 100644
index 64613a0..0000000
--- a/tests/unit/routes/logout-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:logout', 'Unit | Route | logout', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/me-test.js b/tests/unit/routes/me-test.js
deleted file mode 100644
index 9719ac5..0000000
--- a/tests/unit/routes/me-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:me', 'Unit | Route | me', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/models-test.js b/tests/unit/routes/models-test.js
deleted file mode 100644
index a6182e6..0000000
--- a/tests/unit/routes/models-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:models', 'Unit | Route | models', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/projects-test.js b/tests/unit/routes/projects-test.js
deleted file mode 100644
index e5dfb65..0000000
--- a/tests/unit/routes/projects-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:projects', 'Unit | Route | projects', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/projects/delete-test.js b/tests/unit/routes/projects/delete-test.js
deleted file mode 100644
index 7ce43e6..0000000
--- a/tests/unit/routes/projects/delete-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:projects/delete', 'Unit | Route | projects/delete', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/projects/edit-test.js b/tests/unit/routes/projects/edit-test.js
deleted file mode 100644
index 545616f..0000000
--- a/tests/unit/routes/projects/edit-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:projects/edit', 'Unit | Route | projects/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/projects/index-test.js b/tests/unit/routes/projects/index-test.js
deleted file mode 100644
index c232f73..0000000
--- a/tests/unit/routes/projects/index-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:projects/index', 'Unit | Route | projects/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/projects/new-test.js b/tests/unit/routes/projects/new-test.js
deleted file mode 100644
index 0bb6b03..0000000
--- a/tests/unit/routes/projects/new-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:projects/new', 'Unit | Route | projects/new', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/projects/project-test.js b/tests/unit/routes/projects/project-test.js
deleted file mode 100644
index fa2d3fe..0000000
--- a/tests/unit/routes/projects/project-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:projects/project', 'Unit | Route | projects/project', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulation-model/index-test.js b/tests/unit/routes/simulation-model/index-test.js
deleted file mode 100644
index ae828d2..0000000
--- a/tests/unit/routes/simulation-model/index-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulation-model/index', 'Unit | Route | simulation-model/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulation/index-test.js b/tests/unit/routes/simulation/index-test.js
deleted file mode 100644
index ba31a78..0000000
--- a/tests/unit/routes/simulation/index-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulation/index', 'Unit | Route | simulation/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulations-test.js b/tests/unit/routes/simulations-test.js
deleted file mode 100644
index b72a094..0000000
--- a/tests/unit/routes/simulations-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulations', 'Unit | Route | simulations', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulators-test.js b/tests/unit/routes/simulators-test.js
deleted file mode 100644
index 8dbfe46..0000000
--- a/tests/unit/routes/simulators-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulators', 'Unit | Route | simulators', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulators/delete-test.js b/tests/unit/routes/simulators/delete-test.js
deleted file mode 100644
index 98ca109..0000000
--- a/tests/unit/routes/simulators/delete-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulators/delete', 'Unit | Route | simulators/delete', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulators/edit-test.js b/tests/unit/routes/simulators/edit-test.js
deleted file mode 100644
index be49ba0..0000000
--- a/tests/unit/routes/simulators/edit-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulators/edit', 'Unit | Route | simulators/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/simulators/index-test.js b/tests/unit/routes/simulators/index-test.js
deleted file mode 100644
index dfccfba..0000000
--- a/tests/unit/routes/simulators/index-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:simulators/index', 'Unit | Route | simulators/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/user/delete-test.js b/tests/unit/routes/user/delete-test.js
deleted file mode 100644
index 4be7323..0000000
--- a/tests/unit/routes/user/delete-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:user/delete', 'Unit | Route | user/delete', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/user/edit-test.js b/tests/unit/routes/user/edit-test.js
deleted file mode 100644
index 754cb31..0000000
--- a/tests/unit/routes/user/edit-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:user/edit', 'Unit | Route | user/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/user/index-test.js b/tests/unit/routes/user/index-test.js
deleted file mode 100644
index fe27105..0000000
--- a/tests/unit/routes/user/index-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:user/index', 'Unit | Route | user/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/user/new-test.js b/tests/unit/routes/user/new-test.js
deleted file mode 100644
index 5032fa8..0000000
--- a/tests/unit/routes/user/new-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:user/new', 'Unit | Route | user/new', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/visualization/edit-test.js b/tests/unit/routes/visualization/edit-test.js
deleted file mode 100644
index d04fad6..0000000
--- a/tests/unit/routes/visualization/edit-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:visualization/edit', 'Unit | Route | visualization/edit', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/routes/visualization/index-test.js b/tests/unit/routes/visualization/index-test.js
deleted file mode 100644
index 8dae607..0000000
--- a/tests/unit/routes/visualization/index-test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('route:visualization/index', 'Unit | Route | visualization/index', {
- // Specify the other units that are required for this test.
- // needs: ['controller:foo']
-});
-
-test('it exists', function(assert) {
- let route = this.subject();
- assert.ok(route);
-});
diff --git a/tests/unit/serializers/application-test.js b/tests/unit/serializers/application-test.js
deleted file mode 100644
index 705e9ec..0000000
--- a/tests/unit/serializers/application-test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('application', 'Unit | Serializer | application', {
- // Specify the other units that are required for this test.
- needs: ['serializer:application']
-});
-
-// Replace this with your real tests.
-test('it serializes records', function(assert) {
- let record = this.subject();
-
- let serializedRecord = record.serialize();
-
- assert.ok(serializedRecord);
-});
diff --git a/tests/unit/serializers/project-test.js b/tests/unit/serializers/project-test.js
deleted file mode 100644
index f0131a1..0000000
--- a/tests/unit/serializers/project-test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('project', 'Unit | Serializer | project', {
- // Specify the other units that are required for this test.
- needs: ['serializer:project']
-});
-
-// Replace this with your real tests.
-test('it serializes records', function(assert) {
- let record = this.subject();
-
- let serializedRecord = record.serialize();
-
- assert.ok(serializedRecord);
-});
diff --git a/tests/unit/serializers/simulation-model-test.js b/tests/unit/serializers/simulation-model-test.js
deleted file mode 100644
index 32b3e21..0000000
--- a/tests/unit/serializers/simulation-model-test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('simulation-model', 'Unit | Serializer | simulation-model', {
- // Specify the other units that are required for this test.
- needs: ['serializer:simulation-model']
-});
-
-// Replace this with your real tests.
-test('it serializes records', function(assert) {
- let record = this.subject();
-
- let serializedRecord = record.serialize();
-
- assert.ok(serializedRecord);
-});
diff --git a/tests/unit/serializers/simulation-test.js b/tests/unit/serializers/simulation-test.js
deleted file mode 100644
index 40a61cd..0000000
--- a/tests/unit/serializers/simulation-test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('simulation', 'Unit | Serializer | simulation', {
- // Specify the other units that are required for this test.
- needs: ['serializer:simulation']
-});
-
-// Replace this with your real tests.
-test('it serializes records', function(assert) {
- let record = this.subject();
-
- let serializedRecord = record.serialize();
-
- assert.ok(serializedRecord);
-});
diff --git a/tests/unit/serializers/user-test.js b/tests/unit/serializers/user-test.js
deleted file mode 100644
index 19e4a38..0000000
--- a/tests/unit/serializers/user-test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('user', 'Unit | Serializer | user', {
- // Specify the other units that are required for this test.
- needs: ['serializer:user']
-});
-
-// Replace this with your real tests.
-test('it serializes records', function(assert) {
- let record = this.subject();
-
- let serializedRecord = record.serialize();
-
- assert.ok(serializedRecord);
-});
diff --git a/tests/unit/serializers/visualization-test.js b/tests/unit/serializers/visualization-test.js
deleted file mode 100644
index f31eeec..0000000
--- a/tests/unit/serializers/visualization-test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { moduleForModel, test } from 'ember-qunit';
-
-moduleForModel('visualization', 'Unit | Serializer | visualization', {
- // Specify the other units that are required for this test.
- needs: ['serializer:visualization']
-});
-
-// Replace this with your real tests.
-test('it serializes records', function(assert) {
- let record = this.subject();
-
- let serializedRecord = record.serialize();
-
- assert.ok(serializedRecord);
-});
diff --git a/tests/unit/services/session-user-test.js b/tests/unit/services/session-user-test.js
deleted file mode 100644
index 230acec..0000000
--- a/tests/unit/services/session-user-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('service:session-user', 'Unit | Service | session user', {
- // Specify the other units that are required for this test.
- // needs: ['service:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let service = this.subject();
- assert.ok(service);
-});
diff --git a/tests/unit/transforms/array-test.js b/tests/unit/transforms/array-test.js
deleted file mode 100644
index 372f9af..0000000
--- a/tests/unit/transforms/array-test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { moduleFor, test } from 'ember-qunit';
-
-moduleFor('transform:array', 'Unit | Transform | array', {
- // Specify the other units that are required for this test.
- // needs: ['serializer:foo']
-});
-
-// Replace this with your real tests.
-test('it exists', function(assert) {
- let transform = this.subject();
- assert.ok(transform);
-});
diff --git a/todo.md b/todo.md
deleted file mode 100644
index aca9507..0000000
--- a/todo.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# To-Do
- - Change password
- - Go into edit mode if visualization is empty
- - Auto-detect if simulators are running
- - Remove running socket if it's not in the updated list
-
-websocketserverip/config.json
-{
- "affinity": 1,
- "debug": 5,
- "stats": 3,
- "name": "villas-acs",
- "http": {
- "htdocs": "/villas/web/socket",
- "port": 80
- },
- "plugins": [
- "simple_circuit.so",
- "example_hook.so"
- ],
- "nodes": {
- "ws": {
- "type": "websocket",
- "unit": "MVa",
- "units": [
- "V",
- "A",
- "Var"
- ],
- "description": "Demo Channel",
- "source": {
- "simulator": "OP5600",
- "location": "ACS lab"
- },
- "series": [
- {
- "label": "Random walk"
- },
- {
- "label": "Sine"
- },
- {
- "label": "Rect"
- }
- ]
- }
- },
- "paths": [
- {
- "in": "ws",
- "out": "ws"
- }
- ]
-}
-
-
-websocketserverip/nodes.json:
-[
- {
- "name": "ws",
- "connections": 1,
- "state": 3,
- "vectorize": 1,
- "affinity": 1,
- "type": "websocket",
- "unit": "MVa",
- "units": [
- "V",
- "A",
- "Var"
- ],
- "description": "Demo Channel",
- "source": {
- "simulator": "OP5600",
- "location": "ACS lab"
- },
- "series": [
- {
- "label": "Random walk"
- },
- {
- "label": "Sine"
- },
- {
- "label": "Rect"
- }
- ]
- }
-]
diff --git a/vendor/.gitkeep b/vendor/.gitkeep
deleted file mode 100644
index e69de29..0000000
From 48057a99ec3d8f86445b7149cee30443c03e655e Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Thu, 2 Mar 2017 14:54:42 +0100
Subject: [PATCH 052/556] Add new simulator modal
Use bootstrap for buttons, forms, modals
---
src/components/dialog-new-simulator.js | 108 +++++++++++++++++++++++++
src/containers/simulators.js | 42 ++++++----
src/index.js | 2 +
src/stores/simulator-store.js | 4 +-
src/styles/app.css | 10 ++-
5 files changed, 145 insertions(+), 21 deletions(-)
create mode 100644 src/components/dialog-new-simulator.js
diff --git a/src/components/dialog-new-simulator.js b/src/components/dialog-new-simulator.js
new file mode 100644
index 0000000..bce7065
--- /dev/null
+++ b/src/components/dialog-new-simulator.js
@@ -0,0 +1,108 @@
+/**
+ * File: dialog-new-simulator.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+ import React, { Component } from 'react';
+ import { Modal, Button, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+ class NewSimulatorDialog extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: '',
+ simulatorid: '1',
+ endpoint: ''
+ }
+
+ this.closeModal = this.closeModal.bind(this);
+ this.cancelModal = this.cancelModal.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+ this.validateForm = this.validateForm.bind(this);
+ this.resetState = this.resetState.bind(this);
+ }
+
+ valid: false
+
+ closeModal() {
+ this.props.onClose(this.state);
+ }
+
+ cancelModal() {
+ this.props.onClose(null);
+ }
+
+ handleChange(e) {
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ resetState() {
+ this.setState({ name: '', simulatorid: '1', endpoint: '' });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var simulatorid = true;
+ var endpoint = true;
+ var name = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ // test if simulatorid is a number (in a string, not type of number)
+ if (!/^\d+$/.test(this.state.simulatorid)) {
+ simulatorid = false;
+ }
+
+ if (this.state.endpoint === '') {
+ endpoint = false;
+ }
+
+ this.valid = simulatorid && endpoint && name;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+ else if (target === 'simulatorid') return simulatorid ? "success" : "error";
+ else return endpoint ? "success" : "error";
+ }
+
+ render() {
+ return (
+
+
+ New Simulator
+
+
+
+
+
+ Name
+
+
+
+ Simulator ID
+
+
+
+ Endpoint
+
+
+
+
+
+
+ Close
+ Add
+
+
+ );
+ }
+ }
+
+ export default NewSimulatorDialog;
diff --git a/src/containers/simulators.js b/src/containers/simulators.js
index f9687da..03ecb04 100644
--- a/src/containers/simulators.js
+++ b/src/containers/simulators.js
@@ -9,15 +9,24 @@
import React, { Component } from 'react';
import { Container } from 'flux/utils';
+import { Button } from 'react-bootstrap';
import AppDispatcher from '../app-dispatcher';
import VillasStore from '../stores/villas-store';
import SimulatorStore from '../stores/simulator-store';
import Table from '../components/table';
+import NewSimulatorDialog from '../components/dialog-new-simulator';
import '../styles/projects.css';
class Simulators extends Component {
+ constructor(props) {
+ super(props);
+
+ this.showModal = this.showModal.bind(this);
+ this.closeModal = this.closeModal.bind(this);
+ }
+
static getStores() {
return [ VillasStore, SimulatorStore ];
}
@@ -27,7 +36,7 @@ class Simulators extends Component {
villas: VillasStore.getState(),
simulators: SimulatorStore.getState(),
- onButton
+ modal: false
};
}
@@ -37,6 +46,21 @@ class Simulators extends Component {
});
}
+ showModal() {
+ this.setState({ modal: true });
+ }
+
+ closeModal(data) {
+ this.setState({ modal : false });
+
+ if (data) {
+ AppDispatcher.dispatch({
+ type: 'simulators/start-add',
+ simulator: data
+ });
+ }
+ }
+
render() {
var columns = [
{ title: 'Name', key: 'name' },
@@ -51,22 +75,12 @@ class Simulators extends Component {
- New Simulator
+ New Simulator
+
+
);
}
}
-function onButton() {
- AppDispatcher.dispatch({
- type: 'simulators/start-add',
- simulator: {
- name: 'Virtual',
- running: false,
- simulatorid: 3,
- endpoint: '1.1.1.1:1234'
- }
- });
-}
-
export default Container.create(Simulators);
diff --git a/src/index.js b/src/index.js
index 37758bb..c7cccd4 100644
--- a/src/index.js
+++ b/src/index.js
@@ -11,6 +11,8 @@ import React from 'react';
import ReactDOM from 'react-dom';
import Router from './router';
+
+import 'bootstrap/dist/css/bootstrap.css';
import './styles/index.css';
ReactDOM.render(
diff --git a/src/stores/simulator-store.js b/src/stores/simulator-store.js
index f8ff715..66285e1 100644
--- a/src/stores/simulator-store.js
+++ b/src/stores/simulator-store.js
@@ -22,8 +22,6 @@ class SimulatorStore extends ReduceStore {
}
reduce(state, action) {
- console.log(action.type);
-
switch (action.type) {
case 'simulators/start-load':
SimulatorsDataManager.loadSimulators();
@@ -44,7 +42,7 @@ class SimulatorStore extends ReduceStore {
// state should always be immutable, thus make new copy
var simulators = state.slice();
simulators.push(action.simulator);
-
+
return simulators;
case 'simulators/add-error':
diff --git a/src/styles/app.css b/src/styles/app.css
index 6ee6c69..e3c697d 100644
--- a/src/styles/app.css
+++ b/src/styles/app.css
@@ -11,7 +11,7 @@
* Application container
*/
body {
- background-color: #6EA2B0;
+ background-color: #6EA2B0 !important;
}
.app {
@@ -24,7 +24,7 @@ body {
.app header {
width: 100%;
- height: 50px;
+ height: 60px;
padding: 10px 0 0 0;
@@ -35,6 +35,8 @@ body {
.app header h1 {
width: 100%;
+ margin: 0;
+
text-align: center;
}
@@ -119,7 +121,7 @@ body {
/**
* Buttons
*/
-button {
+/*button {
margin-top: 10px;
padding: 4px 8px;
@@ -135,4 +137,4 @@ button {
button:hover {
background: #6EA2B0;
-}
+}*/
From 2fa75f0e58cee29ba906d1e8d253565b69006a6e Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Thu, 2 Mar 2017 16:22:57 +0100
Subject: [PATCH 053/556] Add delete and edit dialog to simulators
---
src/api/rest-api.js | 24 +++
src/components/dialog-edit-simulator.js | 114 +++++++++++++
src/components/dialog-new-simulator.js | 162 +++++++++----------
src/components/table-control.js | 61 +++++++
src/containers/projects.js | 2 -
src/containers/simulators.js | 105 ++++++++++--
src/data-managers/simulators-data-manager.js | 48 ++++--
src/stores/simulator-store.js | 35 +++-
src/styles/app.css | 18 +--
src/styles/projects.css | 8 -
src/styles/simulators.css | 8 -
11 files changed, 447 insertions(+), 138 deletions(-)
create mode 100644 src/components/dialog-edit-simulator.js
create mode 100644 src/components/table-control.js
delete mode 100644 src/styles/projects.css
delete mode 100644 src/styles/simulators.css
diff --git a/src/api/rest-api.js b/src/api/rest-api.js
index 0b3008c..bc886bb 100644
--- a/src/api/rest-api.js
+++ b/src/api/rest-api.js
@@ -41,6 +41,30 @@ class RestAPI {
});
});
}
+
+ delete(url) {
+ return new Promise(function (resolve, reject) {
+ request.delete(makeURL(url)).end(function (error, res) {
+ if (res.status !== 200) {
+ reject();
+ } else {
+ resolve(JSON.parse(res.text));
+ }
+ });
+ });
+ }
+
+ put(url, body) {
+ return new Promise(function (resolve, reject) {
+ request.put(makeURL(url)).send(body).end(function (error, res) {
+ if (res.status !== 200) {
+ reject();
+ } else {
+ resolve(JSON.parse(res.text));
+ }
+ });
+ });
+ }
}
export default new RestAPI();
diff --git a/src/components/dialog-edit-simulator.js b/src/components/dialog-edit-simulator.js
new file mode 100644
index 0000000..a281522
--- /dev/null
+++ b/src/components/dialog-edit-simulator.js
@@ -0,0 +1,114 @@
+/**
+ * File: dialog-new-simulator.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Modal, Button, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+class EditSimulatorDialog extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: '',
+ simulatorid: '1',
+ endpoint: '',
+ _id: ''
+ }
+
+ this.closeModal = this.closeModal.bind(this);
+ this.cancelModal = this.cancelModal.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+ this.validateForm = this.validateForm.bind(this);
+ this.resetState = this.resetState.bind(this);
+ }
+
+ valid: false
+
+ closeModal() {
+ this.props.onClose(this.state);
+ }
+
+ cancelModal() {
+ this.props.onClose(null);
+ }
+
+ handleChange(e) {
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ resetState() {
+ this.setState({
+ name: this.props.simulator.name,
+ simulatorid: this.props.simulator.simulatorid,
+ endpoint: this.props.simulator.endpoint,
+ _id: this.props.simulator._id
+ });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var simulatorid = true;
+ var endpoint = true;
+ var name = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ // test if simulatorid is a number (in a string, not type of number)
+ if (!/^\d+$/.test(this.state.simulatorid)) {
+ simulatorid = false;
+ }
+
+ if (this.state.endpoint === '') {
+ endpoint = false;
+ }
+
+ this.valid = simulatorid && endpoint && name;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+ else if (target === 'simulatorid') return simulatorid ? "success" : "error";
+ else return endpoint ? "success" : "error";
+ }
+
+ render() {
+ return (
+
+
+ Edit Simulator
+
+
+
+
+
+ Name
+
+
+
+ Simulator ID
+
+
+
+ Endpoint
+
+
+
+
+
+
+ Cancel
+ Save
+
+
+ );
+ }
+}
+
+export default EditSimulatorDialog;
diff --git a/src/components/dialog-new-simulator.js b/src/components/dialog-new-simulator.js
index bce7065..95a3aa0 100644
--- a/src/components/dialog-new-simulator.js
+++ b/src/components/dialog-new-simulator.js
@@ -7,102 +7,102 @@
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
- import React, { Component } from 'react';
- import { Modal, Button, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+import React, { Component } from 'react';
+import { Modal, Button, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
- class NewSimulatorDialog extends Component {
- constructor(props) {
- super(props);
+class NewSimulatorDialog extends Component {
+ constructor(props) {
+ super(props);
- this.state = {
- name: '',
- simulatorid: '1',
- endpoint: ''
- }
+ this.state = {
+ name: '',
+ simulatorid: '1',
+ endpoint: ''
+ }
- this.closeModal = this.closeModal.bind(this);
- this.cancelModal = this.cancelModal.bind(this);
- this.handleChange = this.handleChange.bind(this);
- this.validateForm = this.validateForm.bind(this);
- this.resetState = this.resetState.bind(this);
- }
+ this.closeModal = this.closeModal.bind(this);
+ this.cancelModal = this.cancelModal.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+ this.validateForm = this.validateForm.bind(this);
+ this.resetState = this.resetState.bind(this);
+ }
- valid: false
+ valid: false
- closeModal() {
- this.props.onClose(this.state);
- }
+ closeModal() {
+ this.props.onClose(this.state);
+ }
- cancelModal() {
- this.props.onClose(null);
- }
+ cancelModal() {
+ this.props.onClose(null);
+ }
- handleChange(e) {
- this.setState({ [e.target.id]: e.target.value });
- }
+ handleChange(e) {
+ this.setState({ [e.target.id]: e.target.value });
+ }
- resetState() {
- this.setState({ name: '', simulatorid: '1', endpoint: '' });
- }
+ resetState() {
+ this.setState({ name: '', simulatorid: '1', endpoint: '' });
+ }
- validateForm(target) {
- // check all controls
- var simulatorid = true;
- var endpoint = true;
- var name = true;
+ validateForm(target) {
+ // check all controls
+ var simulatorid = true;
+ var endpoint = true;
+ var name = true;
- if (this.state.name === '') {
- name = false;
- }
+ if (this.state.name === '') {
+ name = false;
+ }
- // test if simulatorid is a number (in a string, not type of number)
- if (!/^\d+$/.test(this.state.simulatorid)) {
- simulatorid = false;
- }
+ // test if simulatorid is a number (in a string, not type of number)
+ if (!/^\d+$/.test(this.state.simulatorid)) {
+ simulatorid = false;
+ }
- if (this.state.endpoint === '') {
- endpoint = false;
- }
+ if (this.state.endpoint === '') {
+ endpoint = false;
+ }
- this.valid = simulatorid && endpoint && name;
+ this.valid = simulatorid && endpoint && name;
- // return state to control
- if (target === 'name') return name ? "success" : "error";
- else if (target === 'simulatorid') return simulatorid ? "success" : "error";
- else return endpoint ? "success" : "error";
- }
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+ else if (target === 'simulatorid') return simulatorid ? "success" : "error";
+ else return endpoint ? "success" : "error";
+ }
- render() {
- return (
-
-
- New Simulator
-
+ render() {
+ return (
+
+
+ New Simulator
+
-
-
-
- Name
-
-
-
- Simulator ID
-
-
-
- Endpoint
-
-
-
-
+
+
+
+ Name
+
+
+
+ Simulator ID
+
+
+
+ Endpoint
+
+
+
+
-
- Close
- Add
-
-
- );
- }
- }
+
+ Cancel
+ Add
+
+
+ );
+ }
+}
- export default NewSimulatorDialog;
+export default NewSimulatorDialog;
diff --git a/src/components/table-control.js b/src/components/table-control.js
new file mode 100644
index 0000000..9256a36
--- /dev/null
+++ b/src/components/table-control.js
@@ -0,0 +1,61 @@
+/**
+ * File: table.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Button, Glyphicon } from 'react-bootstrap';
+
+class ControlTable extends Component {
+ render() {
+ // create sorted rows
+ var rows = this.props.data.map(row => {
+ // add cells by column keys
+ var rowArray = [ row._id ];
+
+ for (var i = 0; i < this.props.columns.length; i++) {
+ if (row[this.props.columns[i].key] != null) {
+ rowArray.push(row[this.props.columns[i].key].toString());
+ } else {
+ rowArray.push("");
+ }
+ }
+
+ return rowArray;
+ });
+
+ return (
+
+
+
+ {this.props.columns.map(column => (
+ {column.title}
+ ))}
+
+
+
+
+ {rows.map((row) => (
+
+ {row.filter((element, index) => {
+ return index !== 0;
+ }).map((cell, index) => (
+ {cell}
+ ))}
+
+ this.props.onEdit(row[0])}>
+ this.props.onDelete(row[0])}>
+
+
+ ))}
+
+
+ );
+ }
+}
+
+export default ControlTable;
diff --git a/src/containers/projects.js b/src/containers/projects.js
index bf87dbc..825ca7f 100644
--- a/src/containers/projects.js
+++ b/src/containers/projects.js
@@ -13,8 +13,6 @@ import { Container } from 'flux/utils';
// import AppDispatcher from '../app-dispatcher';
import VillasStore from '../stores/villas-store';
-import '../styles/projects.css';
-
class Projects extends Component {
static getStores() {
return [ VillasStore ];
diff --git a/src/containers/simulators.js b/src/containers/simulators.js
index 03ecb04..d01ebf2 100644
--- a/src/containers/simulators.js
+++ b/src/containers/simulators.js
@@ -9,34 +9,40 @@
import React, { Component } from 'react';
import { Container } from 'flux/utils';
-import { Button } from 'react-bootstrap';
+import { Button, Modal } from 'react-bootstrap';
import AppDispatcher from '../app-dispatcher';
-import VillasStore from '../stores/villas-store';
import SimulatorStore from '../stores/simulator-store';
-import Table from '../components/table';
+import ControlTable from '../components/table-control';
import NewSimulatorDialog from '../components/dialog-new-simulator';
-import '../styles/projects.css';
+import EditSimulatorDialog from '../components/dialog-edit-simulator';
class Simulators extends Component {
constructor(props) {
super(props);
- this.showModal = this.showModal.bind(this);
- this.closeModal = this.closeModal.bind(this);
+ this.showNewModal = this.showNewModal.bind(this);
+ this.closeNewModal = this.closeNewModal.bind(this);
+ this.showDeleteModal = this.showDeleteModal.bind(this);
+ this.confirmDeleteModal = this.confirmDeleteModal.bind(this);
+ this.cancelDeleteModal = this.cancelDeleteModal.bind(this);
+ this.showEditModal = this.showEditModal.bind(this);
+ this.closeEditModal = this.closeEditModal.bind(this);
}
static getStores() {
- return [ VillasStore, SimulatorStore ];
+ return [ SimulatorStore ];
}
static calculateState() {
return {
- villas: VillasStore.getState(),
simulators: SimulatorStore.getState(),
- modal: false
+ newModal: false,
+ deleteModal: false,
+ editModal: false,
+ modalSimulator: {}
};
}
@@ -46,12 +52,12 @@ class Simulators extends Component {
});
}
- showModal() {
- this.setState({ modal: true });
+ showNewModal() {
+ this.setState({ newModal: true });
}
- closeModal(data) {
- this.setState({ modal : false });
+ closeNewModal(data) {
+ this.setState({ newModal : false });
if (data) {
AppDispatcher.dispatch({
@@ -61,6 +67,56 @@ class Simulators extends Component {
}
}
+ showDeleteModal(id) {
+ // get simulator by id
+ var deleteSimulator;
+
+ this.state.simulators.forEach((simulator) => {
+ if (simulator._id === id) {
+ deleteSimulator = simulator;
+ }
+ });
+
+ this.setState({ deleteModal: true, modalSimulator: deleteSimulator });
+ }
+
+ cancelDeleteModal() {
+ this.setState({ deleteModal: false });
+ }
+
+ confirmDeleteModal() {
+ this.setState({ deleteModal: false });
+
+ AppDispatcher.dispatch({
+ type: 'simulators/start-remove',
+ simulator: this.state.modalSimulator
+ });
+ }
+
+ showEditModal(id) {
+ // get simulator by id
+ var editSimulator;
+
+ this.state.simulators.forEach((simulator) => {
+ if (simulator._id === id) {
+ editSimulator = simulator;
+ }
+ });
+
+ this.setState({ editModal: true, modalSimulator: editSimulator });
+ }
+
+ closeEditModal(data) {
+ this.setState({ editModal : false });
+
+ if (data) {
+ AppDispatcher.dispatch({
+ type: 'simulators/start-edit',
+ simulator: data
+ });
+ }
+ }
+
render() {
var columns = [
{ title: 'Name', key: 'name' },
@@ -73,11 +129,28 @@ class Simulators extends Component {
Simulators
-
+
-
New Simulator
+
New Simulator
-
+
+
+
+
+
+
+ Delete Simulator
+
+
+
+ Are you sure you want to delete the simulator '{this.state.modalSimulator.name}' ?
+
+
+
+ Cancel
+ Delete
+
+
);
}
diff --git a/src/data-managers/simulators-data-manager.js b/src/data-managers/simulators-data-manager.js
index bba01a1..d10a333 100644
--- a/src/data-managers/simulators-data-manager.js
+++ b/src/data-managers/simulators-data-manager.js
@@ -16,11 +16,11 @@ const SimulatorsDataManager = {
AppDispatcher.dispatch({
type: 'simulators/loaded',
simulators: response.simulators
- }).catch(error => {
- AppDispatcher.dispatch({
- type: 'simulators/load-error',
- error: error
- });
+ });
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: 'simulators/load-error',
+ error: error
});
});
},
@@ -30,11 +30,39 @@ const SimulatorsDataManager = {
AppDispatcher.dispatch({
type: 'simulators/added',
simulator: response.simulator
- }).catch(error => {
- AppDispatcher.dispatch({
- type: 'simulators/add-error',
- error: error
- });
+ });
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: 'simulators/add-error',
+ error: error
+ });
+ });
+ },
+
+ removeSimulator(simulator) {
+ RestAPI.delete('/simulators/' + simulator._id).then(response => {
+ AppDispatcher.dispatch({
+ type: 'simulators/removed',
+ simulator: simulator
+ });
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: 'simulators/remove-error',
+ error: error
+ });
+ });
+ },
+
+ editSimulator(simulator) {
+ RestAPI.put('/simulators/' + simulator._id, { simulator: simulator }).then(response => {
+ AppDispatcher.dispatch({
+ type: 'simulators/edited',
+ simulator: response.simulator
+ });
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: 'simulators/edit-error',
+ error: error
});
});
}
diff --git a/src/stores/simulator-store.js b/src/stores/simulator-store.js
index 66285e1..83a4533 100644
--- a/src/stores/simulator-store.js
+++ b/src/stores/simulator-store.js
@@ -22,6 +22,8 @@ class SimulatorStore extends ReduceStore {
}
reduce(state, action) {
+ var simulators;
+
switch (action.type) {
case 'simulators/start-load':
SimulatorsDataManager.loadSimulators();
@@ -40,7 +42,7 @@ class SimulatorStore extends ReduceStore {
case 'simulators/added':
// state should always be immutable, thus make new copy
- var simulators = state.slice();
+ simulators = state.slice();
simulators.push(action.simulator);
return simulators;
@@ -49,6 +51,37 @@ class SimulatorStore extends ReduceStore {
// TODO: Add error message
return state;
+ case 'simulators/start-remove':
+ SimulatorsDataManager.removeSimulator(action.simulator);
+ return state;
+
+ case 'simulators/removed':
+ return state.filter((simulator) => {
+ return (simulator !== action.simulator)
+ });
+
+ case 'simulators/remove-error':
+ // TODO: Add error message
+ return state;
+
+ case 'simulators/start-edit':
+ SimulatorsDataManager.editSimulator(action.simulator);
+ return state;
+
+ case 'simulators/edited':
+ simulators = state.slice();
+ for (var i = 0; i < simulators.length; i++) {
+ if (simulators[i]._id === action.simulator._id) {
+ simulators[i] = action.simulator;
+ }
+ }
+
+ return simulators;
+
+ case 'simulators/edit-error':
+ // TODO: Add error message
+ return state;
+
default:
return state;
}
diff --git a/src/styles/app.css b/src/styles/app.css
index e3c697d..1230010 100644
--- a/src/styles/app.css
+++ b/src/styles/app.css
@@ -121,20 +121,14 @@ body {
/**
* Buttons
*/
-/*button {
- margin-top: 10px;
- padding: 4px 8px;
-
+.table-control-button {
border: none;
- background-color: #527984;
- color: #fff;
+ background: none;
- font-size: 14px;
-
- cursor: pointer;
+ padding: 0 5px;
}
-button:hover {
- background: #6EA2B0;
-}*/
+.table-control-button:hover {
+ color: #888;
+}
diff --git a/src/styles/projects.css b/src/styles/projects.css
deleted file mode 100644
index 304b952..0000000
--- a/src/styles/projects.css
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * File: projects.css
- * Author: Markus Grigull
- * Date: 02.03.2017
- * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
diff --git a/src/styles/simulators.css b/src/styles/simulators.css
deleted file mode 100644
index 8cc54ed..0000000
--- a/src/styles/simulators.css
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * File: simulators.css
- * Author: Markus Grigull
- * Date: 02.03.2017
- * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
From c6677e455351648ff9a53187b2da88671f200836 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Fri, 3 Mar 2017 13:21:25 +0100
Subject: [PATCH 054/556] Add visualization list and detailed view
Placeholder widgets are displayed, modifable but not updated yet
---
package.json | 1 +
src/components/dialog-edit-simulator.js | 81 +++++------
src/components/dialog-edit-visualization.js | 82 +++++++++++
src/components/dialog-new-simulator.js | 82 +++++------
src/components/dialog-new-visualization.js | 77 ++++++++++
src/components/dialog.js | 49 +++++++
src/components/dropzone.js | 51 +++++++
src/components/menu-sidebar.js | 1 +
src/components/table-control-link.js | 75 ++++++++++
src/components/table-control.js | 2 +-
src/components/toolbox-item.js | 52 +++++++
src/components/widget.js | 65 +++++++++
src/containers/app.js | 4 +-
src/containers/simulators.js | 38 ++---
src/containers/visualization.js | 96 +++++++++++++
src/containers/visualizations.js | 136 ++++++++++++++++++
src/data-managers/rest-data-manager.js | 82 +++++++++++
src/data-managers/simulators-data-manager.js | 63 +-------
.../visualizations-data-manager.js | 12 ++
src/router.js | 5 +
src/stores/array-store.js | 93 ++++++++++++
src/stores/simulator-store.js | 82 +----------
src/stores/visualization-store.js | 13 ++
src/styles/app.css | 41 +++++-
src/styles/widgets.css | 17 +++
25 files changed, 1036 insertions(+), 264 deletions(-)
create mode 100644 src/components/dialog-edit-visualization.js
create mode 100644 src/components/dialog-new-visualization.js
create mode 100644 src/components/dialog.js
create mode 100644 src/components/dropzone.js
create mode 100644 src/components/table-control-link.js
create mode 100644 src/components/toolbox-item.js
create mode 100644 src/components/widget.js
create mode 100644 src/containers/visualization.js
create mode 100644 src/containers/visualizations.js
create mode 100644 src/data-managers/rest-data-manager.js
create mode 100644 src/data-managers/visualizations-data-manager.js
create mode 100644 src/stores/array-store.js
create mode 100644 src/stores/visualization-store.js
create mode 100644 src/styles/widgets.css
diff --git a/package.json b/package.json
index e8b8119..1830bf3 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"react-dnd": "^2.2.4",
"react-dnd-html5-backend": "^2.2.4",
"react-dom": "^15.4.2",
+ "react-rnd": "^4.2.2",
"react-router": "^3.0.2",
"superagent": "^3.5.0"
},
diff --git a/src/components/dialog-edit-simulator.js b/src/components/dialog-edit-simulator.js
index a281522..bddec15 100644
--- a/src/components/dialog-edit-simulator.js
+++ b/src/components/dialog-edit-simulator.js
@@ -7,10 +7,20 @@
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-import React, { Component } from 'react';
-import { Modal, Button, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Dialog from './dialog';
class EditSimulatorDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ simulator: PropTypes.object.isRequired
+ };
+
+ valid: false;
+
constructor(props) {
super(props);
@@ -19,23 +29,15 @@ class EditSimulatorDialog extends Component {
simulatorid: '1',
endpoint: '',
_id: ''
+ };
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
}
-
- this.closeModal = this.closeModal.bind(this);
- this.cancelModal = this.cancelModal.bind(this);
- this.handleChange = this.handleChange.bind(this);
- this.validateForm = this.validateForm.bind(this);
- this.resetState = this.resetState.bind(this);
- }
-
- valid: false
-
- closeModal() {
- this.props.onClose(this.state);
- }
-
- cancelModal() {
- this.props.onClose(null);
}
handleChange(e) {
@@ -80,33 +82,22 @@ class EditSimulatorDialog extends Component {
render() {
return (
-
-
- Edit Simulator
-
-
-
-
-
- Name
-
-
-
- Simulator ID
-
-
-
- Endpoint
-
-
-
-
-
-
- Cancel
- Save
-
-
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+ Simulator ID
+ this.handleChange(e)} />
+
+
+ Endpoint
+ this.handleChange(e)} />
+
+
+
);
}
}
diff --git a/src/components/dialog-edit-visualization.js b/src/components/dialog-edit-visualization.js
new file mode 100644
index 0000000..5284c7a
--- /dev/null
+++ b/src/components/dialog-edit-visualization.js
@@ -0,0 +1,82 @@
+/**
+ * File: dialog-new-visualization.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Dialog from './dialog';
+
+class EditVisualizationDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ visualization: PropTypes.object.isRequired
+ };
+
+ valid: false;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: '',
+ _id: ''
+ }
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
+ }
+ }
+
+ handleChange(e) {
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ resetState() {
+ this.setState({
+ name: this.props.visualization.name,
+ _id: this.props.visualization._id
+ });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var name = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ this.valid = name;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+
+ return "success";
+ }
+
+ render() {
+ return (
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+
+ );
+ }
+}
+
+export default EditVisualizationDialog;
diff --git a/src/components/dialog-new-simulator.js b/src/components/dialog-new-simulator.js
index 95a3aa0..93a074e 100644
--- a/src/components/dialog-new-simulator.js
+++ b/src/components/dialog-new-simulator.js
@@ -7,34 +7,35 @@
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-import React, { Component } from 'react';
-import { Modal, Button, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Dialog from './dialog';
class NewSimulatorDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired
+ };
+
+ valid: false;
+
constructor(props) {
super(props);
- this.state = {
+ this.state = {
name: '',
simulatorid: '1',
endpoint: ''
+ };
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
}
-
- this.closeModal = this.closeModal.bind(this);
- this.cancelModal = this.cancelModal.bind(this);
- this.handleChange = this.handleChange.bind(this);
- this.validateForm = this.validateForm.bind(this);
- this.resetState = this.resetState.bind(this);
- }
-
- valid: false
-
- closeModal() {
- this.props.onClose(this.state);
- }
-
- cancelModal() {
- this.props.onClose(null);
}
handleChange(e) {
@@ -74,33 +75,22 @@ class NewSimulatorDialog extends Component {
render() {
return (
-
-
- New Simulator
-
-
-
-
-
- Name
-
-
-
- Simulator ID
-
-
-
- Endpoint
-
-
-
-
-
-
- Cancel
- Add
-
-
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+ Simulator ID
+ this.handleChange(e)} />
+
+
+ Endpoint
+ this.handleChange(e)} />
+
+
+
);
}
}
diff --git a/src/components/dialog-new-visualization.js b/src/components/dialog-new-visualization.js
new file mode 100644
index 0000000..d24aa6e
--- /dev/null
+++ b/src/components/dialog-new-visualization.js
@@ -0,0 +1,77 @@
+/**
+ * File: dialog-new-visualization.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Dialog from './dialog';
+
+class NewVisualzationDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired
+ };
+
+ valid: false;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: ''
+ }
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
+ }
+ }
+
+ handleChange(e) {
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ resetState() {
+ this.setState({ name: '' });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var name = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ this.valid = name;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+
+ return "success";
+ }
+
+ render() {
+ return (
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+
+ );
+ }
+}
+
+export default NewVisualzationDialog;
diff --git a/src/components/dialog.js b/src/components/dialog.js
new file mode 100644
index 0000000..a317a02
--- /dev/null
+++ b/src/components/dialog.js
@@ -0,0 +1,49 @@
+/**
+ * File: dialog.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { Modal, Button } from 'react-bootstrap';
+
+class Dialog extends Component {
+ static propTypes = {
+ title: PropTypes.string.isRequired,
+ show: PropTypes.bool.isRequired,
+ buttonTitle: PropTypes.string.isRequired,
+ onClose: PropTypes.func.isRequired
+ };
+
+ closeModal() {
+ this.props.onClose(false);
+ }
+
+ cancelModal() {
+ this.props.onClose(true);
+ }
+
+ render() {
+ return (
+
+
+ {this.props.title}
+
+
+
+ {this.props.children}
+
+
+
+ this.cancelModal()}>Cancel
+ this.closeModal()} disabled={!this.props.valid}>{this.props.buttonTitle}
+
+
+ );
+ }
+}
+
+export default Dialog;
diff --git a/src/components/dropzone.js b/src/components/dropzone.js
new file mode 100644
index 0000000..de2986d
--- /dev/null
+++ b/src/components/dropzone.js
@@ -0,0 +1,51 @@
+/**
+ * File: dropzone.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { DropTarget } from 'react-dnd';
+import classNames from 'classnames';
+
+const dropzoneTarget = {
+ drop(props, monitor) {
+ props.onDrop(monitor.getItem());
+ }
+};
+
+function collect(connect, monitor) {
+ return {
+ connectDropTarget: connect.dropTarget(),
+ isOver: monitor.isOver(),
+ canDrop: monitor.canDrop()
+ };
+}
+
+class Dropzone extends Component {
+ static propTypes = {
+ connectDropTarget: PropTypes.func.isRequired,
+ isOver: PropTypes.bool.isRequired,
+ canDrop: PropTypes.bool.isRequired,
+ onDrop: PropTypes.func.isRequired
+ };
+
+ render() {
+ var toolboxClass = classNames({
+ 'toolbox-dropzone': true,
+ 'toolbox-dropzone-active': this.props.isOver && this.props.canDrop && this.props.editing,
+ 'toolbox-dropzone-editing': this.props.editing
+ });
+
+ return this.props.connectDropTarget(
+
+ {this.props.children}
+
+ );
+ }
+}
+
+export default DropTarget('widget', dropzoneTarget, collect)(Dropzone);
diff --git a/src/components/menu-sidebar.js b/src/components/menu-sidebar.js
index c6df652..b396169 100644
--- a/src/components/menu-sidebar.js
+++ b/src/components/menu-sidebar.js
@@ -21,6 +21,7 @@ class SidebarMenu extends Component {
Projects
Simulations
Simulators
+ Visualizations
);
diff --git a/src/components/table-control-link.js b/src/components/table-control-link.js
new file mode 100644
index 0000000..4e9c87a
--- /dev/null
+++ b/src/components/table-control-link.js
@@ -0,0 +1,75 @@
+/**
+ * File: table-control-link.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { Button, Glyphicon } from 'react-bootstrap';
+import { Link } from 'react-router';
+
+class ControlLinkTable extends Component {
+ static propTypes = {
+ columns: PropTypes.array.isRequired,
+ onEdit: PropTypes.func.isRequired,
+ onDelete: PropTypes.func.isRequired,
+ linkRoot: PropTypes.string.isRequired
+ };
+
+ render() {
+ // create sorted rows
+ var rows = this.props.data.map(row => {
+ // add cells by column keys
+ var rowArray = [ row._id ];
+
+ for (var i = 0; i < this.props.columns.length; i++) {
+ if (row[this.props.columns[i].key] != null) {
+ rowArray.push(row[this.props.columns[i].key].toString());
+ } else {
+ rowArray.push("");
+ }
+ }
+
+ return rowArray;
+ });
+
+ return (
+
+
+
+ {this.props.columns.map(column => (
+ {column.title}
+ ))}
+
+
+
+
+ {rows.map((row) => (
+
+ {row.filter((element, index) => {
+ return index !== 0;
+ }).map((cell, index) => (
+
+ {index === 0 ? (
+ {cell}
+ ) : (
+ {cell}
+ )}
+
+ ))}
+
+ this.props.onEdit(row[0])}>
+ this.props.onDelete(row[0])}>
+
+
+ ))}
+
+
+ );
+ }
+}
+
+export default ControlLinkTable;
diff --git a/src/components/table-control.js b/src/components/table-control.js
index 9256a36..ea12ca8 100644
--- a/src/components/table-control.js
+++ b/src/components/table-control.js
@@ -1,5 +1,5 @@
/**
- * File: table.js
+ * File: table-control.js
* Author: Markus Grigull
* Date: 02.03.2017
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
diff --git a/src/components/toolbox-item.js b/src/components/toolbox-item.js
new file mode 100644
index 0000000..bedb46a
--- /dev/null
+++ b/src/components/toolbox-item.js
@@ -0,0 +1,52 @@
+/**
+ * File: toolbox-item.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { DragSource } from 'react-dnd';
+import classNames from 'classnames';
+
+const toolboxItemSource = {
+ beginDrag(props) {
+ return {
+ name: props.name
+ };
+ }
+};
+
+function collect(connect, monitor) {
+ return {
+ connectDragSource: connect.dragSource(),
+ isDragging: monitor.isDragging()
+ }
+}
+
+class ToolboxItem extends Component {
+ static propTypes = {
+ connectDragSource: PropTypes.func.isRequired,
+ isDragging: PropTypes.bool.isRequired,
+ name: PropTypes.string.isRequired,
+ type: PropTypes.string.isRequired
+ };
+
+ render() {
+ var itemClass = classNames({
+ 'toolbox-item': true,
+ 'toolbox-item-dragging': this.props.isDragging
+ });
+ var dropEffect = 'copy';
+
+ return this.props.connectDragSource(
+
+ {this.props.name}
+
+ , {dropEffect});
+ }
+}
+
+export default DragSource('widget', toolboxItemSource, collect)(ToolboxItem);
diff --git a/src/components/widget.js b/src/components/widget.js
new file mode 100644
index 0000000..fa37ce3
--- /dev/null
+++ b/src/components/widget.js
@@ -0,0 +1,65 @@
+/**
+ * File: widget.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import Rnd from 'react-rnd';
+
+import '../styles/widgets.css';
+
+class Widget extends Component {
+ constructor(props) {
+ super(props);
+
+ this.resizeStop = this.resizeStop.bind(this);
+ this.dragStop = this.dragStop.bind(this);
+ }
+
+ resizeStop(direction, styleSize, clientSize, delta) {
+ // update widget
+ var widget = this.props.data;
+ widget.width = styleSize.width;
+ widget.height = styleSize.height;
+
+ this.props.onWidgetChange(widget);
+ }
+
+ dragStop(event, ui) {
+ // update widget
+ var widget = this.props.data;
+ widget.x = ui.position.left;
+ widget.y = ui.position.top;
+
+ this.props.onWidgetChange(widget);
+ }
+
+ render() {
+ const widget = this.props.data;
+
+ if (this.props.editing) {
+ return (
+ { this.rnd = c; }}
+ initial={{ x: Number(widget.x), y: Number(widget.y), width: widget.width, height: widget.height }}
+ bounds={'parent'}
+ className="widget"
+ onResizeStop={this.resizeStop}
+ onDragStop={this.dragStop}
+ >
+ {widget.name}
+
+ );
+ } else {
+ return (
+ {widget.name}
+ );
+ }
+ }
+}
+
+export default Widget;
diff --git a/src/containers/app.js b/src/containers/app.js
index b1b8a57..37acdb1 100644
--- a/src/containers/app.js
+++ b/src/containers/app.js
@@ -9,6 +9,8 @@
import React, { Component } from 'react';
import { Container } from 'flux/utils';
+import { DragDropContext } from 'react-dnd';
+import HTML5Backend from 'react-dnd-html5-backend';
// import AppDispatcher from '../app-dispatcher';
import VillasStore from '../stores/villas-store';
@@ -52,4 +54,4 @@ class App extends Component {
}
}
-export default Container.create(App);
+export default DragDropContext(HTML5Backend)(Container.create(App));
diff --git a/src/containers/simulators.js b/src/containers/simulators.js
index d01ebf2..e3be874 100644
--- a/src/containers/simulators.js
+++ b/src/containers/simulators.js
@@ -19,18 +19,6 @@ import NewSimulatorDialog from '../components/dialog-new-simulator';
import EditSimulatorDialog from '../components/dialog-edit-simulator';
class Simulators extends Component {
- constructor(props) {
- super(props);
-
- this.showNewModal = this.showNewModal.bind(this);
- this.closeNewModal = this.closeNewModal.bind(this);
- this.showDeleteModal = this.showDeleteModal.bind(this);
- this.confirmDeleteModal = this.confirmDeleteModal.bind(this);
- this.cancelDeleteModal = this.cancelDeleteModal.bind(this);
- this.showEditModal = this.showEditModal.bind(this);
- this.closeEditModal = this.closeEditModal.bind(this);
- }
-
static getStores() {
return [ SimulatorStore ];
}
@@ -52,17 +40,13 @@ class Simulators extends Component {
});
}
- showNewModal() {
- this.setState({ newModal: true });
- }
-
closeNewModal(data) {
this.setState({ newModal : false });
if (data) {
AppDispatcher.dispatch({
type: 'simulators/start-add',
- simulator: data
+ data: data
});
}
}
@@ -80,16 +64,12 @@ class Simulators extends Component {
this.setState({ deleteModal: true, modalSimulator: deleteSimulator });
}
- cancelDeleteModal() {
- this.setState({ deleteModal: false });
- }
-
confirmDeleteModal() {
this.setState({ deleteModal: false });
AppDispatcher.dispatch({
type: 'simulators/start-remove',
- simulator: this.state.modalSimulator
+ data: this.state.modalSimulator
});
}
@@ -112,7 +92,7 @@ class Simulators extends Component {
if (data) {
AppDispatcher.dispatch({
type: 'simulators/start-edit',
- simulator: data
+ data: data
});
}
}
@@ -129,13 +109,13 @@ class Simulators extends Component {
Simulators
-
+ this.showEditModal(id)} onDelete={(id) => this.showDeleteModal(id)} />
- New Simulator
+ this.setState({ newModal: true })}>New Simulator
-
+ this.closeNewModal(data)} />
-
+ this.closeEditModal(data)} simulator={this.state.modalSimulator} />
@@ -147,8 +127,8 @@ class Simulators extends Component {
- Cancel
- Delete
+ this.setState({ deleteModal: false })}>Cancel
+ this.confirmDeleteModal()}>Delete
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
new file mode 100644
index 0000000..dc260f0
--- /dev/null
+++ b/src/containers/visualization.js
@@ -0,0 +1,96 @@
+/**
+ * File: visualization.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Container } from 'flux/utils';
+import { Button } from 'react-bootstrap';
+
+import ToolboxItem from '../components/toolbox-item';
+import Dropzone from '../components/dropzone';
+import Widget from '../components/widget';
+import VisualizationStore from '../stores/visualization-store';
+import AppDispatcher from '../app-dispatcher';
+
+class Visualization extends Component {
+ static getStores() {
+ return [ VisualizationStore ];
+ }
+
+ static calculateState() {
+ return {
+ visualizations: VisualizationStore.getState(),
+
+ visualization: {},
+ editing: false
+ }
+ }
+
+ handleDrop(item) {
+ console.log(item);
+ }
+
+ widgetChange(widget) {
+ console.log(widget);
+ }
+
+ componentWillMount() {
+ AppDispatcher.dispatch({
+ type: 'visualizations/start-load'
+ });
+ }
+
+ componentDidUpdate() {
+ if (this.state.visualization._id !== this.props.params.visualization) {
+ this.reloadVisualization();
+ }
+ }
+
+ reloadVisualization() {
+ // select visualization by param id
+ this.state.visualizations.forEach((visualization) => {
+ if (visualization._id === this.props.params.visualization) {
+ this.setState({ visualization: visualization });
+ }
+ });
+ }
+
+ render() {
+ return (
+
+
{this.state.visualization.name}
+
+
+ {this.state.editing ? (
+
+ this.setState({ editing: false })}>Save
+ this.setState({ editing: false })}>Cancel
+
+ ) : (
+
this.setState({ editing: true })}>Edit
+ )}
+
+
+ {this.state.editing &&
+
+
+
+ }
+
+
this.handleDrop(item)} editing={this.state.editing}>
+ {this.state.visualization.widgets != null &&
+ this.state.visualization.widgets.map((widget, index) => (
+
+ ))}
+
+
+ );
+ }
+}
+
+export default Container.create(Visualization);
diff --git a/src/containers/visualizations.js b/src/containers/visualizations.js
new file mode 100644
index 0000000..1de8d9b
--- /dev/null
+++ b/src/containers/visualizations.js
@@ -0,0 +1,136 @@
+/**
+ * File: visualizations.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Container } from 'flux/utils';
+import { Button, Modal } from 'react-bootstrap';
+
+import AppDispatcher from '../app-dispatcher';
+import VisualizationStore from '../stores/visualization-store';
+
+import ControlLinkTable from '../components/table-control-link';
+import NewVisualzationDialog from '../components/dialog-new-visualization';
+import EditVisualizationDialog from '../components/dialog-edit-visualization';
+
+class Visualizations extends Component {
+ static getStores() {
+ return [ VisualizationStore ];
+ }
+
+ static calculateState() {
+ return {
+ visualizations: VisualizationStore.getState(),
+
+ newModal: false,
+ deleteModal: false,
+ editModal: false,
+ modalVisualization: {}
+ };
+ }
+
+ componentWillMount() {
+ AppDispatcher.dispatch({
+ type: 'visualizations/start-load'
+ });
+ }
+
+ closeNewModal(data) {
+ this.setState({ newModal : false });
+
+ if (data) {
+ AppDispatcher.dispatch({
+ type: 'visualizations/start-add',
+ data: data
+ });
+ }
+ }
+
+ showDeleteModal(id) {
+ // get visualization by id
+ var deleteVisualization;
+
+ this.state.visualizations.forEach((visualization) => {
+ if (visualization._id === id) {
+ deleteVisualization = visualization;
+ }
+ });
+
+ this.setState({ deleteModal: true, modalVisualization: deleteVisualization });
+ }
+
+ confirmDeleteModal() {
+ this.setState({ deleteModal: false });
+
+ AppDispatcher.dispatch({
+ type: 'visualizations/start-remove',
+ data: this.state.modalVisualization
+ });
+ }
+
+ showEditModal(id) {
+ // get visualization by id
+ var editVisualization;
+
+ this.state.visualizations.forEach((visualization) => {
+ if (visualization._id === id) {
+ editVisualization = visualization;
+ }
+ });
+
+ this.setState({ editModal: true, modalVisualization: editVisualization });
+ }
+
+ closeEditModal(data) {
+ this.setState({ editModal : false });
+
+ if (data) {
+ AppDispatcher.dispatch({
+ type: 'visualizations/start-edit',
+ data: data
+ });
+ }
+ }
+
+ render() {
+ var columns = [
+ { title: 'Name', key: 'name' }
+ ];
+
+ return (
+
+
Visualizations
+
+ this.showEditModal(id)} onDelete={(id) => this.showDeleteModal(id)} linkRoot="/visualizations"/>
+
+ this.setState({ newModal: true })}>New Visualization
+
+ this.closeNewModal(data)} />
+
+ this.closeEditModal(data)} visualization={this.state.modalVisualization} />
+
+
+
+ Delete Visualization
+
+
+
+ Are you sure you want to delete the visualization '{this.state.modalVisualization.name}' ?
+
+
+
+ this.setState({ deleteModal: false })}>Cancel
+ this.confirmDeleteModal()}>Delete
+
+
+
+ );
+ }
+}
+
+export default Container.create(Visualizations);
diff --git a/src/data-managers/rest-data-manager.js b/src/data-managers/rest-data-manager.js
new file mode 100644
index 0000000..87ef406
--- /dev/null
+++ b/src/data-managers/rest-data-manager.js
@@ -0,0 +1,82 @@
+/**
+ * File: data-manager.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import RestAPI from '../api/rest-api';
+import AppDispatcher from '../app-dispatcher';
+
+class RestDataManager {
+ constructor(type, url) {
+ this.url = url;
+ this.type = type;
+ }
+
+ load() {
+ RestAPI.get(this.url).then(response => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/loaded',
+ data: response[this.type + 's']
+ });
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/load-error',
+ error: error
+ });
+ });
+ }
+
+ add(object) {
+ var obj = {};
+ obj[this.type] = object;
+
+ RestAPI.post(this.url, obj).then(response => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/added',
+ data: response[this.type]
+ });
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/add-error',
+ error: error
+ });
+ });
+ }
+
+ remove(object) {
+ RestAPI.delete(this.url + '/' + object._id).then(response => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/removed',
+ data: response[this.type]
+ });
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/remove-error',
+ error: error
+ });
+ });
+ }
+
+ update(object) {
+ var obj = {};
+ obj[this.type] = object;
+
+ RestAPI.put(this.url + '/' + object._id, obj).then(response => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/edited',
+ data: response[this.type]
+ });
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/edit-error',
+ error: error
+ });
+ });
+ }
+};
+
+export default RestDataManager;
diff --git a/src/data-managers/simulators-data-manager.js b/src/data-managers/simulators-data-manager.js
index d10a333..ee6e25c 100644
--- a/src/data-managers/simulators-data-manager.js
+++ b/src/data-managers/simulators-data-manager.js
@@ -7,65 +7,6 @@
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-import RestAPI from '../api/rest-api';
-import AppDispatcher from '../app-dispatcher';
+import RestDataManager from './rest-data-manager';
-const SimulatorsDataManager = {
- loadSimulators() {
- RestAPI.get('/simulators').then(response => {
- AppDispatcher.dispatch({
- type: 'simulators/loaded',
- simulators: response.simulators
- });
- }).catch(error => {
- AppDispatcher.dispatch({
- type: 'simulators/load-error',
- error: error
- });
- });
- },
-
- addSimulator(simulator) {
- RestAPI.post('/simulators', { simulator: simulator }).then(response => {
- AppDispatcher.dispatch({
- type: 'simulators/added',
- simulator: response.simulator
- });
- }).catch(error => {
- AppDispatcher.dispatch({
- type: 'simulators/add-error',
- error: error
- });
- });
- },
-
- removeSimulator(simulator) {
- RestAPI.delete('/simulators/' + simulator._id).then(response => {
- AppDispatcher.dispatch({
- type: 'simulators/removed',
- simulator: simulator
- });
- }).catch(error => {
- AppDispatcher.dispatch({
- type: 'simulators/remove-error',
- error: error
- });
- });
- },
-
- editSimulator(simulator) {
- RestAPI.put('/simulators/' + simulator._id, { simulator: simulator }).then(response => {
- AppDispatcher.dispatch({
- type: 'simulators/edited',
- simulator: response.simulator
- });
- }).catch(error => {
- AppDispatcher.dispatch({
- type: 'simulators/edit-error',
- error: error
- });
- });
- }
-}
-
-export default SimulatorsDataManager;
+export default new RestDataManager('simulator', '/simulators');
diff --git a/src/data-managers/visualizations-data-manager.js b/src/data-managers/visualizations-data-manager.js
new file mode 100644
index 0000000..10210bc
--- /dev/null
+++ b/src/data-managers/visualizations-data-manager.js
@@ -0,0 +1,12 @@
+/**
+ * File: visualizations-data-manager.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import RestDataManager from './rest-data-manager';
+
+export default new RestDataManager('visualization', '/visualizations');
diff --git a/src/router.js b/src/router.js
index fca3355..83230d4 100644
--- a/src/router.js
+++ b/src/router.js
@@ -14,6 +14,8 @@ import App from './containers/app';
import Home from './containers/home';
import Projects from './containers/projects';
import Simulators from './containers/simulators';
+import Visualization from './containers/visualization';
+import Visualizations from './containers/visualizations';
class Root extends Component {
render() {
@@ -23,6 +25,9 @@ class Root extends Component {
+
+
+
);
diff --git a/src/stores/array-store.js b/src/stores/array-store.js
new file mode 100644
index 0000000..41123e8
--- /dev/null
+++ b/src/stores/array-store.js
@@ -0,0 +1,93 @@
+/**
+ * File: array-store.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import { ReduceStore } from 'flux/utils';
+
+import AppDispatcher from '../app-dispatcher';
+
+class ArrayStore extends ReduceStore {
+ constructor(type, dataManager) {
+ super(AppDispatcher);
+
+ this.type = type;
+ this.dataManager = dataManager;
+ }
+
+ getInitialState() {
+ return [];
+ }
+
+ reduce(state, action) {
+ var array;
+
+ switch (action.type) {
+ case this.type + '/start-load':
+ this.dataManager.load();
+ return state;
+
+ case this.type + '/loaded':
+ return action.data;
+
+ case this.type + '/load-error':
+ // TODO: Add error message
+ return state;
+
+ case this.type + '/start-add':
+ this.dataManager.add(action.data);
+ return state;
+
+ case this.type + '/added':
+ // state should always be immutable, thus make new copy
+ array = state.slice();
+ array.push(action.data);
+
+ return array;
+
+ case this.type + '/add-error':
+ // TODO: Add error message
+ return state;
+
+ case this.type + '/start-remove':
+ this.dataManager.remove(action.data);
+ return state;
+
+ case this.type + '/removed':
+ return state.filter((item) => {
+ return (item !== action.data);
+ });
+
+ case this.type + '/remove-error':
+ // TODO: Add error message
+ return state;
+
+ case this.type + '/start-edit':
+ this.dataManager.update(action.data);
+ return state;
+
+ case this.type + '/edited':
+ array = state.slice();
+ for (var i = 0; i < array.length; i++) {
+ if (array[i]._id === action.data._id) {
+ array[i] = action.data;
+ }
+ }
+
+ return array;
+
+ case this.type + '/edit-error':
+ // TODO: Add error message
+ return state;
+
+ default:
+ return state;
+ }
+ }
+}
+
+export default ArrayStore;
diff --git a/src/stores/simulator-store.js b/src/stores/simulator-store.js
index 83a4533..9413db7 100644
--- a/src/stores/simulator-store.js
+++ b/src/stores/simulator-store.js
@@ -7,85 +7,7 @@
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-import { ReduceStore } from 'flux/utils';
-
-import AppDispatcher from '../app-dispatcher';
+import ArrayStore from './array-store';
import SimulatorsDataManager from '../data-managers/simulators-data-manager';
-class SimulatorStore extends ReduceStore {
- constructor() {
- super(AppDispatcher);
- }
-
- getInitialState() {
- return [];
- }
-
- reduce(state, action) {
- var simulators;
-
- switch (action.type) {
- case 'simulators/start-load':
- SimulatorsDataManager.loadSimulators();
- return state;
-
- case 'simulators/loaded':
- return action.simulators;
-
- case 'simulators/load-error':
- // TODO: Add error message
- return state;
-
- case 'simulators/start-add':
- SimulatorsDataManager.addSimulator(action.simulator);
- return state;
-
- case 'simulators/added':
- // state should always be immutable, thus make new copy
- simulators = state.slice();
- simulators.push(action.simulator);
-
- return simulators;
-
- case 'simulators/add-error':
- // TODO: Add error message
- return state;
-
- case 'simulators/start-remove':
- SimulatorsDataManager.removeSimulator(action.simulator);
- return state;
-
- case 'simulators/removed':
- return state.filter((simulator) => {
- return (simulator !== action.simulator)
- });
-
- case 'simulators/remove-error':
- // TODO: Add error message
- return state;
-
- case 'simulators/start-edit':
- SimulatorsDataManager.editSimulator(action.simulator);
- return state;
-
- case 'simulators/edited':
- simulators = state.slice();
- for (var i = 0; i < simulators.length; i++) {
- if (simulators[i]._id === action.simulator._id) {
- simulators[i] = action.simulator;
- }
- }
-
- return simulators;
-
- case 'simulators/edit-error':
- // TODO: Add error message
- return state;
-
- default:
- return state;
- }
- }
-}
-
-export default new SimulatorStore();
+export default new ArrayStore('simulators', SimulatorsDataManager);
diff --git a/src/stores/visualization-store.js b/src/stores/visualization-store.js
new file mode 100644
index 0000000..5b5c83f
--- /dev/null
+++ b/src/stores/visualization-store.js
@@ -0,0 +1,13 @@
+/**
+ * File: visualization-store.js
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import ArrayStore from './array-store';
+import VisualizationsDataManager from '../data-managers/visualizations-data-manager';
+
+export default new ArrayStore('visualizations', VisualizationsDataManager);
diff --git a/src/styles/app.css b/src/styles/app.css
index 1230010..aa73469 100644
--- a/src/styles/app.css
+++ b/src/styles/app.css
@@ -53,7 +53,7 @@ body {
.app-content {
min-height: 200px;
- margin: 20px 20px 20px 170px;
+ margin: 20px 20px 20px 200px;
padding: 15px 20px;
background-color: #fff;
@@ -67,6 +67,8 @@ body {
.menu-sidebar {
float: left;
+ width: 160px;
+
margin: 20px 0 0 20px;
padding: 20px 25px 20px 25px;
@@ -132,3 +134,40 @@ body {
.table-control-button:hover {
color: #888;
}
+
+/**
+ * Toolbox
+ */
+.toolbox-dropzone {
+ width: 100%;
+ min-height: 400px;
+
+ position: relative;
+}
+
+.toolbox-dropzone-editing {
+ border: 3px dashed #e1e1e1;
+}
+
+.toolbox-dropzone-active {
+ border-color: #aaa;
+}
+
+.toolbox {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
+.toolbox-item {
+ display: inline-block;
+
+ padding: 5px 10px;
+
+ border: 1px solid gray;
+
+ cursor: move;
+}
+
+.toolbox-item-dragging {
+ opacity: 0.4;
+}
diff --git a/src/styles/widgets.css b/src/styles/widgets.css
new file mode 100644
index 0000000..29f86ca
--- /dev/null
+++ b/src/styles/widgets.css
@@ -0,0 +1,17 @@
+/**
+ * File: widgets.css
+ * Author: Markus Grigull
+ * Date: 02.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+.widget {
+ width: 100%;
+ height: 100%;
+
+ padding: 5px 10px;
+
+ border: 1px solid lightgray;
+}
From d9a2ae55a9911278d97909536964dc7bedb692ae Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Fri, 3 Mar 2017 16:58:35 +0100
Subject: [PATCH 055/556] Add widget context menu
Widget deletion render is kinda broken, but deletion works
---
package.json | 1 +
src/components/widget.js | 24 ++++---
src/containers/visualization.js | 110 +++++++++++++++++++++++++-------
src/styles/widgets.css | 70 +++++++++++++++++++-
4 files changed, 168 insertions(+), 37 deletions(-)
diff --git a/package.json b/package.json
index 1830bf3..d794de0 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"immutable": "^3.8.1",
"react": "^15.4.2",
"react-bootstrap": "^0.30.7",
+ "react-contextmenu": "^2.3.0",
"react-d3": "^0.4.0",
"react-dnd": "^2.2.4",
"react-dnd-html5-backend": "^2.2.4",
diff --git a/src/components/widget.js b/src/components/widget.js
index fa37ce3..424d799 100644
--- a/src/components/widget.js
+++ b/src/components/widget.js
@@ -9,24 +9,18 @@
import React, { Component } from 'react';
import Rnd from 'react-rnd';
+import { ContextMenuTrigger } from 'react-contextmenu';
import '../styles/widgets.css';
class Widget extends Component {
- constructor(props) {
- super(props);
-
- this.resizeStop = this.resizeStop.bind(this);
- this.dragStop = this.dragStop.bind(this);
- }
-
resizeStop(direction, styleSize, clientSize, delta) {
// update widget
var widget = this.props.data;
widget.width = styleSize.width;
widget.height = styleSize.height;
- this.props.onWidgetChange(widget);
+ this.props.onWidgetChange(widget, this.props.index);
}
dragStop(event, ui) {
@@ -35,7 +29,7 @@ class Widget extends Component {
widget.x = ui.position.left;
widget.y = ui.position.top;
- this.props.onWidgetChange(widget);
+ this.props.onWidgetChange(widget, this.props.index);
}
render() {
@@ -48,15 +42,19 @@ class Widget extends Component {
initial={{ x: Number(widget.x), y: Number(widget.y), width: widget.width, height: widget.height }}
bounds={'parent'}
className="widget"
- onResizeStop={this.resizeStop}
- onDragStop={this.dragStop}
+ onResizeStop={(direction, styleSize, clientSize, delta) => this.resizeStop(direction, styleSize, clientSize, delta)}
+ onDragStop={(event, ui) => this.dragStop(event, ui)}
>
- {widget.name}
+
);
} else {
return (
- {widget.name}
+
+ {widget.name}
+
);
}
}
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index dc260f0..5257c9b 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -10,6 +10,7 @@
import React, { Component } from 'react';
import { Container } from 'flux/utils';
import { Button } from 'react-bootstrap';
+import { ContextMenu, MenuItem } from 'react-contextmenu';
import ToolboxItem from '../components/toolbox-item';
import Dropzone from '../components/dropzone';
@@ -32,11 +33,59 @@ class Visualization extends Component {
}
handleDrop(item) {
- console.log(item);
+ // add new widget
+ var widget = {
+ name: 'Name',
+ type: item.name,
+ width: 100,
+ height: 100,
+ x: 0,
+ y: 0,
+ z: 0
+ };
+
+ var visualization = this.state.visualization;
+ visualization.widgets.push(widget);
+
+ this.setState({ visualization: visualization });
+ this.forceUpdate();
}
- widgetChange(widget) {
- console.log(widget);
+ widgetChange(widget, index) {
+ // save changes temporarily
+ var visualization = this.state.visualization;
+ visualization.widgets[index] = widget;
+
+ this.setState({ visualization: visualization });
+ }
+
+ editWidget(e, data) {
+
+ }
+
+ deleteWidget(e, data) {
+ // delete widget temporarily
+ var visualization = this.state.visualization;
+ visualization.widgets.splice(data.index, 1);
+
+ this.setState({ visualization: visualization });
+ this.forceUpdate();
+ }
+
+ saveChanges() {
+ AppDispatcher.dispatch({
+ type: 'visualizations/start-edit',
+ data: this.state.visualization
+ });
+
+ this.setState({ editing: false });
+ }
+
+ discardChanges() {
+ this.setState({ editing: false, visualization: {} });
+
+ this.reloadVisualization();
+ this.forceUpdate();
}
componentWillMount() {
@@ -55,39 +104,56 @@ class Visualization extends Component {
// select visualization by param id
this.state.visualizations.forEach((visualization) => {
if (visualization._id === this.props.params.visualization) {
- this.setState({ visualization: visualization });
+ // JSON.parse(JSON.stringify(obj)) = deep clone to make also copy of widget objects inside
+ this.setState({ visualization: JSON.parse(JSON.stringify(visualization)) });
}
});
}
render() {
+ console.log(this.state.visualization.widgets);
+
return (
-
{this.state.visualization.name}
-
- {this.state.editing ? (
-
- this.setState({ editing: false })}>Save
- this.setState({ editing: false })}>Cancel
-
- ) : (
-
this.setState({ editing: true })}>Edit
- )}
+
+ {this.state.visualization.name}
+
+
+
+ {this.state.editing ? (
+
+ this.saveChanges()}>Save
+ this.discardChanges()}>Cancel
+
+ ) : (
+
this.setState({ editing: true })}>Edit
+ )}
+
- {this.state.editing &&
-
-
-
- }
+
+ {this.state.editing &&
+
+
+
+ }
+
+
this.handleDrop(item)} editing={this.state.editing}>
+ {this.state.visualization.widgets != null &&
+ this.state.visualization.widgets.map((widget, index) => (
+ this.widgetChange(w, i)} editing={this.state.editing} index={index} />
+ ))}
+
-
this.handleDrop(item)} editing={this.state.editing}>
{this.state.visualization.widgets != null &&
this.state.visualization.widgets.map((widget, index) => (
-
+
))}
-
+
);
}
diff --git a/src/styles/widgets.css b/src/styles/widgets.css
index 29f86ca..7fe801b 100644
--- a/src/styles/widgets.css
+++ b/src/styles/widgets.css
@@ -11,7 +11,73 @@
width: 100%;
height: 100%;
- padding: 5px 10px;
-
border: 1px solid lightgray;
}
+
+.react-contextmenu {
+ min-width: 160px;
+ padding: 5px 0;
+ margin: 2px 0 0;
+ font-size: 16px;
+ color: #373a3c;
+ text-align: left;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid rgba(0,0,0,.15);
+ border-radius: .25rem;
+ outline: none;
+ opacity: 0;
+ pointer-events: none;
+ z-index: 100;
+}
+
+.react-contextmenu.react-contextmenu--visible {
+ opacity: 1;
+ pointer-events: auto;
+}
+
+.react-contextmenu-item {
+ width: 200px;
+ padding: 3px 20px;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #373a3c;
+ text-align: inherit;
+ white-space: nowrap;
+ background: 0 0;
+ border: 0;
+ cursor: pointer;
+}
+
+.react-contextmenu-item.react-contextmenu-item--active,
+.react-contextmenu-item:hover {
+ color: #fff;
+ background-color: #0275d8;
+ border-color: #0275d8;
+ text-decoration: none;
+}
+
+.react-contextmenu-item--divider {
+ margin-bottom: 3px;
+ padding: 2px 0;
+ border-bottom: 1px solid rgba(0,0,0,.15);
+ cursor: inherit;
+}
+.react-contextmenu-item--divider:hover {
+ background-color: transparent;
+ border-color: rgba(0,0,0,.15);
+}
+
+.react-contextmenu-item.react-contextmenu-submenu {
+ padding: 0;
+}
+
+.react-contextmenu-item.react-contextmenu-submenu > .react-contextmenu-item {
+}
+
+.react-contextmenu-item.react-contextmenu-submenu > .react-contextmenu-item:after {
+ content: "▶";
+ display: inline-block;
+ position: absolute;
+ right: 7px;
+}
From 5441bd46f6fd5e0869fa418d626dcb7ab6b63179 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Sat, 4 Mar 2017 10:31:13 +0100
Subject: [PATCH 056/556] Add websocket api with simulator data
Simulator data is passed to each widget to process the data
---
src/api/websocket-api.js | 36 +++++++++++
src/containers/visualization.js | 15 +++--
src/{components => containers}/widget.js | 44 +++++++++----
src/data-managers/rest-data-manager.js | 2 +-
src/data-managers/simulator-data-manager.js | 72 +++++++++++++++++++++
src/stores/simulator-data-store.js | 66 +++++++++++++++++++
6 files changed, 218 insertions(+), 17 deletions(-)
create mode 100644 src/api/websocket-api.js
rename src/{components => containers}/widget.js (76%)
create mode 100644 src/data-managers/simulator-data-manager.js
create mode 100644 src/stores/simulator-data-store.js
diff --git a/src/api/websocket-api.js b/src/api/websocket-api.js
new file mode 100644
index 0000000..33f96b8
--- /dev/null
+++ b/src/api/websocket-api.js
@@ -0,0 +1,36 @@
+/**
+ * File: websocket-api.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+class WebsocketAPI {
+ constructor() {
+ this.sockets = {};
+ }
+
+ addSocket(endpoint, identifier, callbacks) {
+ // create web socket client
+ var socket = new WebSocket('ws://' + endpoint, 'live');
+ socket.binaryType = 'arraybuffer';
+
+ // register callbacks
+ if (callbacks.onOpen) socket.addEventListener('open', event => callbacks.onOpen(event));
+ if (callbacks.onClose) socket.addEventListener('close', event => callbacks.onClose(event));
+ if (callbacks.onMessage) socket.addEventListener('message', event => callbacks.onMessage(event));
+ if (callbacks.onError) socket.addEventListener('error', event => callbacks.onError(event));
+
+ // save socket
+ this.sockets[identifier] = socket;
+ }
+
+ removeSocket(identifier) {
+ this.sockets[identifier].close();
+ delete this.sockets[identifier];
+ }
+}
+
+export default new WebsocketAPI();
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index 5257c9b..f2c33f2 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -14,7 +14,7 @@ import { ContextMenu, MenuItem } from 'react-contextmenu';
import ToolboxItem from '../components/toolbox-item';
import Dropzone from '../components/dropzone';
-import Widget from '../components/widget';
+import Widget from './widget';
import VisualizationStore from '../stores/visualization-store';
import AppDispatcher from '../app-dispatcher';
@@ -27,8 +27,7 @@ class Visualization extends Component {
return {
visualizations: VisualizationStore.getState(),
- visualization: {},
- editing: false
+ visualization: {}
}
}
@@ -92,6 +91,14 @@ class Visualization extends Component {
AppDispatcher.dispatch({
type: 'visualizations/start-load'
});
+
+ AppDispatcher.dispatch({
+ type: 'simulatorData/open',
+ endpoint: 'localhost:5000',
+ identifier: 'RTDS'
+ });
+
+ this.setState({ editing: false });
}
componentDidUpdate() {
@@ -111,8 +118,6 @@ class Visualization extends Component {
}
render() {
- console.log(this.state.visualization.widgets);
-
return (
diff --git a/src/components/widget.js b/src/containers/widget.js
similarity index 76%
rename from src/components/widget.js
rename to src/containers/widget.js
index 424d799..949cb4a 100644
--- a/src/components/widget.js
+++ b/src/containers/widget.js
@@ -1,26 +1,32 @@
/**
* File: widget.js
* Author: Markus Grigull
- * Date: 02.03.2017
+ * Date: 04.03.2017
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
import React, { Component } from 'react';
-import Rnd from 'react-rnd';
+import { Container } from 'flux/utils';
import { ContextMenuTrigger } from 'react-contextmenu';
+import Rnd from 'react-rnd';
+
+import SimulatorDataStore from '../stores/simulator-data-store';
import '../styles/widgets.css';
class Widget extends Component {
- resizeStop(direction, styleSize, clientSize, delta) {
- // update widget
- var widget = this.props.data;
- widget.width = styleSize.width;
- widget.height = styleSize.height;
+ static getStores() {
+ return [ SimulatorDataStore ];
+ }
- this.props.onWidgetChange(widget, this.props.index);
+ static calculateState() {
+ return {
+ simulatorData: SimulatorDataStore.getState(),
+
+ widget: {}
+ };
}
dragStop(event, ui) {
@@ -32,9 +38,25 @@ class Widget extends Component {
this.props.onWidgetChange(widget, this.props.index);
}
+ resizeStop(direction, styleSize, clientSize, delta) {
+ // update widget
+ var widget = this.props.data;
+ widget.width = styleSize.width;
+ widget.height = styleSize.height;
+
+ this.props.onWidgetChange(widget, this.props.index);
+ }
+
render() {
const widget = this.props.data;
+ var value = '';
+
+ if (this.state.simulatorData.RTDS && this.state.simulatorData.RTDS.values) {
+ const arr = this.state.simulatorData.RTDS.values[this.props.index];
+ value = arr[arr.length - 1].y;
+ }
+
if (this.props.editing) {
return (
this.dragStop(event, ui)}
>
);
} else {
return (
- {widget.name}
+ {value}
);
}
}
}
-export default Widget;
+export default Container.create(Widget);
diff --git a/src/data-managers/rest-data-manager.js b/src/data-managers/rest-data-manager.js
index 87ef406..cf5a47b 100644
--- a/src/data-managers/rest-data-manager.js
+++ b/src/data-managers/rest-data-manager.js
@@ -1,5 +1,5 @@
/**
- * File: data-manager.js
+ * File: rest-data-manager.js
* Author: Markus Grigull
* Date: 03.03.2017
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
diff --git a/src/data-managers/simulator-data-manager.js b/src/data-managers/simulator-data-manager.js
new file mode 100644
index 0000000..049eda2
--- /dev/null
+++ b/src/data-managers/simulator-data-manager.js
@@ -0,0 +1,72 @@
+/**
+ * File: simulator-data-manager.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import WebsocketAPI from '../api/websocket-api';
+import AppDispatcher from '../app-dispatcher';
+
+class SimulationDataManager {
+ open(endpoint, identifier) {
+ WebsocketAPI.addSocket(endpoint, identifier, { onOpen: event => this.onOpen(event), onClose: event => this.onClose(event), onMessage: event => this.onMessage(event) });
+ }
+
+ onOpen(event) {
+ // TODO: Add identifiers to callbacks
+
+ AppDispatcher.dispatch({
+ type: 'simulatorData/opened',
+ identifier: 'RTDS',
+ signals: 8
+ });
+ }
+
+ onClose(event) {
+ AppDispatcher.dispatch({
+ type: 'simulatorData/closed'
+ });
+ }
+
+ onMessage(event) {
+ var message = this.bufferToMessage(event.data);
+
+ AppDispatcher.dispatch({
+ type: 'simulatorData/data-changed',
+ data: message,
+ identifier: 'RTDS'
+ });
+ }
+
+ bufferToMessage(blob) {
+ // parse incoming message into usable data
+ var data = new DataView(blob);
+
+ let OFFSET_ENDIAN = 1;
+ let OFFSET_TYPE = 2;
+ let OFFSET_VERSION = 4;
+
+ var bits = data.getUint8(0);
+ var simulator = data.getUint8(0x01);
+ var endian = (bits >> OFFSET_ENDIAN) & 0x1 ? 0 : 1;
+ var length = data.getUint16(0x02, endian);
+
+ var values = new Float32Array(data.buffer, data.byteOffset + 0x10, length);
+
+ return {
+ endian: endian,
+ version: (bits >> OFFSET_VERSION) & 0xF,
+ type: (bits >> OFFSET_TYPE) & 0x3,
+ length: length,
+ sequence: data.getUint32(0x04, endian),
+ timestamp: data.getUint32(0x08, endian) * 1e3 + data.getUint32(0x0C, endian) * 1e-6,
+ values: values,
+ simulator: simulator
+ };
+ }
+}
+
+export default new SimulationDataManager();
diff --git a/src/stores/simulator-data-store.js b/src/stores/simulator-data-store.js
new file mode 100644
index 0000000..14b426b
--- /dev/null
+++ b/src/stores/simulator-data-store.js
@@ -0,0 +1,66 @@
+/**
+ * File: simulator-data-store.js
+ * Author: Markus Grigull
+ * Date: 03.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import { ReduceStore } from 'flux/utils';
+
+import AppDispatcher from '../app-dispatcher';
+import SimulatorDataManager from '../data-managers/simulator-data-manager';
+
+class SimulationDataStore extends ReduceStore {
+ constructor() {
+ super(AppDispatcher);
+ }
+
+ getInitialState() {
+ return {};
+ }
+
+ reduce(state, action) {
+ var i;
+
+ switch (action.type) {
+ case 'simulatorData/open':
+ SimulatorDataManager.open(action.endpoint, action.identifier);
+ return state;
+
+ case 'simulatorData/opened':
+ // create entry for simulator
+ state[action.identifier] = { signals: action.signals, values: [], sequence: null, timestamp: null };
+
+ for (i = 0; i < action.signals; i++) {
+ state[action.identifier].values.push([]);
+ }
+
+ return state;
+
+ case 'simulatorData/data-changed':
+ // add data to simulator
+ for (i = 0; i < state[action.identifier].signals; i++) {
+ state[action.identifier].values[i].push({ x: action.data.timestamp, y: action.data.values[i] });
+ }
+
+ // update metadata
+ state[action.identifier].timestamp = action.data.timestamp;
+ state[action.identifier].sequence = action.data.sequence;
+
+ // explicit call to prevent array copy
+ this.__emitChange();
+
+ return state;
+
+ case 'simulatorData/closed':
+ return state;
+
+ default:
+ return state;
+ }
+ }
+}
+
+export default new SimulationDataStore();
From 1939df5f33a724e268781633f633c78831b85285 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Mon, 6 Mar 2017 21:55:51 +0100
Subject: [PATCH 057/556] Fix rest API, array-data-manager
---
src/api/rest-api.js | 16 ++++++++--------
src/containers/home.js | 2 --
src/containers/visualization.js | 20 +++++++++++++++-----
src/stores/array-store.js | 10 +++++-----
src/stores/simulator-data-store.js | 8 ++++++++
src/styles/home.css | 8 --------
6 files changed, 36 insertions(+), 28 deletions(-)
delete mode 100644 src/styles/home.css
diff --git a/src/api/rest-api.js b/src/api/rest-api.js
index bc886bb..40329c2 100644
--- a/src/api/rest-api.js
+++ b/src/api/rest-api.js
@@ -21,8 +21,8 @@ class RestAPI {
get(url) {
return new Promise(function (resolve, reject) {
request.get(makeURL(url)).end(function (error, res) {
- if (res.status !== 200) {
- reject();
+ if (res == null || res.status !== 200) {
+ reject(error);
} else {
resolve(JSON.parse(res.text));
}
@@ -33,8 +33,8 @@ class RestAPI {
post(url, body) {
return new Promise(function (resolve, reject) {
request.post(makeURL(url)).send(body).end(function (error, res) {
- if (res.status !== 200) {
- reject();
+ if (res == null || res.status !== 200) {
+ reject(error);
} else {
resolve(JSON.parse(res.text));
}
@@ -45,8 +45,8 @@ class RestAPI {
delete(url) {
return new Promise(function (resolve, reject) {
request.delete(makeURL(url)).end(function (error, res) {
- if (res.status !== 200) {
- reject();
+ if (res == null || res.status !== 200) {
+ reject(error);
} else {
resolve(JSON.parse(res.text));
}
@@ -57,8 +57,8 @@ class RestAPI {
put(url, body) {
return new Promise(function (resolve, reject) {
request.put(makeURL(url)).send(body).end(function (error, res) {
- if (res.status !== 200) {
- reject();
+ if (res == null || res.status !== 200) {
+ reject(error);
} else {
resolve(JSON.parse(res.text));
}
diff --git a/src/containers/home.js b/src/containers/home.js
index 81ead97..ae74541 100644
--- a/src/containers/home.js
+++ b/src/containers/home.js
@@ -13,8 +13,6 @@ import { Container } from 'flux/utils';
// import AppDispatcher from '../app-dispatcher';
import VillasStore from '../stores/villas-store';
-import '../styles/home.css';
-
class Home extends Component {
static getStores() {
return [ VillasStore ];
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index f2c33f2..9fd585f 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -23,11 +23,23 @@ class Visualization extends Component {
return [ VisualizationStore ];
}
- static calculateState() {
+ static calculateState(prevState) {
+ if (prevState) {
+ return {
+ visualizations: VisualizationStore.getState(),
+
+ visualization: prevState.visualization,
+ editing: prevState.editing,
+ grid: prevState.grid
+ };
+ }
+
return {
visualizations: VisualizationStore.getState(),
- visualization: {}
+ visualization: {},
+ editing: false,
+ grid: false
}
}
@@ -97,8 +109,6 @@ class Visualization extends Component {
endpoint: 'localhost:5000',
identifier: 'RTDS'
});
-
- this.setState({ editing: false });
}
componentDidUpdate() {
@@ -147,7 +157,7 @@ class Visualization extends Component {
this.handleDrop(item)} editing={this.state.editing}>
{this.state.visualization.widgets != null &&
this.state.visualization.widgets.map((widget, index) => (
- this.widgetChange(w, i)} editing={this.state.editing} index={index} />
+ this.widgetChange(w, i)} editing={this.state.editing} index={index} grid={this.state.grid} />
))}
diff --git a/src/stores/array-store.js b/src/stores/array-store.js
index 41123e8..8f2179d 100644
--- a/src/stores/array-store.js
+++ b/src/stores/array-store.js
@@ -43,11 +43,11 @@ class ArrayStore extends ReduceStore {
return state;
case this.type + '/added':
- // state should always be immutable, thus make new copy
- array = state.slice();
- array.push(action.data);
+ // signal array change since its not automatically detected
+ state.push(action.data);
+ this.__emitChange();
- return array;
+ return state;
case this.type + '/add-error':
// TODO: Add error message
@@ -59,7 +59,7 @@ class ArrayStore extends ReduceStore {
case this.type + '/removed':
return state.filter((item) => {
- return (item !== action.data);
+ return (item !== action.original);
});
case this.type + '/remove-error':
diff --git a/src/stores/simulator-data-store.js b/src/stores/simulator-data-store.js
index 14b426b..38b69a3 100644
--- a/src/stores/simulator-data-store.js
+++ b/src/stores/simulator-data-store.js
@@ -12,6 +12,8 @@ import { ReduceStore } from 'flux/utils';
import AppDispatcher from '../app-dispatcher';
import SimulatorDataManager from '../data-managers/simulator-data-manager';
+const MAX_VALUES = 10000;
+
class SimulationDataStore extends ReduceStore {
constructor() {
super(AppDispatcher);
@@ -43,6 +45,12 @@ class SimulationDataStore extends ReduceStore {
// add data to simulator
for (i = 0; i < state[action.identifier].signals; i++) {
state[action.identifier].values[i].push({ x: action.data.timestamp, y: action.data.values[i] });
+
+ // erase old values
+ if (state[action.identifier].values[i].length > MAX_VALUES) {
+ const pos = state[action.identifier].values[i].length - MAX_VALUES;
+ state[action.identifier].values[i].splice(0, pos);
+ }
}
// update metadata
diff --git a/src/styles/home.css b/src/styles/home.css
deleted file mode 100644
index 5a74ef5..0000000
--- a/src/styles/home.css
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * File: home.css
- * Author: Markus Grigull
- * Date: 02.03.2017
- * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
From 01488c49396822eb7e24cdb8ab0c8460acf71591 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Mon, 6 Mar 2017 22:01:33 +0100
Subject: [PATCH 058/556] Add simulation(s) route
Move dialogs to components/dialog directory
Change table component, add table-column component, this makes
table-control and table-control-link obsolete
Fix minor bugs
---
src/components/{ => dialog}/dialog.js | 0
src/components/dialog/edit-simulation.js | 83 ++++++++++
.../edit-simulator.js} | 5 +-
.../edit-visualization.js} | 3 +-
src/components/dialog/new-simulation.js | 76 +++++++++
.../new-simulator.js} | 5 +-
.../new-visualization.js} | 3 +-
src/components/menu-sidebar.js | 2 +-
src/components/table-column.js | 32 ++++
src/components/table-control-link.js | 75 ---------
src/components/table-control.js | 61 -------
src/components/table.js | 87 +++++++---
src/containers/simulation.js | 150 ++++++++++++++++++
src/containers/simulations.js | 136 ++++++++++++++++
src/containers/simulators.js | 52 ++----
src/containers/visualizations.js | 52 ++----
src/containers/widget.js | 33 ++--
src/data-managers/rest-data-manager.js | 3 +-
src/data-managers/simulations-data-manager.js | 12 ++
src/router.js | 5 +
src/stores/simulation-store.js | 13 ++
21 files changed, 636 insertions(+), 252 deletions(-)
rename src/components/{ => dialog}/dialog.js (100%)
create mode 100644 src/components/dialog/edit-simulation.js
rename src/components/{dialog-edit-simulator.js => dialog/edit-simulator.js} (95%)
rename src/components/{dialog-edit-visualization.js => dialog/edit-visualization.js} (96%)
create mode 100644 src/components/dialog/new-simulation.js
rename src/components/{dialog-new-simulator.js => dialog/new-simulator.js} (95%)
rename src/components/{dialog-new-visualization.js => dialog/new-visualization.js} (96%)
create mode 100644 src/components/table-column.js
delete mode 100644 src/components/table-control-link.js
delete mode 100644 src/components/table-control.js
create mode 100644 src/containers/simulation.js
create mode 100644 src/containers/simulations.js
create mode 100644 src/data-managers/simulations-data-manager.js
create mode 100644 src/stores/simulation-store.js
diff --git a/src/components/dialog.js b/src/components/dialog/dialog.js
similarity index 100%
rename from src/components/dialog.js
rename to src/components/dialog/dialog.js
diff --git a/src/components/dialog/edit-simulation.js b/src/components/dialog/edit-simulation.js
new file mode 100644
index 0000000..af9dfa4
--- /dev/null
+++ b/src/components/dialog/edit-simulation.js
@@ -0,0 +1,83 @@
+/**
+ * File: new-simulation.js
+ * Author: Markus Grigull
+ * Date: 04.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Dialog from './dialog';
+
+class EditSimulationDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ simulation: PropTypes.object.isRequired
+ };
+
+ valid: false;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: '',
+ _id: ''
+ }
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
+ }
+ }
+
+ handleChange(e) {
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ resetState() {
+ this.setState({
+ name: this.props.simulation.name,
+ _id: this.props.simulation._id
+ });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var name = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ this.valid = name;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+
+ return "success";
+ }
+
+ render() {
+ return (
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+
+
+ );
+ }
+}
+
+export default EditSimulationDialog;
diff --git a/src/components/dialog-edit-simulator.js b/src/components/dialog/edit-simulator.js
similarity index 95%
rename from src/components/dialog-edit-simulator.js
rename to src/components/dialog/edit-simulator.js
index bddec15..ad6fa39 100644
--- a/src/components/dialog-edit-simulator.js
+++ b/src/components/dialog/edit-simulator.js
@@ -1,5 +1,5 @@
/**
- * File: dialog-new-simulator.js
+ * File: new-simulator.js
* Author: Markus Grigull
* Date: 02.03.2017
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
@@ -87,14 +87,17 @@ class EditSimulatorDialog extends Component {
Name
this.handleChange(e)} />
+
Simulator ID
this.handleChange(e)} />
+
Endpoint
this.handleChange(e)} />
+
diff --git a/src/components/dialog-edit-visualization.js b/src/components/dialog/edit-visualization.js
similarity index 96%
rename from src/components/dialog-edit-visualization.js
rename to src/components/dialog/edit-visualization.js
index 5284c7a..e31f96a 100644
--- a/src/components/dialog-edit-visualization.js
+++ b/src/components/dialog/edit-visualization.js
@@ -1,5 +1,5 @@
/**
- * File: dialog-new-visualization.js
+ * File: new-visualization.js
* Author: Markus Grigull
* Date: 03.03.2017
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
@@ -72,6 +72,7 @@ class EditVisualizationDialog extends Component {
Name
this.handleChange(e)} />
+
diff --git a/src/components/dialog/new-simulation.js b/src/components/dialog/new-simulation.js
new file mode 100644
index 0000000..617f00b
--- /dev/null
+++ b/src/components/dialog/new-simulation.js
@@ -0,0 +1,76 @@
+/**
+ * File: new-simulation.js
+ * Author: Markus Grigull
+ * Date: 04.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Dialog from './dialog';
+
+class NewSimulationDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired
+ };
+
+ valid: false;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: ''
+ };
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
+ }
+ }
+
+ handleChange(e) {
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ resetState() {
+ this.setState({ name: '' });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var name = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ this.valid = name;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+ }
+
+ render() {
+ return (
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+
+
+ );
+ }
+}
+
+export default NewSimulationDialog;
diff --git a/src/components/dialog-new-simulator.js b/src/components/dialog/new-simulator.js
similarity index 95%
rename from src/components/dialog-new-simulator.js
rename to src/components/dialog/new-simulator.js
index 93a074e..87eb407 100644
--- a/src/components/dialog-new-simulator.js
+++ b/src/components/dialog/new-simulator.js
@@ -1,5 +1,5 @@
/**
- * File: dialog-new-simulator.js
+ * File: new-simulator.js
* Author: Markus Grigull
* Date: 02.03.2017
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
@@ -80,14 +80,17 @@ class NewSimulatorDialog extends Component {
Name
this.handleChange(e)} />
+
Simulator ID
this.handleChange(e)} />
+
Endpoint
this.handleChange(e)} />
+
diff --git a/src/components/dialog-new-visualization.js b/src/components/dialog/new-visualization.js
similarity index 96%
rename from src/components/dialog-new-visualization.js
rename to src/components/dialog/new-visualization.js
index d24aa6e..06b3c73 100644
--- a/src/components/dialog-new-visualization.js
+++ b/src/components/dialog/new-visualization.js
@@ -1,5 +1,5 @@
/**
- * File: dialog-new-visualization.js
+ * File: new-visualization.js
* Author: Markus Grigull
* Date: 03.03.2017
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
@@ -67,6 +67,7 @@ class NewVisualzationDialog extends Component {
Name
this.handleChange(e)} />
+
diff --git a/src/components/menu-sidebar.js b/src/components/menu-sidebar.js
index b396169..509f33d 100644
--- a/src/components/menu-sidebar.js
+++ b/src/components/menu-sidebar.js
@@ -19,7 +19,7 @@ class SidebarMenu extends Component {
Home
Projects
- Simulations
+ Simulations
Simulators
Visualizations
diff --git a/src/components/table-column.js b/src/components/table-column.js
new file mode 100644
index 0000000..d657859
--- /dev/null
+++ b/src/components/table-column.js
@@ -0,0 +1,32 @@
+/**
+ * File: table-column.js
+ * Author: Markus Grigull
+ * Date: 06.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+
+class TableColumn extends Component {
+ static defaultProps = {
+ title: '',
+ modifier: null,
+ width: null,
+ editButton: false,
+ deleteButton: false,
+ link: '/',
+ linkKey: ''
+ };
+
+ render() {
+ return (
+
+ {this.props.title}
+
+ );
+ }
+}
+
+export default TableColumn;
diff --git a/src/components/table-control-link.js b/src/components/table-control-link.js
deleted file mode 100644
index 4e9c87a..0000000
--- a/src/components/table-control-link.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * File: table-control-link.js
- * Author: Markus Grigull
- * Date: 03.03.2017
- * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import React, { Component, PropTypes } from 'react';
-import { Button, Glyphicon } from 'react-bootstrap';
-import { Link } from 'react-router';
-
-class ControlLinkTable extends Component {
- static propTypes = {
- columns: PropTypes.array.isRequired,
- onEdit: PropTypes.func.isRequired,
- onDelete: PropTypes.func.isRequired,
- linkRoot: PropTypes.string.isRequired
- };
-
- render() {
- // create sorted rows
- var rows = this.props.data.map(row => {
- // add cells by column keys
- var rowArray = [ row._id ];
-
- for (var i = 0; i < this.props.columns.length; i++) {
- if (row[this.props.columns[i].key] != null) {
- rowArray.push(row[this.props.columns[i].key].toString());
- } else {
- rowArray.push("");
- }
- }
-
- return rowArray;
- });
-
- return (
-
-
-
- {this.props.columns.map(column => (
- {column.title}
- ))}
-
-
-
-
- {rows.map((row) => (
-
- {row.filter((element, index) => {
- return index !== 0;
- }).map((cell, index) => (
-
- {index === 0 ? (
- {cell}
- ) : (
- {cell}
- )}
-
- ))}
-
- this.props.onEdit(row[0])}>
- this.props.onDelete(row[0])}>
-
-
- ))}
-
-
- );
- }
-}
-
-export default ControlLinkTable;
diff --git a/src/components/table-control.js b/src/components/table-control.js
deleted file mode 100644
index ea12ca8..0000000
--- a/src/components/table-control.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * File: table-control.js
- * Author: Markus Grigull
- * Date: 02.03.2017
- * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
- * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
- * Unauthorized copying of this file, via any medium is strictly prohibited.
- **********************************************************************************/
-
-import React, { Component } from 'react';
-import { Button, Glyphicon } from 'react-bootstrap';
-
-class ControlTable extends Component {
- render() {
- // create sorted rows
- var rows = this.props.data.map(row => {
- // add cells by column keys
- var rowArray = [ row._id ];
-
- for (var i = 0; i < this.props.columns.length; i++) {
- if (row[this.props.columns[i].key] != null) {
- rowArray.push(row[this.props.columns[i].key].toString());
- } else {
- rowArray.push("");
- }
- }
-
- return rowArray;
- });
-
- return (
-
-
-
- {this.props.columns.map(column => (
- {column.title}
- ))}
-
-
-
-
- {rows.map((row) => (
-
- {row.filter((element, index) => {
- return index !== 0;
- }).map((cell, index) => (
- {cell}
- ))}
-
- this.props.onEdit(row[0])}>
- this.props.onDelete(row[0])}>
-
-
- ))}
-
-
- );
- }
-}
-
-export default ControlTable;
diff --git a/src/components/table.js b/src/components/table.js
index fab3bfe..898e65f 100644
--- a/src/components/table.js
+++ b/src/components/table.js
@@ -8,46 +8,93 @@
**********************************************************************************/
import React, { Component } from 'react';
+import { Table, Button, Glyphicon } from 'react-bootstrap';
+import { Link } from 'react-router';
+
+import TableColumn from './table-column';
+
+class CustomTable extends Component {
+ static defaultProps = {
+ width: null
+ };
-class Table extends Component {
render() {
- // create sorted rows
- var rows = this.props.data.map(row => {
- // add cells by column keys
- var rowArray = [];
+ // create sorted data for rows
+ var rows = [];
+ if (this.props.data) {
+ rows = this.props.data.map((row, index) => {
+ var array = [];
- for (var i = 0; i < this.props.columns.length; i++) {
- if (row[this.props.columns[i].key] != null) {
- rowArray.push(row[this.props.columns[i].key].toString());
- } else {
- rowArray.push("");
+ for (var i = 0; i < this.props.children.length; i++) {
+ // only handle table-column children
+ if (this.props.children[i].type === TableColumn) {
+ // add content to cell
+ var cell = [];
+
+ // add data to cell
+ const dataKey = this.props.children[i].props.dataKey;
+ if (dataKey && row[dataKey] != null) {
+ // get content
+ var content;
+ const modifier = this.props.children[i].props.modifier;
+
+ if (modifier) {
+ content = modifier(row[dataKey]);
+ } else {
+ content = row[dataKey].toString();
+ }
+
+ // check if cell should be a link
+ const linkKey = this.props.children[i].props.linkKey;
+ if (linkKey && row[linkKey] != null) {
+ cell.push( {content});
+ } else {
+ cell.push(content);
+ }
+ }
+
+ // add buttons
+ if (this.props.children[i].props.editButton) {
+ const onEdit = this.props.children[i].props.onEdit;
+ cell.push( onEdit(index)}> );
+ }
+
+ if (this.props.children[i].props.deleteButton) {
+ const onDelete = this.props.children[i].props.onDelete;
+ cell.push( onDelete(index)}> );
+ }
+
+ array.push(cell);
+ }
}
- }
- return rowArray;
- });
+ return array;
+ });
+ }
return (
-
+
- {this.props.columns.map(column => (
- {column.title}
- ))}
+ {this.props.children}
{rows.map((row, index) => (
{row.map((cell, index) => (
- {cell}
+
+ {cell.map((element, index) => (
+ {element}
+ ))}
+
))}
))}
-
+
);
}
}
-export default Table;
+export default CustomTable;
diff --git a/src/containers/simulation.js b/src/containers/simulation.js
new file mode 100644
index 0000000..a4b59b7
--- /dev/null
+++ b/src/containers/simulation.js
@@ -0,0 +1,150 @@
+/**
+ * File: simulation.js
+ * Author: Markus Grigull
+ * Date: 04.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Container } from 'flux/utils';
+import { Button, Modal, Glyphicon } from 'react-bootstrap';
+
+import SimulationStore from '../stores/simulation-store';
+import SimulatorStore from '../stores/simulator-store';
+import AppDispatcher from '../app-dispatcher';
+
+import Table from '../components/table';
+import TableColumn from '../components/table-column';
+import NewSimulationModelDialog from '../components/dialog/new-simulation-model';
+import EditSimulationModelDialog from '../components/dialog/edit-simulation-model';
+
+class Simulation extends Component {
+ static getStores() {
+ return [ SimulationStore, SimulatorStore ];
+ }
+
+ static calculateState() {
+ return {
+ simulations: SimulationStore.getState(),
+ simulators: SimulatorStore.getState(),
+
+ newModal: false,
+ deleteModal: false,
+ editModal: false,
+ modalData: {},
+
+ simulation: {}
+ }
+ }
+
+ componentWillMount() {
+ AppDispatcher.dispatch({
+ type: 'simulations/start-load'
+ });
+
+ AppDispatcher.dispatch({
+ type: 'simulators/start-load'
+ });
+ }
+
+ componentDidUpdate() {
+ if (this.state.simulation._id !== this.props.params.simulation) {
+ this.reloadSimulation();
+ }
+ }
+
+ reloadSimulation() {
+ // select simulation by param id
+ this.state.simulations.forEach((simulation) => {
+ if (simulation._id === this.props.params.simulation) {
+ // JSON.parse(JSON.stringify(obj)) = deep clone to make also copy of widget objects inside
+ this.setState({ simulation: JSON.parse(JSON.stringify(simulation)) });
+ }
+ });
+ }
+
+ closeNewModal(data) {
+ this.setState({ newModal : false });
+
+ if (data) {
+ this.state.simulation.models.push(data);
+
+ AppDispatcher.dispatch({
+ type: 'simulations/start-edit',
+ data: this.state.simulation
+ });
+ }
+ }
+
+ confirmDeleteModal() {
+ this.setState({ deleteModal: false });
+
+
+
+ /*AppDispatcher.dispatch({
+ type: 'visualizations/start-remove',
+ data: this.state.modalVisualization
+ });*/
+ }
+
+ closeEditModal(data) {
+ this.setState({ editModal : false });
+
+ if (data) {
+ /*AppDispatcher.dispatch({
+ type: 'visualizations/start-edit',
+ data: data
+ });*/
+ }
+ }
+
+ getSimulatorName(id) {
+ for (var i = 0; i < this.state.simulators.length; i++) {
+ if (this.state.simulators[i]._id === id) {
+ return this.state.simulators[i].name;
+ }
+ }
+
+ return id;
+ }
+
+ render() {
+ return (
+
+
{this.state.simulation.name}
+
+
+
+ this.getSimulatorName(id)} />
+
+ this.setState({ editModal: true, modalData: this.state.simulation.models[index] })} onDelete={(index) => this.setState({ deleteModal: true, modalData: this.state.simulation.models[index] })} />
+
+
+
this.setState({ newModal: true })}> Simulation Model
+
+
this.closeNewModal(data)} simulators={this.state.simulators} />
+
+ this.closeEditModal(data)} data={this.state.modalData} />
+
+
+
+ Delete Simulation Model
+
+
+
+ Are you sure you want to delete the simulation model '{this.state.modalData.name}' ?
+
+
+
+ this.setState({ deleteModal: false })}>Cancel
+ this.confirmDeleteModal()}>Delete
+
+
+
+ );
+ }
+}
+
+export default Container.create(Simulation);
diff --git a/src/containers/simulations.js b/src/containers/simulations.js
new file mode 100644
index 0000000..dd80a71
--- /dev/null
+++ b/src/containers/simulations.js
@@ -0,0 +1,136 @@
+/**
+ * File: simulations.js
+ * Author: Markus Grigull
+ * Date: 04.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { Container } from 'flux/utils';
+import { Button, Modal, Glyphicon } from 'react-bootstrap';
+
+import AppDispatcher from '../app-dispatcher';
+import SimulationStore from '../stores/simulation-store';
+
+import Table from '../components/table';
+import TableColumn from '../components/table-column';
+import NewSimulationDialog from '../components/dialog/new-simulation';
+import EditSimulationDialog from '../components/dialog/edit-simulation';
+
+class Simulations extends Component {
+ static getStores() {
+ return [ SimulationStore ];
+ }
+
+ static calculateState() {
+ return {
+ simulations: SimulationStore.getState(),
+
+ newModal: false,
+ deleteModal: false,
+ editModal: false,
+ modalSimulation: {}
+ };
+ }
+
+ componentWillMount() {
+ AppDispatcher.dispatch({
+ type: 'simulations/start-load'
+ });
+ }
+
+ closeNewModal(data) {
+ this.setState({ newModal : false });
+
+ if (data) {
+ AppDispatcher.dispatch({
+ type: 'simulations/start-add',
+ data: data
+ });
+ }
+ }
+
+ showDeleteModal(id) {
+ // get simulation by id
+ var deleteSimulation;
+
+ this.state.simulations.forEach((simulation) => {
+ if (simulation._id === id) {
+ deleteSimulation = simulation;
+ }
+ });
+
+ this.setState({ deleteModal: true, modalSimulation: deleteSimulation });
+ }
+
+ confirmDeleteModal() {
+ this.setState({ deleteModal: false });
+
+ AppDispatcher.dispatch({
+ type: 'simulations/start-remove',
+ data: this.state.modalSimulation
+ });
+ }
+
+ showEditModal(id) {
+ // get simulation by id
+ var editSimulation;
+
+ this.state.simulations.forEach((simulation) => {
+ if (simulation._id === id) {
+ editSimulation = simulation;
+ }
+ });
+
+ this.setState({ editModal: true, modalSimulation: editSimulation });
+ }
+
+ closeEditModal(data) {
+ this.setState({ editModal : false });
+
+ if (data) {
+ AppDispatcher.dispatch({
+ type: 'simulations/start-edit',
+ data: data
+ });
+ }
+ }
+
+ render() {
+ return (
+
+
Simulations
+
+
+
+ this.setState({ editModal: true, modalSimulation: this.state.simulations[index] })} onDelete={index => this.setState({ deleteModal: true, modalSimulation: this.state.simulations[index] })} />
+
+
+
this.setState({ newModal: true })}> Simulation
+
+
this.closeNewModal(data)} />
+
+ this.closeEditModal(data)} simulation={this.state.modalSimulation} />
+
+
+
+ Delete Simulation
+
+
+
+ Are you sure you want to delete the simulation '{this.state.modalSimulation.name}' ?
+
+
+
+ this.setState({ deleteModal: false })}>Cancel
+ this.confirmDeleteModal()}>Delete
+
+
+
+ );
+ }
+}
+
+export default Container.create(Simulations);
diff --git a/src/containers/simulators.js b/src/containers/simulators.js
index e3be874..00ab175 100644
--- a/src/containers/simulators.js
+++ b/src/containers/simulators.js
@@ -9,14 +9,15 @@
import React, { Component } from 'react';
import { Container } from 'flux/utils';
-import { Button, Modal } from 'react-bootstrap';
+import { Button, Modal, Glyphicon } from 'react-bootstrap';
import AppDispatcher from '../app-dispatcher';
import SimulatorStore from '../stores/simulator-store';
-import ControlTable from '../components/table-control';
-import NewSimulatorDialog from '../components/dialog-new-simulator';
-import EditSimulatorDialog from '../components/dialog-edit-simulator';
+import Table from '../components/table';
+import TableColumn from '../components/table-column';
+import NewSimulatorDialog from '../components/dialog/new-simulator';
+import EditSimulatorDialog from '../components/dialog/edit-simulator';
class Simulators extends Component {
static getStores() {
@@ -51,19 +52,6 @@ class Simulators extends Component {
}
}
- showDeleteModal(id) {
- // get simulator by id
- var deleteSimulator;
-
- this.state.simulators.forEach((simulator) => {
- if (simulator._id === id) {
- deleteSimulator = simulator;
- }
- });
-
- this.setState({ deleteModal: true, modalSimulator: deleteSimulator });
- }
-
confirmDeleteModal() {
this.setState({ deleteModal: false });
@@ -73,19 +61,6 @@ class Simulators extends Component {
});
}
- showEditModal(id) {
- // get simulator by id
- var editSimulator;
-
- this.state.simulators.forEach((simulator) => {
- if (simulator._id === id) {
- editSimulator = simulator;
- }
- });
-
- this.setState({ editModal: true, modalSimulator: editSimulator });
- }
-
closeEditModal(data) {
this.setState({ editModal : false });
@@ -98,20 +73,19 @@ class Simulators extends Component {
}
render() {
- var columns = [
- { title: 'Name', key: 'name' },
- { title: 'ID', key: 'simulatorid', width: 80 },
- { title: 'Running', key: 'running', width: 80 },
- { title: 'Endpoint', key: 'endpoint', width: 120 }
- ];
-
return (
Simulators
-
this.showEditModal(id)} onDelete={(id) => this.showDeleteModal(id)} />
+
+
+
+
+
+ this.setState({ editModal: true, modalSimulator: this.state.simulators[index] })} onDelete={(index) => this.setState({ deleteModal: true, modalSimulator: this.state.simulators[index] })} />
+
- this.setState({ newModal: true })}>New Simulator
+ this.setState({ newModal: true })}> Simulator
this.closeNewModal(data)} />
diff --git a/src/containers/visualizations.js b/src/containers/visualizations.js
index 1de8d9b..782fdd1 100644
--- a/src/containers/visualizations.js
+++ b/src/containers/visualizations.js
@@ -9,14 +9,15 @@
import React, { Component } from 'react';
import { Container } from 'flux/utils';
-import { Button, Modal } from 'react-bootstrap';
+import { Button, Modal, Glyphicon } from 'react-bootstrap';
import AppDispatcher from '../app-dispatcher';
import VisualizationStore from '../stores/visualization-store';
-import ControlLinkTable from '../components/table-control-link';
-import NewVisualzationDialog from '../components/dialog-new-visualization';
-import EditVisualizationDialog from '../components/dialog-edit-visualization';
+import Table from '../components/table';
+import TableColumn from '../components/table-column';
+import NewVisualzationDialog from '../components/dialog/new-visualization';
+import EditVisualizationDialog from '../components/dialog/edit-visualization';
class Visualizations extends Component {
static getStores() {
@@ -30,7 +31,7 @@ class Visualizations extends Component {
newModal: false,
deleteModal: false,
editModal: false,
- modalVisualization: {}
+ modalData: {}
};
}
@@ -51,19 +52,6 @@ class Visualizations extends Component {
}
}
- showDeleteModal(id) {
- // get visualization by id
- var deleteVisualization;
-
- this.state.visualizations.forEach((visualization) => {
- if (visualization._id === id) {
- deleteVisualization = visualization;
- }
- });
-
- this.setState({ deleteModal: true, modalVisualization: deleteVisualization });
- }
-
confirmDeleteModal() {
this.setState({ deleteModal: false });
@@ -73,19 +61,6 @@ class Visualizations extends Component {
});
}
- showEditModal(id) {
- // get visualization by id
- var editVisualization;
-
- this.state.visualizations.forEach((visualization) => {
- if (visualization._id === id) {
- editVisualization = visualization;
- }
- });
-
- this.setState({ editModal: true, modalVisualization: editVisualization });
- }
-
closeEditModal(data) {
this.setState({ editModal : false });
@@ -98,21 +73,20 @@ class Visualizations extends Component {
}
render() {
- var columns = [
- { title: 'Name', key: 'name' }
- ];
-
return (
Visualizations
-
this.showEditModal(id)} onDelete={(id) => this.showDeleteModal(id)} linkRoot="/visualizations"/>
+
+
+ this.setState({ editModal: true, modalData: this.state.visualizations[index] })} onDelete={index => this.setState({ deleteModal: true, modalData: this.state.visualizations[index] })} />
+
- this.setState({ newModal: true })}>New Visualization
+ this.setState({ newModal: true })}> Visualization
this.closeNewModal(data)} />
- this.closeEditModal(data)} visualization={this.state.modalVisualization} />
+ this.closeEditModal(data)} visualization={this.state.modalData} />
@@ -120,7 +94,7 @@ class Visualizations extends Component {
- Are you sure you want to delete the visualization '{this.state.modalVisualization.name}' ?
+ Are you sure you want to delete the visualization '{this.state.modalData.name}' ?
diff --git a/src/containers/widget.js b/src/containers/widget.js
index 949cb4a..b436075 100644
--- a/src/containers/widget.js
+++ b/src/containers/widget.js
@@ -13,6 +13,7 @@ import { ContextMenuTrigger } from 'react-contextmenu';
import Rnd from 'react-rnd';
import SimulatorDataStore from '../stores/simulator-data-store';
+import WidgetValue from '../components/widget-value';
import '../styles/widgets.css';
@@ -21,12 +22,20 @@ class Widget extends Component {
return [ SimulatorDataStore ];
}
- static calculateState() {
- return {
- simulatorData: SimulatorDataStore.getState(),
+ static calculateState(prevState) {
+ if (prevState) {
+ return {
+ simulatorData: SimulatorDataStore.getState(),
- widget: {}
- };
+ sequence: prevState.sequence + 1
+ }
+ } else {
+ return {
+ simulatorData: SimulatorDataStore.getState(),
+
+ sequence: 0
+ };
+ }
}
dragStop(event, ui) {
@@ -50,11 +59,9 @@ class Widget extends Component {
render() {
const widget = this.props.data;
- var value = '';
-
- if (this.state.simulatorData.RTDS && this.state.simulatorData.RTDS.values) {
- const arr = this.state.simulatorData.RTDS.values[this.props.index];
- value = arr[arr.length - 1].y;
+ var grid = this.props.grid;
+ if (!grid) {
+ grid = [ 1, 1 ];
}
if (this.props.editing) {
@@ -66,16 +73,18 @@ class Widget extends Component {
className="widget"
onResizeStop={(direction, styleSize, clientSize, delta) => this.resizeStop(direction, styleSize, clientSize, delta)}
onDragStop={(event, ui) => this.dragStop(event, ui)}
+ moveGrid={grid}
+ resizeGrid={grid}
>
);
} else {
return (
- {value}
+
);
}
diff --git a/src/data-managers/rest-data-manager.js b/src/data-managers/rest-data-manager.js
index cf5a47b..db92935 100644
--- a/src/data-managers/rest-data-manager.js
+++ b/src/data-managers/rest-data-manager.js
@@ -51,7 +51,8 @@ class RestDataManager {
RestAPI.delete(this.url + '/' + object._id).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/removed',
- data: response[this.type]
+ data: response[this.type],
+ original: object
});
}).catch(error => {
AppDispatcher.dispatch({
diff --git a/src/data-managers/simulations-data-manager.js b/src/data-managers/simulations-data-manager.js
new file mode 100644
index 0000000..4a9d0bf
--- /dev/null
+++ b/src/data-managers/simulations-data-manager.js
@@ -0,0 +1,12 @@
+/**
+ * File: simulation-data-manager.js
+ * Author: Markus Grigull
+ * Date: 04.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+ import RestDataManager from './rest-data-manager';
+
+ export default new RestDataManager('simulation', '/simulations');
diff --git a/src/router.js b/src/router.js
index 83230d4..5689e6e 100644
--- a/src/router.js
+++ b/src/router.js
@@ -16,6 +16,8 @@ import Projects from './containers/projects';
import Simulators from './containers/simulators';
import Visualization from './containers/visualization';
import Visualizations from './containers/visualizations';
+import Simulations from './containers/simulations';
+import Simulation from './containers/simulation';
class Root extends Component {
render() {
@@ -28,6 +30,9 @@ class Root extends Component {
+
+
+
);
diff --git a/src/stores/simulation-store.js b/src/stores/simulation-store.js
new file mode 100644
index 0000000..89854f5
--- /dev/null
+++ b/src/stores/simulation-store.js
@@ -0,0 +1,13 @@
+/**
+ * File: simulation-store.js
+ * Author: Markus Grigull
+ * Date: 04.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import ArrayStore from './array-store';
+import SimulationsDataManager from '../data-managers/simulations-data-manager';
+
+export default new ArrayStore('simulations', SimulationsDataManager);
From 04e7ea218401678d9d568671347e1541306fc047 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Tue, 7 Mar 2017 11:12:22 +0100
Subject: [PATCH 059/556] Add simulation-model route and dialogs
Add inline edit to table
---
.../dialog/edit-simulation-model.js | 140 ++++++++++++++++++
src/components/dialog/edit-widget-value.js | 92 ++++++++++++
src/components/dialog/new-simulation-model.js | 136 +++++++++++++++++
src/components/table-column.js | 4 +-
src/components/table.js | 38 ++++-
src/containers/simulation.js | 31 ++--
src/styles/app.css | 25 +---
7 files changed, 422 insertions(+), 44 deletions(-)
create mode 100644 src/components/dialog/edit-simulation-model.js
create mode 100644 src/components/dialog/edit-widget-value.js
create mode 100644 src/components/dialog/new-simulation-model.js
diff --git a/src/components/dialog/edit-simulation-model.js b/src/components/dialog/edit-simulation-model.js
new file mode 100644
index 0000000..e51380c
--- /dev/null
+++ b/src/components/dialog/edit-simulation-model.js
@@ -0,0 +1,140 @@
+/**
+ * File: edit-simulation-model.js
+ * Author: Markus Grigull
+ * Date: 04.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Table from '../table';
+import TableColumn from '../table-column';
+import Dialog from './dialog';
+
+class EditSimulationModelDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ data: PropTypes.object.isRequired,
+ simulators: PropTypes.array.isRequired
+ };
+
+ valid: false;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: '',
+ simulator: '',
+ length: 1
+ }
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
+ }
+ }
+
+ handleChange(e) {
+ if (e.target.id === 'length') {
+ // change mapping size
+ if (e.target.value > this.state.mapping.length) {
+ // add missing signals
+ while (this.state.mapping.length < e.target.value) {
+ this.state.mapping.push({ name: 'Signal', type: 'Type' });
+ }
+ } else {
+ // remove signals
+ this.state.mapping.splice(e.target.value, this.state.mapping.length - e.target.value);
+ }
+ }
+
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ handleMappingChange(event, row, column) {
+ var mapping = this.state.mapping;
+
+ if (column === 1) {
+ mapping[row].name = event.target.value;
+ } else if (column === 2) {
+ mapping[row].type = event.target.value;
+ }
+
+ this.setState({ mapping: mapping });
+ }
+
+ resetState() {
+ this.setState({
+ name: this.props.data.name,
+ simulator: this.props.data.simulator,
+ length: this.props.data.length,
+ mapping: this.props.data.mapping
+ });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var name = true;
+ var length = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ // test if simulatorid is a number (in a string, not type of number)
+ if (!/^\d+$/.test(this.state.length)) {
+ length = false;
+ }
+
+ this.valid = name && length;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+ else if (target === 'length') return length ? "success" : "error";
+ }
+
+ render() {
+ return (
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+
+ Simulator
+ this.handleChange(e)}>
+ {this.props.simulators.map(simulator => (
+ {simulator.name}
+ ))}
+
+
+
+ Length
+ this.handleChange(e)} />
+
+
+
+ Mapping
+
+
+ this.handleMappingChange(event, row, column)} />
+ this.handleMappingChange(event, row, column)} />
+
+
+
+
+ );
+ }
+}
+
+export default EditSimulationModelDialog;
diff --git a/src/components/dialog/edit-widget-value.js b/src/components/dialog/edit-widget-value.js
new file mode 100644
index 0000000..1fa5de8
--- /dev/null
+++ b/src/components/dialog/edit-widget-value.js
@@ -0,0 +1,92 @@
+/**
+ * File: edit-widget-value.js
+ * Author: Markus Grigull
+ * Date: 04.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Dialog from './dialog';
+
+class EditWidgetValueDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired
+ };
+
+ valid: false;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: '',
+ simulator: '',
+ signal: 0
+ }
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
+ }
+ }
+
+ handleChange(e) {
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ resetState() {
+ this.setState({ name: '' });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var name = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ this.valid = name;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+
+ return "success";
+ }
+
+ render() {
+ return (
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+
+ Simulator
+
+ RTDS
+ Opal
+
+
+
+ Signal
+ this.handleChange(e)} />
+
+
+
+
+ );
+ }
+}
+
+export default EditWidgetValueDialog;
diff --git a/src/components/dialog/new-simulation-model.js b/src/components/dialog/new-simulation-model.js
new file mode 100644
index 0000000..005c928
--- /dev/null
+++ b/src/components/dialog/new-simulation-model.js
@@ -0,0 +1,136 @@
+/**
+ * File: new-simulation-model.js
+ * Author: Markus Grigull
+ * Date: 04.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel, HelpBlock } from 'react-bootstrap';
+
+import Table from '../table';
+import TableColumn from '../table-column';
+import Dialog from './dialog';
+
+class NewSimulationModelDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ simulators: PropTypes.array.isRequired
+ };
+
+ valid: false;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: '',
+ simulator: '',
+ length: '1',
+ mapping: [ { name: 'Signal', type: 'Type' } ]
+ };
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
+ }
+ }
+
+ handleChange(e) {
+ if (e.target.id === 'length') {
+ // change mapping size
+ if (e.target.value > this.state.mapping.length) {
+ // add missing signals
+ while (this.state.mapping.length < e.target.value) {
+ this.state.mapping.push({ name: 'Signal', type: 'Type' });
+ }
+ } else {
+ // remove signals
+ this.state.mapping.splice(e.target.value, this.state.mapping.length - e.target.value);
+ }
+ }
+
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ handleMappingChange(event, row, column) {
+ var mapping = this.state.mapping;
+
+ if (column === 1) {
+ mapping[row].name = event.target.value;
+ } else if (column === 2) {
+ mapping[row].type = event.target.value;
+ }
+
+ this.setState({ mapping: mapping });
+ }
+
+ resetState() {
+ this.setState({ name: '', simulator: '', length: '1', mapping: [ { name: 'Signal', type: 'Type' } ] });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var name = true;
+ var length = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ // test if simulatorid is a number (in a string, not type of number)
+ if (!/^\d+$/.test(this.state.length)) {
+ length = false;
+ }
+
+ this.valid = name && length;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+ else if (target === 'length') return length ? "success" : "error";
+ }
+
+ render() {
+ return (
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+
+ Simulator
+ this.handleChange(e)}>
+ {this.props.simulators.map(simulator => (
+ {simulator.name}
+ ))}
+
+
+
+ Length
+ this.handleChange(e)} />
+
+
+
+ Mapping
+ Click Name or Type cell to edit
+
+
+ this.handleMappingChange(event, row, column)} />
+ this.handleMappingChange(event, row, column)} />
+
+
+
+
+ );
+ }
+}
+
+export default NewSimulationModelDialog;
diff --git a/src/components/table-column.js b/src/components/table-column.js
index d657859..905ca2a 100644
--- a/src/components/table-column.js
+++ b/src/components/table-column.js
@@ -17,7 +17,9 @@ class TableColumn extends Component {
editButton: false,
deleteButton: false,
link: '/',
- linkKey: ''
+ linkKey: '',
+ dataIndex: false,
+ inlineEditable: false
};
render() {
diff --git a/src/components/table.js b/src/components/table.js
index 898e65f..a40eff8 100644
--- a/src/components/table.js
+++ b/src/components/table.js
@@ -8,16 +8,28 @@
**********************************************************************************/
import React, { Component } from 'react';
-import { Table, Button, Glyphicon } from 'react-bootstrap';
+import { Table, Button, Glyphicon, FormControl } from 'react-bootstrap';
import { Link } from 'react-router';
import TableColumn from './table-column';
class CustomTable extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ editCell: [ -1, -1 ]
+ };
+ }
+
static defaultProps = {
width: null
};
+ onClick(event, row, column) {
+ this.setState({ editCell: [ column, row ]}); // x, y
+ }
+
render() {
// create sorted data for rows
var rows = [];
@@ -53,6 +65,10 @@ class CustomTable extends Component {
}
}
+ if (this.props.children[i].props.dataIndex) {
+ cell.push(index);
+ }
+
// add buttons
if (this.props.children[i].props.editButton) {
const onEdit = this.props.children[i].props.onEdit;
@@ -80,13 +96,19 @@ class CustomTable extends Component {
- {rows.map((row, index) => (
-
- {row.map((cell, index) => (
-
- {cell.map((element, index) => (
- {element}
- ))}
+ {rows.map((row, rowIndex) => (
+
+ {row.map((cell, cellIndex) => (
+ this.onClick(event, rowIndex, cellIndex) : () => {}}>
+ {(this.state.editCell[0] === cellIndex && this.state.editCell[1] === rowIndex ) ? (
+ this.props.children[cellIndex].props.onInlineChange(event, rowIndex, cellIndex)} />
+ ) : (
+
+ {cell.map((element, elementIndex) => (
+ {element}
+ ))}
+
+ )}
))}
diff --git a/src/containers/simulation.js b/src/containers/simulation.js
index a4b59b7..b6f6c97 100644
--- a/src/containers/simulation.js
+++ b/src/containers/simulation.js
@@ -34,6 +34,7 @@ class Simulation extends Component {
deleteModal: false,
editModal: false,
modalData: {},
+ modalIndex: null,
simulation: {}
}
@@ -79,24 +80,30 @@ class Simulation extends Component {
}
confirmDeleteModal() {
- this.setState({ deleteModal: false });
+ // remove model from simulation
+ var simulation = this.state.simulation;
+ simulation.models.splice(this.state.modalIndex, 1);
+ this.setState({ deleteModal: false, simulation: simulation });
-
- /*AppDispatcher.dispatch({
- type: 'visualizations/start-remove',
- data: this.state.modalVisualization
- });*/
+ AppDispatcher.dispatch({
+ type: 'simulations/start-edit',
+ data: simulation
+ });
}
closeEditModal(data) {
this.setState({ editModal : false });
if (data) {
- /*AppDispatcher.dispatch({
- type: 'visualizations/start-edit',
- data: data
- });*/
+ var simulation = this.state.simulation;
+ simulation.models[this.state.modalIndex] = data;
+ this.setState({ simulation: simulation });
+
+ AppDispatcher.dispatch({
+ type: 'simulations/start-edit',
+ data: simulation
+ });
}
}
@@ -119,14 +126,14 @@ class Simulation extends Component {
this.getSimulatorName(id)} />
- this.setState({ editModal: true, modalData: this.state.simulation.models[index] })} onDelete={(index) => this.setState({ deleteModal: true, modalData: this.state.simulation.models[index] })} />
+ this.setState({ editModal: true, modalData: this.state.simulation.models[index], modalIndex: index })} onDelete={(index) => this.setState({ deleteModal: true, modalData: this.state.simulation.models[index], modalIndex: index })} />
this.setState({ newModal: true })}> Simulation Model
this.closeNewModal(data)} simulators={this.state.simulators} />
- this.closeEditModal(data)} data={this.state.modalData} />
+ this.closeEditModal(data)} data={this.state.modalData} simulators={this.state.simulators} />
diff --git a/src/styles/app.css b/src/styles/app.css
index aa73469..c1aad96 100644
--- a/src/styles/app.css
+++ b/src/styles/app.css
@@ -28,7 +28,7 @@ body {
padding: 10px 0 0 0;
- color: #103B7D;
+ color: #527984;
background-color: #fff;
}
@@ -51,7 +51,7 @@ body {
}
.app-content {
- min-height: 200px;
+ min-height: 400px;
margin: 20px 20px 20px 200px;
padding: 15px 20px;
@@ -94,32 +94,11 @@ body {
/**
* Tables
*/
-.table {
- margin-top: 20px;
-
- border: 0;
- border-collapse: collapse;
-
- background-color: #f6f6f6;
-}
-
-.table th, td {
- padding: 5px;
-
- text-align: left;
-
- border: none;
-}
-
.table th {
background-color: #527984;
color: #fff;
}
-.table tr:nth-child(even) {
- background-color: #ddd;
-}
-
/**
* Buttons
*/
From bcb92422ffd7c13bc2e748cdef22557af0d9c251 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 8 Mar 2017 12:54:21 +0100
Subject: [PATCH 060/556] Add projects route and link to visualizations
Change rest data-manager element update mechanism
Fix new simulation-data dialog default simulator property
---
src/components/dialog/dialog.js | 2 +-
src/components/dialog/edit-project.js | 94 ++++++++++++++++
src/components/dialog/new-project.js | 86 +++++++++++++++
src/components/dialog/new-simulation-model.js | 2 +-
src/components/menu-sidebar.js | 1 -
.../{visualizations.js => project.js} | 104 +++++++++++++++---
src/containers/projects.js | 98 ++++++++++++++++-
src/data-managers/projects-data-manager.js | 12 ++
src/data-managers/rest-data-manager.js | 36 ++++--
src/data-managers/simulations-data-manager.js | 4 +-
src/router.js | 6 +-
src/stores/array-store.js | 53 ++++++---
src/stores/project-store.js | 13 +++
13 files changed, 458 insertions(+), 53 deletions(-)
create mode 100644 src/components/dialog/edit-project.js
create mode 100644 src/components/dialog/new-project.js
rename src/containers/{visualizations.js => project.js} (55%)
create mode 100644 src/data-managers/projects-data-manager.js
create mode 100644 src/stores/project-store.js
diff --git a/src/components/dialog/dialog.js b/src/components/dialog/dialog.js
index a317a02..e3c774d 100644
--- a/src/components/dialog/dialog.js
+++ b/src/components/dialog/dialog.js
@@ -39,7 +39,7 @@ class Dialog extends Component {
this.cancelModal()}>Cancel
- this.closeModal()} disabled={!this.props.valid}>{this.props.buttonTitle}
+ this.closeModal()} disabled={!this.props.valid}>{this.props.buttonTitle}
);
diff --git a/src/components/dialog/edit-project.js b/src/components/dialog/edit-project.js
new file mode 100644
index 0000000..b4facfb
--- /dev/null
+++ b/src/components/dialog/edit-project.js
@@ -0,0 +1,94 @@
+/**
+ * File: edit-project.js
+ * Author: Markus Grigull
+ * Date: 07.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Dialog from './dialog';
+
+class EditProjectDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ project: PropTypes.object.isRequired,
+ simulations: PropTypes.array.isRequired
+ };
+
+ valid: true;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: '',
+ simulation: '',
+ _id: ''
+ }
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
+ }
+ }
+
+ handleChange(e) {
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ resetState() {
+ this.setState({
+ name: this.props.project.name,
+ simulation: this.props.project.simulation,
+ _id: this.props.project._id
+ });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var name = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ this.valid = name;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+
+ return "success";
+ }
+
+ render() {
+ return (
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+
+ Simulation
+ this.handleChange(e)}>
+ {this.props.simulations.map(simulation => (
+ {simulation.name}
+ ))}
+
+
+
+
+ );
+ }
+}
+
+export default EditProjectDialog;
diff --git a/src/components/dialog/new-project.js b/src/components/dialog/new-project.js
new file mode 100644
index 0000000..6abc0c8
--- /dev/null
+++ b/src/components/dialog/new-project.js
@@ -0,0 +1,86 @@
+/**
+ * File: new-project.js
+ * Author: Markus Grigull
+ * Date: 07.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Dialog from './dialog';
+
+class NewProjectDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+ simulations: PropTypes.array.isRequired
+ };
+
+ valid: false;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ name: '',
+ simulation: ''
+ };
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state);
+ } else {
+ this.props.onClose();
+ }
+ }
+
+ handleChange(e) {
+ this.setState({ [e.target.id]: e.target.value });
+ }
+
+ resetState() {
+ this.setState({ name: '', simulation: this.props.simulations[0]._id });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var name = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ this.valid = name;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+ }
+
+ render() {
+ return (
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+
+ Simulation
+ this.handleChange(e)}>
+ {this.props.simulations.map(simulation => (
+ {simulation.name}
+ ))}
+
+
+
+
+ );
+ }
+}
+
+export default NewProjectDialog;
diff --git a/src/components/dialog/new-simulation-model.js b/src/components/dialog/new-simulation-model.js
index 005c928..cb3ca63 100644
--- a/src/components/dialog/new-simulation-model.js
+++ b/src/components/dialog/new-simulation-model.js
@@ -72,7 +72,7 @@ class NewSimulationModelDialog extends Component {
}
resetState() {
- this.setState({ name: '', simulator: '', length: '1', mapping: [ { name: 'Signal', type: 'Type' } ] });
+ this.setState({ name: '', simulator: this.props.simulators[0]._id, length: '1', mapping: [ { name: 'Signal', type: 'Type' } ] });
}
validateForm(target) {
diff --git a/src/components/menu-sidebar.js b/src/components/menu-sidebar.js
index 509f33d..afe51a6 100644
--- a/src/components/menu-sidebar.js
+++ b/src/components/menu-sidebar.js
@@ -21,7 +21,6 @@ class SidebarMenu extends Component {
Projects
Simulations
Simulators
- Visualizations
);
diff --git a/src/containers/visualizations.js b/src/containers/project.js
similarity index 55%
rename from src/containers/visualizations.js
rename to src/containers/project.js
index 782fdd1..34804d7 100644
--- a/src/containers/visualizations.js
+++ b/src/containers/project.js
@@ -1,5 +1,5 @@
/**
- * File: visualizations.js
+ * File: project.js
* Author: Markus Grigull
* Date: 03.03.2017
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
@@ -12,6 +12,7 @@ import { Container } from 'flux/utils';
import { Button, Modal, Glyphicon } from 'react-bootstrap';
import AppDispatcher from '../app-dispatcher';
+import ProjectStore from '../stores/project-store';
import VisualizationStore from '../stores/visualization-store';
import Table from '../components/table';
@@ -21,35 +22,95 @@ import EditVisualizationDialog from '../components/dialog/edit-visualization';
class Visualizations extends Component {
static getStores() {
- return [ VisualizationStore ];
+ return [ ProjectStore, VisualizationStore ];
}
- static calculateState() {
- return {
- visualizations: VisualizationStore.getState(),
+ static calculateState(prevState) {
+ if (prevState) {
+ return {
+ projects: ProjectStore.getState(),
+ visualizations: VisualizationStore.getState(),
- newModal: false,
- deleteModal: false,
- editModal: false,
- modalData: {}
- };
+ newModal: prevState.newModal,
+ deleteModal: prevState.deleteModal,
+ editModal: prevState.editModal,
+ modalData: prevState.modalData,
+
+ project: prevState.project,
+ reload: prevState.reload
+ };
+ } else {
+ return {
+ projects: ProjectStore.getState(),
+ visualizations: VisualizationStore.getState(),
+
+ newModal: false,
+ deleteModal: false,
+ editModal: false,
+ modalData: {},
+
+ project: {},
+ reload: false
+ };
+ }
}
componentWillMount() {
AppDispatcher.dispatch({
- type: 'visualizations/start-load'
+ type: 'projects/start-load'
+ });
+ }
+
+ componentDidUpdate() {
+ if (this.state.project._id !== this.props.params.project /*|| this.state.reload*/) {
+ this.reloadProject();
+
+ if (this.state.reload) {
+ this.setState({ reload: false });
+ }
+ }
+ }
+
+ loadVisualizations(ids) {
+ if (AppDispatcher.isDispatching()) {
+ // try again later
+ var self = this;
+ setTimeout(function() {
+ self.loadVisualizations(ids);
+ }, 1);
+ } else {
+ AppDispatcher.dispatch({
+ type: 'visualizations/start-load',
+ data: ids
+ });
+ }
+ }
+
+ reloadProject() {
+ // select project by param id
+ this.state.projects.forEach((project) => {
+ if (project._id === this.props.params.project) {
+ // JSON.parse(JSON.stringify(obj)) = deep clone to make also copy of widget objects inside
+ this.setState({ project: JSON.parse(JSON.stringify(project)) });
+
+ // load visualizations
+ this.loadVisualizations(project.visualizations);
+ }
});
}
closeNewModal(data) {
- this.setState({ newModal : false });
-
if (data) {
+ // add project to visualization
+ data.project = this.state.project._id;
+
AppDispatcher.dispatch({
type: 'visualizations/start-add',
data: data
});
}
+
+ this.setState({ newModal: false, reload: data != null });
}
confirmDeleteModal() {
@@ -73,11 +134,24 @@ class Visualizations extends Component {
}
render() {
+ // get visualizations for this project
+ var visualizations = [];
+
+ if (this.state.visualizations && this.state.project.visualizations) {
+ this.state.visualizations.forEach((visualization) => {
+ this.state.project.visualizations.forEach((id) => {
+ if (visualization._id === id) {
+ visualizations.push(visualization);
+ }
+ });
+ });
+ }
+
return (
-
Visualizations
+
{this.state.project.name}
-
+
this.setState({ editModal: true, modalData: this.state.visualizations[index] })} onDelete={index => this.setState({ deleteModal: true, modalData: this.state.visualizations[index] })} />
diff --git a/src/containers/projects.js b/src/containers/projects.js
index 825ca7f..4e6a4b6 100644
--- a/src/containers/projects.js
+++ b/src/containers/projects.js
@@ -9,26 +9,116 @@
import React, { Component } from 'react';
import { Container } from 'flux/utils';
+import { Button, Modal, Glyphicon } from 'react-bootstrap';
-// import AppDispatcher from '../app-dispatcher';
-import VillasStore from '../stores/villas-store';
+import AppDispatcher from '../app-dispatcher';
+import ProjectStore from '../stores/project-store';
+import SimulationStore from '../stores/simulation-store';
+
+import Table from '../components/table';
+import TableColumn from '../components/table-column';
+import NewProjectDialog from '../components/dialog/new-project';
+import EditProjectDialog from '../components/dialog/edit-project';
class Projects extends Component {
static getStores() {
- return [ VillasStore ];
+ return [ ProjectStore, SimulationStore ];
}
static calculateState() {
return {
- villas: VillasStore.getState()
+ projects: ProjectStore.getState(),
+ simulations: SimulationStore.getState(),
+
+ newModal: false,
+ editModal: false,
+ deleteModal: false,
+ modalData: {}
};
}
+ componentWillMount() {
+ AppDispatcher.dispatch({
+ type: 'projects/start-load'
+ });
+
+ AppDispatcher.dispatch({
+ type: 'simulations/start-load'
+ });
+ }
+
+ closeNewModal(data) {
+ this.setState({ newModal: false });
+
+ if (data) {
+ AppDispatcher.dispatch({
+ type: 'projects/start-add',
+ data: data
+ });
+ }
+ }
+
+ confirmDeleteModal() {
+ this.setState({ deleteModal: false });
+
+ AppDispatcher.dispatch({
+ type: 'projects/start-remove',
+ data: this.state.modalData
+ });
+ }
+
+ closeEditModal(data) {
+ this.setState({ editModal: false });
+
+ if (data) {
+ AppDispatcher.dispatch({
+ type: 'projects/start-edit',
+ data: data
+ });
+ }
+ }
+
+ getSimulationName(id) {
+ for (var i = 0; i < this.state.simulations.length; i++) {
+ if (this.state.simulations[i]._id === id) {
+ return this.state.simulations[i].name;
+ }
+ }
+
+ return id;
+ }
+
render() {
return (
Projects
+
+
+ this.getSimulationName(id)} />
+ this.setState({ editModal: true, modalData: this.state.projects[index] })} onDelete={index => this.setState({ deleteModal: true, modalData: this.state.projects[index] })} />
+
+
+
this.setState({ newModal: true })}> Project
+
+
this.closeNewModal(data)} simulations={this.state.simulations} />
+
+ this.closeEditModal(data)} project={this.state.modalData} simulations={this.state.simulations} />
+
+
+
+ Delete Project
+
+
+
+ Are you sure you want to delete the project '{this.state.modalData.name}' ?
+
+
+
+ this.setState({ deleteModal: false})}>Cancel
+ this.confirmDeleteModal()}>Delete
+
+
);
}
diff --git a/src/data-managers/projects-data-manager.js b/src/data-managers/projects-data-manager.js
new file mode 100644
index 0000000..a85801d
--- /dev/null
+++ b/src/data-managers/projects-data-manager.js
@@ -0,0 +1,12 @@
+/**
+ * File: projects-data-manager.js
+ * Author: Markus Grigull
+ * Date: 07.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import RestDataManager from './rest-data-manager';
+
+export default new RestDataManager('project', '/projects');
diff --git a/src/data-managers/rest-data-manager.js b/src/data-managers/rest-data-manager.js
index db92935..0b5d178 100644
--- a/src/data-managers/rest-data-manager.js
+++ b/src/data-managers/rest-data-manager.js
@@ -16,18 +16,34 @@ class RestDataManager {
this.type = type;
}
- load() {
- RestAPI.get(this.url).then(response => {
- AppDispatcher.dispatch({
- type: this.type + 's/loaded',
- data: response[this.type + 's']
+ load(id) {
+ if (id != null) {
+ // load single object
+ RestAPI.get(this.url + '/' + id).then(response => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/loaded',
+ data: response[this.type]
+ });
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/load-error',
+ error: error
+ });
});
- }).catch(error => {
- AppDispatcher.dispatch({
- type: this.type + 's/load-error',
- error: error
+ } else {
+ // load all objects
+ RestAPI.get(this.url).then(response => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/loaded',
+ data: response[this.type + 's']
+ });
+ }).catch(error => {
+ AppDispatcher.dispatch({
+ type: this.type + 's/load-error',
+ error: error
+ });
});
- });
+ }
}
add(object) {
diff --git a/src/data-managers/simulations-data-manager.js b/src/data-managers/simulations-data-manager.js
index 4a9d0bf..d5a606e 100644
--- a/src/data-managers/simulations-data-manager.js
+++ b/src/data-managers/simulations-data-manager.js
@@ -7,6 +7,6 @@
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
- import RestDataManager from './rest-data-manager';
+import RestDataManager from './rest-data-manager';
- export default new RestDataManager('simulation', '/simulations');
+export default new RestDataManager('simulation', '/simulations');
diff --git a/src/router.js b/src/router.js
index 5689e6e..49ed410 100644
--- a/src/router.js
+++ b/src/router.js
@@ -13,9 +13,9 @@ import { Router, Route, hashHistory } from 'react-router';
import App from './containers/app';
import Home from './containers/home';
import Projects from './containers/projects';
+import Project from './containers/project';
import Simulators from './containers/simulators';
import Visualization from './containers/visualization';
-import Visualizations from './containers/visualizations';
import Simulations from './containers/simulations';
import Simulation from './containers/simulation';
@@ -25,10 +25,12 @@ class Root extends Component {
+
+
+
-
diff --git a/src/stores/array-store.js b/src/stores/array-store.js
index 8f2179d..b7c166a 100644
--- a/src/stores/array-store.js
+++ b/src/stores/array-store.js
@@ -23,16 +23,46 @@ class ArrayStore extends ReduceStore {
return [];
}
- reduce(state, action) {
- var array;
+ updateElements(state, newElements) {
+ // search for existing element to update
+ state.forEach((element, index, array) => {
+ newElements.forEach((updateElement, index) => {
+ if (element._id === updateElement._id) {
+ array[index] = element;
+ // remove updated element from update list
+ newElements.splice(index, 1);
+ }
+ });
+ });
+
+ // all elements still in the list will just be added
+ state = state.concat(newElements);
+
+ // announce change to listeners
+ this.__emitChange();
+
+ return state;
+ }
+
+ reduce(state, action) {
switch (action.type) {
case this.type + '/start-load':
- this.dataManager.load();
+ if (Array.isArray(action.data)) {
+ action.data.forEach((id) => {
+ this.dataManager.load(id);
+ });
+ } else {
+ this.dataManager.load(action.data);
+ }
return state;
case this.type + '/loaded':
- return action.data;
+ if (Array.isArray(action.data)) {
+ return this.updateElements(state, action.data);
+ } else {
+ return this.updateElements(state, [action.data]);
+ }
case this.type + '/load-error':
// TODO: Add error message
@@ -43,11 +73,7 @@ class ArrayStore extends ReduceStore {
return state;
case this.type + '/added':
- // signal array change since its not automatically detected
- state.push(action.data);
- this.__emitChange();
-
- return state;
+ return this.updateElements(state, [action.data]);
case this.type + '/add-error':
// TODO: Add error message
@@ -71,14 +97,7 @@ class ArrayStore extends ReduceStore {
return state;
case this.type + '/edited':
- array = state.slice();
- for (var i = 0; i < array.length; i++) {
- if (array[i]._id === action.data._id) {
- array[i] = action.data;
- }
- }
-
- return array;
+ return this.updateElements(state, [action.data]);
case this.type + '/edit-error':
// TODO: Add error message
diff --git a/src/stores/project-store.js b/src/stores/project-store.js
new file mode 100644
index 0000000..405820f
--- /dev/null
+++ b/src/stores/project-store.js
@@ -0,0 +1,13 @@
+/**
+ * File: project-store.js
+ * Author: Markus Grigull
+ * Date: 07.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import ArrayStore from './array-store';
+import ProjectsDataManager from '../data-managers/projects-data-manager';
+
+export default new ArrayStore('projects', ProjectsDataManager);
From 7161ea7adc3a064fdb2809b430ad6b9fc913bb2c Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 8 Mar 2017 15:41:53 +0100
Subject: [PATCH 061/556] Add unique simulator sockets
Add automatic simulator-data load
Add missing widget-value component
---
src/api/websocket-api.js | 16 ++---
src/app-dispatcher.js | 18 +++++-
src/components/widget-value.js | 34 ++++++++++
src/containers/app.js | 62 +++++++++++++++++--
src/containers/project.js | 20 ++----
src/containers/visualization.js | 56 ++++++++---------
src/containers/widget.js | 2 +-
...ager.js => simulator-data-data-manager.js} | 39 ++++++++----
src/stores/simulator-data-store.js | 9 ++-
9 files changed, 178 insertions(+), 78 deletions(-)
create mode 100644 src/components/widget-value.js
rename src/data-managers/{simulator-data-manager.js => simulator-data-data-manager.js} (56%)
diff --git a/src/api/websocket-api.js b/src/api/websocket-api.js
index 33f96b8..c5cad2c 100644
--- a/src/api/websocket-api.js
+++ b/src/api/websocket-api.js
@@ -8,13 +8,9 @@
**********************************************************************************/
class WebsocketAPI {
- constructor() {
- this.sockets = {};
- }
-
- addSocket(endpoint, identifier, callbacks) {
+ addSocket(endpoint, callbacks) {
// create web socket client
- var socket = new WebSocket('ws://' + endpoint, 'live');
+ var socket = new WebSocket(this.getURL(endpoint), 'live');
socket.binaryType = 'arraybuffer';
// register callbacks
@@ -23,13 +19,11 @@ class WebsocketAPI {
if (callbacks.onMessage) socket.addEventListener('message', event => callbacks.onMessage(event));
if (callbacks.onError) socket.addEventListener('error', event => callbacks.onError(event));
- // save socket
- this.sockets[identifier] = socket;
+ return socket;
}
- removeSocket(identifier) {
- this.sockets[identifier].close();
- delete this.sockets[identifier];
+ getURL(endpoint) {
+ return 'ws://' + endpoint;
}
}
diff --git a/src/app-dispatcher.js b/src/app-dispatcher.js
index 689348d..52ba2af 100644
--- a/src/app-dispatcher.js
+++ b/src/app-dispatcher.js
@@ -9,6 +9,20 @@
import { Dispatcher } from 'flux';
-const dispatcher: Dispatcher = new Dispatcher();
+class AppDispatcher extends Dispatcher {
+ dispatch(payload) {
+ if (this.isDispatching()) {
+ // try again later
+ var self = this;
-export default dispatcher;
+ setTimeout(function() {
+ self.dispatch(payload);
+ }, 1);
+ } else {
+ // do actual dispatch
+ super.dispatch(payload);
+ }
+ }
+}
+
+export default new AppDispatcher();
diff --git a/src/components/widget-value.js b/src/components/widget-value.js
new file mode 100644
index 0000000..e016d0a
--- /dev/null
+++ b/src/components/widget-value.js
@@ -0,0 +1,34 @@
+/**
+ * File: widget-value.js
+ * Author: Markus Grigull
+ * Date: 04.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+
+//import EditWidgetValueDialog from './dialog-edit-widget-value';
+
+class WidgetValue extends Component {
+ render() {
+ // calculate value
+ var value = null;
+ const identifier = '58bfd9facd76830327c8b6d4';
+ const signal = 2;
+
+ if (this.props.data && this.props.data[identifier] && this.props.data[identifier].values) {
+ const signalArray = this.props.data[identifier].values[signal];
+ value = signalArray[signalArray.length - 1].y;
+ }
+
+ return (
+
+ {this.props.widget.name}: {value}
+
+ );
+ }
+}
+
+export default WidgetValue;
diff --git a/src/containers/app.js b/src/containers/app.js
index 37acdb1..d5283ac 100644
--- a/src/containers/app.js
+++ b/src/containers/app.js
@@ -12,8 +12,9 @@ import { Container } from 'flux/utils';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
-// import AppDispatcher from '../app-dispatcher';
-import VillasStore from '../stores/villas-store';
+import AppDispatcher from '../app-dispatcher';
+import SimulationStore from '../stores/simulation-store';
+import SimulatorStore from '../stores/simulator-store';
import Header from '../components/header';
import Footer from '../components/footer';
@@ -23,15 +24,68 @@ import '../styles/app.css';
class App extends Component {
static getStores() {
- return [ VillasStore ];
+ return [ SimulationStore, SimulatorStore ];
}
static calculateState() {
return {
- villas: VillasStore.getState()
+ simulators: SimulatorStore.getState(),
+ simulations: SimulationStore.getState()
};
}
+ componentWillMount() {
+ // load all simulators and simulations to fetch simulation data
+ AppDispatcher.dispatch({
+ type: 'simulators/start-load'
+ });
+
+ AppDispatcher.dispatch({
+ type: 'simulations/start-load'
+ });
+ }
+
+ componentDidUpdate() {
+ if (this.state.simulators && this.state.simulations && this.state.simulations.length > 0) {
+ // get list of used simulators
+ var simulators = [];
+
+ this.state.simulations.forEach((simulation) => {
+ // open connection to each simulator running a simulation model
+ simulation.models.forEach((simulationModel) => {
+ // add simulator to list if not already part of
+ const index = simulators.findIndex((element) => {
+ return element.simulator === simulationModel.simulator;
+ });
+
+ if (index === -1) {
+ simulators.push({ simulator: simulationModel.simulator, signals: simulationModel.length });
+ } else {
+ if (simulators[index].length < simulationModel.length) {
+ simulators[index].length = simulationModel.length;
+ }
+ }
+ });
+ });
+
+ // open connection to each simulator
+ this.state.simulators.forEach((simulator) => {
+ const index = simulators.findIndex((element) => {
+ return element.simulator === simulator._id;
+ });
+
+ if (index !== -1) {
+ AppDispatcher.dispatch({
+ type: 'simulatorData/open',
+ identifier: simulator._id,
+ endpoint: simulator.endpoint,
+ signals: simulators[index].signals
+ });
+ }
+ });
+ }
+ }
+
render() {
// get children
var children = this.props.children;
diff --git a/src/containers/project.js b/src/containers/project.js
index 34804d7..910eebe 100644
--- a/src/containers/project.js
+++ b/src/containers/project.js
@@ -71,21 +71,6 @@ class Visualizations extends Component {
}
}
- loadVisualizations(ids) {
- if (AppDispatcher.isDispatching()) {
- // try again later
- var self = this;
- setTimeout(function() {
- self.loadVisualizations(ids);
- }, 1);
- } else {
- AppDispatcher.dispatch({
- type: 'visualizations/start-load',
- data: ids
- });
- }
- }
-
reloadProject() {
// select project by param id
this.state.projects.forEach((project) => {
@@ -94,7 +79,10 @@ class Visualizations extends Component {
this.setState({ project: JSON.parse(JSON.stringify(project)) });
// load visualizations
- this.loadVisualizations(project.visualizations);
+ AppDispatcher.dispatch({
+ type: 'visualizations/start-load',
+ data: project.visualizations
+ });
}
});
}
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index 9fd585f..31bf209 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -15,12 +15,15 @@ import { ContextMenu, MenuItem } from 'react-contextmenu';
import ToolboxItem from '../components/toolbox-item';
import Dropzone from '../components/dropzone';
import Widget from './widget';
+
import VisualizationStore from '../stores/visualization-store';
+import ProjectStore from '../stores/project-store';
+import SimulationStore from '../stores/simulation-store';
import AppDispatcher from '../app-dispatcher';
class Visualization extends Component {
static getStores() {
- return [ VisualizationStore ];
+ return [ VisualizationStore, ProjectStore, SimulationStore ];
}
static calculateState(prevState) {
@@ -38,11 +41,34 @@ class Visualization extends Component {
visualizations: VisualizationStore.getState(),
visualization: {},
+ simulation: null,
editing: false,
grid: false
}
}
+ componentWillMount() {
+ AppDispatcher.dispatch({
+ type: 'visualizations/start-load'
+ });
+ }
+
+ componentDidUpdate() {
+ if (this.state.visualization._id !== this.props.params.visualization) {
+ this.reloadVisualization();
+ }
+ }
+
+ reloadVisualization() {
+ // select visualization by param id
+ this.state.visualizations.forEach((visualization) => {
+ if (visualization._id === this.props.params.visualization) {
+ // JSON.parse(JSON.stringify(obj)) = deep clone to make also copy of widget objects inside
+ this.setState({ visualization: JSON.parse(JSON.stringify(visualization)) });
+ }
+ });
+ }
+
handleDrop(item) {
// add new widget
var widget = {
@@ -99,34 +125,6 @@ class Visualization extends Component {
this.forceUpdate();
}
- componentWillMount() {
- AppDispatcher.dispatch({
- type: 'visualizations/start-load'
- });
-
- AppDispatcher.dispatch({
- type: 'simulatorData/open',
- endpoint: 'localhost:5000',
- identifier: 'RTDS'
- });
- }
-
- componentDidUpdate() {
- if (this.state.visualization._id !== this.props.params.visualization) {
- this.reloadVisualization();
- }
- }
-
- reloadVisualization() {
- // select visualization by param id
- this.state.visualizations.forEach((visualization) => {
- if (visualization._id === this.props.params.visualization) {
- // JSON.parse(JSON.stringify(obj)) = deep clone to make also copy of widget objects inside
- this.setState({ visualization: JSON.parse(JSON.stringify(visualization)) });
- }
- });
- }
-
render() {
return (
diff --git a/src/containers/widget.js b/src/containers/widget.js
index b436075..c24a0a0 100644
--- a/src/containers/widget.js
+++ b/src/containers/widget.js
@@ -84,7 +84,7 @@ class Widget extends Component {
} else {
return (
-
+
);
}
diff --git a/src/data-managers/simulator-data-manager.js b/src/data-managers/simulator-data-data-manager.js
similarity index 56%
rename from src/data-managers/simulator-data-manager.js
rename to src/data-managers/simulator-data-data-manager.js
index 049eda2..2dffa9a 100644
--- a/src/data-managers/simulator-data-manager.js
+++ b/src/data-managers/simulator-data-data-manager.js
@@ -1,5 +1,5 @@
/**
- * File: simulator-data-manager.js
+ * File: simulator-data-data-manager.js
* Author: Markus Grigull
* Date: 03.03.2017
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
@@ -10,34 +10,47 @@
import WebsocketAPI from '../api/websocket-api';
import AppDispatcher from '../app-dispatcher';
-class SimulationDataManager {
- open(endpoint, identifier) {
- WebsocketAPI.addSocket(endpoint, identifier, { onOpen: event => this.onOpen(event), onClose: event => this.onClose(event), onMessage: event => this.onMessage(event) });
+class SimulatorDataDataManager {
+ constructor() {
+ this._sockets = {};
}
- onOpen(event) {
- // TODO: Add identifiers to callbacks
+ open(endpoint, identifier, signals) {
+ // pass signals to onOpen callback
+ if (this._sockets[identifier] != null) {
+ if (this._sockets[identifier].url !== WebsocketAPI.getURL(endpoint)) {
+ // replace connection, since endpoint changed
+ this._sockets.close();
+ this._sockets[identifier] = WebsocketAPI.addSocket(endpoint, { onOpen: (event) => this.onOpen(event, identifier, signals), onClose: (event) => this.onClose(event, identifier), onMessage: (event) => this.onMessage(event, identifier) });
+ }
+ } else {
+ this._sockets[identifier] = WebsocketAPI.addSocket(endpoint, { onOpen: (event) => this.onOpen(event, identifier, signals), onClose: (event) => this.onClose(event, identifier), onMessage: (event) => this.onMessage(event, identifier) });
+ }
+ }
+
+ onOpen(event, identifier, signals) {
AppDispatcher.dispatch({
type: 'simulatorData/opened',
- identifier: 'RTDS',
- signals: 8
+ identifier: identifier,
+ signals: signals
});
}
- onClose(event) {
+ onClose(event, identifier) {
AppDispatcher.dispatch({
- type: 'simulatorData/closed'
+ type: 'simulatorData/closed',
+ identifier: identifier
});
}
- onMessage(event) {
+ onMessage(event, identifier) {
var message = this.bufferToMessage(event.data);
AppDispatcher.dispatch({
type: 'simulatorData/data-changed',
data: message,
- identifier: 'RTDS'
+ identifier: identifier
});
}
@@ -69,4 +82,4 @@ class SimulationDataManager {
}
}
-export default new SimulationDataManager();
+export default new SimulatorDataDataManager();
diff --git a/src/stores/simulator-data-store.js b/src/stores/simulator-data-store.js
index 38b69a3..c14644f 100644
--- a/src/stores/simulator-data-store.js
+++ b/src/stores/simulator-data-store.js
@@ -10,7 +10,7 @@
import { ReduceStore } from 'flux/utils';
import AppDispatcher from '../app-dispatcher';
-import SimulatorDataManager from '../data-managers/simulator-data-manager';
+import SimulatorDataDataManager from '../data-managers/simulator-data-data-manager';
const MAX_VALUES = 10000;
@@ -28,7 +28,7 @@ class SimulationDataStore extends ReduceStore {
switch (action.type) {
case 'simulatorData/open':
- SimulatorDataManager.open(action.endpoint, action.identifier);
+ SimulatorDataDataManager.open(action.endpoint, action.identifier, action.signals);
return state;
case 'simulatorData/opened':
@@ -63,6 +63,11 @@ class SimulationDataStore extends ReduceStore {
return state;
case 'simulatorData/closed':
+ // close and delete socket
+ state[action.identifier].close();
+ state[action.identifier] = null;
+
+ this.__emitChange();
return state;
default:
From 24d009e214a9ad8b351e415fd92b78b284c80c85 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 8 Mar 2017 20:30:23 +0100
Subject: [PATCH 062/556] Add edit dialog to widgets and value-widget
Data and simulation is passed properly to widgets
---
src/components/dialog/edit-widget-value.js | 106 ++++++++-------------
src/components/dialog/edit-widget.js | 95 ++++++++++++++++++
src/components/widget-value.js | 11 +--
src/containers/visualization.js | 80 +++++++++++++---
src/containers/widget.js | 4 +-
5 files changed, 205 insertions(+), 91 deletions(-)
create mode 100644 src/components/dialog/edit-widget.js
diff --git a/src/components/dialog/edit-widget-value.js b/src/components/dialog/edit-widget-value.js
index 1fa5de8..7f16a03 100644
--- a/src/components/dialog/edit-widget-value.js
+++ b/src/components/dialog/edit-widget-value.js
@@ -7,86 +7,58 @@
* Unauthorized copying of this file, via any medium is strictly prohibited.
**********************************************************************************/
-import React, { Component, PropTypes } from 'react';
+import React, { Component } from 'react';
import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
-import Dialog from './dialog';
-
-class EditWidgetValueDialog extends Component {
- static propTypes = {
- show: PropTypes.bool.isRequired,
- onClose: PropTypes.func.isRequired
- };
-
- valid: false;
-
+class EditValueWidget extends Component {
constructor(props) {
super(props);
this.state = {
- name: '',
- simulator: '',
- signal: 0
- }
+ widget: {
+ simulator: '',
+ signal: 0
+ }
+ };
}
- onClose(canceled) {
- if (canceled === false) {
- this.props.onClose(this.state);
- } else {
- this.props.onClose();
- }
- }
-
- handleChange(e) {
- this.setState({ [e.target.id]: e.target.value });
- }
-
- resetState() {
- this.setState({ name: '' });
- }
-
- validateForm(target) {
- // check all controls
- var name = true;
-
- if (this.state.name === '') {
- name = false;
- }
-
- this.valid = name;
-
- // return state to control
- if (target === 'name') return name ? "success" : "error";
-
- return "success";
+ componentWillReceiveProps(nextProps) {
+ this.setState({ widget: nextProps.widget });
}
render() {
+ // get selected simulation model
+ var simulationModel = {};
+
+ if (this.props.simulation) {
+ this.props.simulation.models.forEach((model) => {
+ if (model.simulation === this.state.widget.simulation) {
+ simulationModel = model;
+ }
+ });
+ }
+
return (
- this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
-
-
- Name
- this.handleChange(e)} />
-
-
-
- Simulator
-
- RTDS
- Opal
-
-
-
- Signal
- this.handleChange(e)} />
-
-
-
-
+
+
+ Simulator
+ this.props.handleChange(e)}>
+ {this.props.simulation.models.map((model, index) => (
+ {model.name}
+ ))}
+
+
+
+ Signal
+ this.props.handleChange(e)}>
+ {simulationModel.mapping.map((signal, index) => (
+ {simulationModel.mapping[index].name}
+ ))}
+
+
+
);
}
}
-export default EditWidgetValueDialog;
+export default EditValueWidget;
diff --git a/src/components/dialog/edit-widget.js b/src/components/dialog/edit-widget.js
new file mode 100644
index 0000000..c777466
--- /dev/null
+++ b/src/components/dialog/edit-widget.js
@@ -0,0 +1,95 @@
+/**
+ * File: edit-widget.js
+ * Author: Markus Grigull
+ * Date: 08.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component, PropTypes } from 'react';
+import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+import Dialog from './dialog';
+
+import EditValueWidget from './edit-widget-value';
+
+class EditWidgetDialog extends Component {
+ static propTypes = {
+ show: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired
+ };
+
+ valid: true;
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ widget: {
+ name: '',
+ simulator: '',
+ signal: 0
+ }
+ };
+ }
+
+ onClose(canceled) {
+ if (canceled === false) {
+ this.props.onClose(this.state.widget);
+ } else {
+ this.props.onClose();
+ }
+ }
+
+ handleChange(e) {
+ var widget = this.state.widget;
+ widget[e.target.id] = e.target.value;
+ this.setState({ widget: widget });
+
+ console.log(this.state.widget);
+ }
+
+ resetState() {
+ this.setState({ widget: this.props.widget });
+ }
+
+ validateForm(target) {
+ // check all controls
+ var name = true;
+
+ if (this.state.name === '') {
+ name = false;
+ }
+
+ this.valid = name;
+
+ // return state to control
+ if (target === 'name') return name ? "success" : "error";
+ }
+
+ render() {
+ // get widget part
+ var widgetDialog = null;
+
+ if (this.props.widget && this.props.widget.type === 'Value') {
+ widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e) => this.handleChange(e)} />;
+ }
+
+ return (
+ this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
+
+
+ Name
+ this.handleChange(e)} />
+
+
+
+ {widgetDialog}
+
+
+ );
+ }
+}
+
+export default EditWidgetDialog;
diff --git a/src/components/widget-value.js b/src/components/widget-value.js
index e016d0a..92987b6 100644
--- a/src/components/widget-value.js
+++ b/src/components/widget-value.js
@@ -9,23 +9,20 @@
import React, { Component } from 'react';
-//import EditWidgetValueDialog from './dialog-edit-widget-value';
-
class WidgetValue extends Component {
render() {
// calculate value
var value = null;
- const identifier = '58bfd9facd76830327c8b6d4';
- const signal = 2;
+ const widget = this.props.widget;
- if (this.props.data && this.props.data[identifier] && this.props.data[identifier].values) {
- const signalArray = this.props.data[identifier].values[signal];
+ if (this.props.data && this.props.data[widget.simulator] && this.props.data[widget.simulator].values) {
+ const signalArray = this.props.data[widget.simulator].values[widget.signal];
value = signalArray[signalArray.length - 1].y;
}
return (
- {this.props.widget.name}: {value}
+ {widget.name}: {value}
);
}
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index 31bf209..e1fb132 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -15,6 +15,7 @@ import { ContextMenu, MenuItem } from 'react-contextmenu';
import ToolboxItem from '../components/toolbox-item';
import Dropzone from '../components/dropzone';
import Widget from './widget';
+import EditWidget from '../components/dialog/edit-widget';
import VisualizationStore from '../stores/visualization-store';
import ProjectStore from '../stores/project-store';
@@ -27,24 +28,25 @@ class Visualization extends Component {
}
static calculateState(prevState) {
- if (prevState) {
- return {
- visualizations: VisualizationStore.getState(),
-
- visualization: prevState.visualization,
- editing: prevState.editing,
- grid: prevState.grid
- };
+ if (prevState == null) {
+ prevState = {};
}
return {
visualizations: VisualizationStore.getState(),
+ projects: ProjectStore.getState(),
+ simulations: SimulationStore.getState(),
- visualization: {},
- simulation: null,
- editing: false,
- grid: false
- }
+ visualization: prevState.visualization || {},
+ project: prevState.project || null,
+ simulation: prevState.simulation || null,
+ editing: prevState.editing || false,
+ grid: prevState.grid || false,
+
+ editModal: prevState.editModal || false,
+ modalData: prevState.modalData || null,
+ modalIndex: prevState.modalIndex || null
+ };
}
componentWillMount() {
@@ -57,6 +59,29 @@ class Visualization extends Component {
if (this.state.visualization._id !== this.props.params.visualization) {
this.reloadVisualization();
}
+
+ // load depending project
+ if (this.state.project == null && this.state.projects) {
+ this.state.projects.forEach((project) => {
+ if (project._id === this.state.visualization.project) {
+ this.setState({ project: project, simulation: null });
+
+ AppDispatcher.dispatch({
+ type: 'simulations/start-load',
+ data: project.simulation
+ });
+ }
+ });
+ }
+
+ // load depending simulation
+ if (this.state.simulation == null && this.state.simulations && this.state.project) {
+ this.state.simulations.forEach((simulation) => {
+ if (simulation._id === this.state.project.simulation) {
+ this.setState({ simulation: simulation });
+ }
+ });
+ }
}
reloadVisualization() {
@@ -64,7 +89,12 @@ class Visualization extends Component {
this.state.visualizations.forEach((visualization) => {
if (visualization._id === this.props.params.visualization) {
// JSON.parse(JSON.stringify(obj)) = deep clone to make also copy of widget objects inside
- this.setState({ visualization: JSON.parse(JSON.stringify(visualization)) });
+ this.setState({ visualization: JSON.parse(JSON.stringify(visualization)), project: null });
+
+ AppDispatcher.dispatch({
+ type: 'projects/start-load',
+ data: visualization.project
+ });
}
});
}
@@ -81,6 +111,12 @@ class Visualization extends Component {
z: 0
};
+ // set type specific properties
+ if (item.name === 'Value') {
+ widget.simulator = this.state.simulation.models[0].simulator;
+ widget.signal = 0;
+ }
+
var visualization = this.state.visualization;
visualization.widgets.push(widget);
@@ -97,7 +133,19 @@ class Visualization extends Component {
}
editWidget(e, data) {
+ this.setState({ editModal: true, modalData: this.state.visualization.widgets[data.index], modalIndex: data.index });
+ }
+ closeEdit(data) {
+ if (data) {
+ // save changes temporarily
+ var visualization = this.state.visualization;
+ visualization.widgets[this.state.modalIndex] = data;
+
+ this.setState({ editModal: false, visualization: visualization });
+ } else {
+ this.setState({ editModal: false });
+ }
}
deleteWidget(e, data) {
@@ -155,7 +203,7 @@ class Visualization extends Component {
this.handleDrop(item)} editing={this.state.editing}>
{this.state.visualization.widgets != null &&
this.state.visualization.widgets.map((widget, index) => (
- this.widgetChange(w, i)} editing={this.state.editing} index={index} grid={this.state.grid} />
+ this.widgetChange(w, i)} editing={this.state.editing} index={index} grid={this.state.grid} />
))}
@@ -166,6 +214,8 @@ class Visualization extends Component {
this.deleteWidget(e, data)}>Delete
))}
+
+ this.closeEdit(data)} widget={this.state.modalData} simulation={this.state.simulation} />
);
diff --git a/src/containers/widget.js b/src/containers/widget.js
index c24a0a0..67e7bd4 100644
--- a/src/containers/widget.js
+++ b/src/containers/widget.js
@@ -77,14 +77,14 @@ class Widget extends Component {
resizeGrid={grid}
>
);
} else {
return (
-
+
);
}
From 98909301b964730019a824bc6447bd17bf12789d Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Mon, 13 Mar 2017 16:39:43 +0100
Subject: [PATCH 063/556] Add plot widget
Plot edit dialog not created yet
---
src/components/dialog/edit-widget-plot.js | 0
src/components/dialog/edit-widget.js | 1 +
src/components/widget-plot.js | 66 +++++++++++++++++++++++
src/containers/visualization.js | 5 ++
src/containers/widget.js | 18 +++++--
src/stores/simulator-data-store.js | 11 ++--
src/styles/app.css | 2 +
src/styles/widgets.css | 2 +
8 files changed, 97 insertions(+), 8 deletions(-)
create mode 100644 src/components/dialog/edit-widget-plot.js
create mode 100644 src/components/widget-plot.js
diff --git a/src/components/dialog/edit-widget-plot.js b/src/components/dialog/edit-widget-plot.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/dialog/edit-widget.js b/src/components/dialog/edit-widget.js
index c777466..21ba51b 100644
--- a/src/components/dialog/edit-widget.js
+++ b/src/components/dialog/edit-widget.js
@@ -13,6 +13,7 @@ import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
import Dialog from './dialog';
import EditValueWidget from './edit-widget-value';
+import editPlotWidget from './edit-widget-plot';
class EditWidgetDialog extends Component {
static propTypes = {
diff --git a/src/components/widget-plot.js b/src/components/widget-plot.js
new file mode 100644
index 0000000..fad5f0c
--- /dev/null
+++ b/src/components/widget-plot.js
@@ -0,0 +1,66 @@
+/**
+ * File: widget-plot.js
+ * Author: Markus Grigull
+ * Date: 08.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { LineChart } from 'rd3';
+
+class WidgetPlot extends Component {
+ render() {
+ // get selected simulation model
+ const widget = this.props.widget;
+ var simulationModel;
+
+ if (this.props.simulation && this.props.simulation.models && this.props.data[widget.simulator]) {
+ this.props.simulation.models.forEach((model) => {
+ if (model.simulator === widget.simulator) {
+ simulationModel = model;
+ }
+ });
+ } else {
+ return (
);
+ }
+
+ if (widget.plotType === 'table') {
+ return (
+ Table
+ );
+ } else if (widget.plotType === 'multiple') {
+ // get selected data
+ var lineData = [];
+ const latestTimestamp = this.props.data[widget.simulator].values[0][this.props.data[widget.simulator].values[0].length - 1].x;
+
+ widget.signals.forEach((signal) => {
+ lineData.push({
+ name: simulationModel.mapping[signal].name,
+ values: this.props.data[widget.simulator].values[signal]
+ });
+ });
+
+ return (
+
+ {return new Date(d.x);}}
+ hoverAnimation={false}
+ circleRadius={0}
+ domain={{ x: [latestTimestamp - 10000, latestTimestamp] }}
+ />
+
+ );
+ } else {
+ return (Error
);
+ }
+ }
+}
+
+export default WidgetPlot;
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index e1fb132..13dea0f 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -115,6 +115,10 @@ class Visualization extends Component {
if (item.name === 'Value') {
widget.simulator = this.state.simulation.models[0].simulator;
widget.signal = 0;
+ } else if (item.name === 'Plot') {
+ widget.simulator = this.state.simulation.models[0].simulator;
+ widget.plotType = 'multiple';
+ widget.signals = [ 0 ];
}
var visualization = this.state.visualization;
@@ -197,6 +201,7 @@ class Visualization extends Component {
{this.state.editing &&
+
}
diff --git a/src/containers/widget.js b/src/containers/widget.js
index 67e7bd4..d6ac0d8 100644
--- a/src/containers/widget.js
+++ b/src/containers/widget.js
@@ -14,6 +14,7 @@ import Rnd from 'react-rnd';
import SimulatorDataStore from '../stores/simulator-data-store';
import WidgetValue from '../components/widget-value';
+import WidgetPlot from '../components/widget-plot';
import '../styles/widgets.css';
@@ -57,13 +58,22 @@ class Widget extends Component {
}
render() {
- const widget = this.props.data;
-
+ // configure grid
var grid = this.props.grid;
if (!grid) {
grid = [ 1, 1 ];
}
+ // get widget element
+ const widget = this.props.data;
+ var element = null;
+
+ if (widget.type === 'Value') {
+ element =
+ } else if (widget.type === 'Plot') {
+ element =
+ }
+
if (this.props.editing) {
return (
);
} else {
return (
-
+ {element}
);
}
diff --git a/src/stores/simulator-data-store.js b/src/stores/simulator-data-store.js
index c14644f..1fe5816 100644
--- a/src/stores/simulator-data-store.js
+++ b/src/stores/simulator-data-store.js
@@ -12,7 +12,7 @@ import { ReduceStore } from 'flux/utils';
import AppDispatcher from '../app-dispatcher';
import SimulatorDataDataManager from '../data-managers/simulator-data-data-manager';
-const MAX_VALUES = 10000;
+const MAX_VALUES = 100;
class SimulationDataStore extends ReduceStore {
constructor() {
@@ -64,10 +64,13 @@ class SimulationDataStore extends ReduceStore {
case 'simulatorData/closed':
// close and delete socket
- state[action.identifier].close();
- state[action.identifier] = null;
+ if (state[action.identifier]) {
+ state[action.identifier].close();
+ state[action.identifier] = null;
+
+ this.__emitChange();
+ }
- this.__emitChange();
return state;
default:
diff --git a/src/styles/app.css b/src/styles/app.css
index c1aad96..b7d16e3 100644
--- a/src/styles/app.css
+++ b/src/styles/app.css
@@ -142,6 +142,8 @@ body {
padding: 5px 10px;
+ margin-right: 10px;
+
border: 1px solid gray;
cursor: move;
diff --git a/src/styles/widgets.css b/src/styles/widgets.css
index 7fe801b..fb9a781 100644
--- a/src/styles/widgets.css
+++ b/src/styles/widgets.css
@@ -12,6 +12,8 @@
height: 100%;
border: 1px solid lightgray;
+
+ padding: 3px 6px;
}
.react-contextmenu {
From 913280af2e318eed0c1a4272de83da91df714d24 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Mon, 13 Mar 2017 20:42:26 +0100
Subject: [PATCH 064/556] Add plot widget edit dialog for multiple plot type
---
src/components/dialog/edit-widget-plot.js | 89 +++++++++++++++++++++++
src/components/dialog/edit-widget.js | 14 ++--
2 files changed, 98 insertions(+), 5 deletions(-)
diff --git a/src/components/dialog/edit-widget-plot.js b/src/components/dialog/edit-widget-plot.js
index e69de29..837e15c 100644
--- a/src/components/dialog/edit-widget-plot.js
+++ b/src/components/dialog/edit-widget-plot.js
@@ -0,0 +1,89 @@
+/**
+ * File: edit-widget-plot.js
+ * Author: Markus Grigull
+ * Date: 13.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+import { FormGroup, FormControl, ControlLabel, Checkbox } from 'react-bootstrap';
+
+class EditPlotWidget extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ widget: {
+ simulator: '',
+ plotType: '',
+ signals: []
+ }
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({ widget: nextProps.widget });
+ }
+
+ handleSignalChange(e, index) {
+ var signals = this.state.widget.signals;
+
+ if (e.target.checked) {
+ // add signal
+ signals.push(index);
+ } else {
+ // remove signal
+ const pos = signals.indexOf(index);
+ if (pos > -1) {
+ signals.splice(pos, 1);
+ }
+ }
+
+ this.props.handleChange({ target: { id: 'signals', value: signals } });
+ }
+
+ render() {
+ // get selected simulation model
+ var simulationModel = {};
+
+ if (this.props.simulation) {
+ this.props.simulation.models.forEach((model) => {
+ if (model.simulation === this.state.widget.simulation) {
+ simulationModel = model;
+ }
+ });
+ }
+
+ return (
+
+
+ Simulator
+ this.props.handleChange(e)}>
+ {this.props.simulation.models.map((model, index) => (
+ {model.name}
+ ))}
+
+
+
+ Type
+ this.props.handleChange(e)}>
+ Multiple
+ Table
+
+
+ {this.state.widget.plotType === 'multiple' &&
+
+ Signals
+ {simulationModel.mapping.map((signal, index) => (
+ this.handleSignalChange(e, index)}>{signal.name}
+ ))}
+
+ }
+
+ );
+ }
+}
+
+export default EditPlotWidget;
diff --git a/src/components/dialog/edit-widget.js b/src/components/dialog/edit-widget.js
index 21ba51b..bd9dbc5 100644
--- a/src/components/dialog/edit-widget.js
+++ b/src/components/dialog/edit-widget.js
@@ -13,7 +13,7 @@ import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
import Dialog from './dialog';
import EditValueWidget from './edit-widget-value';
-import editPlotWidget from './edit-widget-plot';
+import EditPlotWidget from './edit-widget-plot';
class EditWidgetDialog extends Component {
static propTypes = {
@@ -43,12 +43,12 @@ class EditWidgetDialog extends Component {
}
}
- handleChange(e) {
+ handleChange(e, index) {
var widget = this.state.widget;
widget[e.target.id] = e.target.value;
this.setState({ widget: widget });
- console.log(this.state.widget);
+ //console.log(this.state.widget);
}
resetState() {
@@ -73,8 +73,12 @@ class EditWidgetDialog extends Component {
// get widget part
var widgetDialog = null;
- if (this.props.widget && this.props.widget.type === 'Value') {
- widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e) => this.handleChange(e)} />;
+ if (this.props.widget) {
+ if (this.props.widget.type === 'Value') {
+ widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e) => this.handleChange(e)} />;
+ } else if (this.props.widget.type === 'Plot') {
+ widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />;
+ }
}
return (
From 42e4afbed87af1a296cb9c774c1ca7ee4c1ab504 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Tue, 14 Mar 2017 19:00:13 +0100
Subject: [PATCH 065/556] Increase widget performance
Make rest-api more universal usable
---
src/api/rest-api.js | 15 +--
src/components/widget-plot.js | 110 ++++++++++--------
src/components/widget-value.js | 31 +++--
src/containers/visualization.js | 4 +-
src/containers/widget.js | 4 +-
src/data-managers/rest-data-manager.js | 16 ++-
.../simulator-data-data-manager.js | 6 +
src/stores/simulator-data-store.js | 37 +++---
8 files changed, 135 insertions(+), 88 deletions(-)
diff --git a/src/api/rest-api.js b/src/api/rest-api.js
index 40329c2..d01e996 100644
--- a/src/api/rest-api.js
+++ b/src/api/rest-api.js
@@ -10,17 +10,10 @@
import request from 'superagent/lib/client';
import Promise from 'es6-promise';
-const API_URL = 'http://localhost:4000/api/v1';
-
-function makeURL(part) {
- // TODO: Add / if missing at front of part
- return API_URL + part;
-}
-
class RestAPI {
get(url) {
return new Promise(function (resolve, reject) {
- request.get(makeURL(url)).end(function (error, res) {
+ request.get(url).set('Access-Control-Allow-Origin', '*').end(function (error, res) {
if (res == null || res.status !== 200) {
reject(error);
} else {
@@ -32,7 +25,7 @@ class RestAPI {
post(url, body) {
return new Promise(function (resolve, reject) {
- request.post(makeURL(url)).send(body).end(function (error, res) {
+ request.post(url).send(body).end(function (error, res) {
if (res == null || res.status !== 200) {
reject(error);
} else {
@@ -44,7 +37,7 @@ class RestAPI {
delete(url) {
return new Promise(function (resolve, reject) {
- request.delete(makeURL(url)).end(function (error, res) {
+ request.delete(url).end(function (error, res) {
if (res == null || res.status !== 200) {
reject(error);
} else {
@@ -56,7 +49,7 @@ class RestAPI {
put(url, body) {
return new Promise(function (resolve, reject) {
- request.put(makeURL(url)).send(body).end(function (error, res) {
+ request.put(url).send(body).end(function (error, res) {
if (res == null || res.status !== 200) {
reject(error);
} else {
diff --git a/src/components/widget-plot.js b/src/components/widget-plot.js
index fad5f0c..140a0f6 100644
--- a/src/components/widget-plot.js
+++ b/src/components/widget-plot.js
@@ -11,55 +11,73 @@ import React, { Component } from 'react';
import { LineChart } from 'rd3';
class WidgetPlot extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ values: [],
+ firstTimestamp: 0,
+ latestTimestamp: 0,
+ sequence: null
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ // check data
+ const simulator = nextProps.widget.simulator;
+
+ if (nextProps.simulation == null || nextProps.data == null || nextProps.data[simulator] == null || nextProps.data[simulator].length === 0 || nextProps.data[simulator].values[0].length === 0) {
+ // clear values
+ this.setState({ values: [], sequence: null });
+ return;
+ }
+
+ // check if new data, otherwise skip
+ if (this.state.sequence >= nextProps.data[simulator].sequence) {
+ return;
+ }
+
+ // get timestamps
+ const latestTimestamp = nextProps.data[simulator].values[0][nextProps.data[simulator].values[0].length - 1].x;
+ const firstTimestamp = latestTimestamp - nextProps.widget.time * 100;
+
+ // find element index representing firstTimestamp
+ const firstIndex = nextProps.data[simulator].values[0].findIndex((value) => {
+ return value.x >= firstTimestamp;
+ });
+
+ // copy all values for each signal in time region
+ var values = [];
+
+ nextProps.widget.signals.forEach((signal) => {
+ values.push({
+ values: nextProps.data[simulator].values[signal].slice(firstIndex, nextProps.data[simulator].values[signal].length - 1)
+ });
+ });
+
+ this.setState({ values: values, firstTimestamp: firstTimestamp, latestTimestamp: latestTimestamp, sequence: nextProps.data[simulator].sequence });
+ }
+
render() {
- // get selected simulation model
- const widget = this.props.widget;
- var simulationModel;
-
- if (this.props.simulation && this.props.simulation.models && this.props.data[widget.simulator]) {
- this.props.simulation.models.forEach((model) => {
- if (model.simulator === widget.simulator) {
- simulationModel = model;
- }
- });
- } else {
- return (
);
+ if (this.state.sequence == null) {
+ return (Empty
);
}
- if (widget.plotType === 'table') {
- return (
- Table
- );
- } else if (widget.plotType === 'multiple') {
- // get selected data
- var lineData = [];
- const latestTimestamp = this.props.data[widget.simulator].values[0][this.props.data[widget.simulator].values[0].length - 1].x;
-
- widget.signals.forEach((signal) => {
- lineData.push({
- name: simulationModel.mapping[signal].name,
- values: this.props.data[widget.simulator].values[signal]
- });
- });
-
- return (
-
- {return new Date(d.x);}}
- hoverAnimation={false}
- circleRadius={0}
- domain={{ x: [latestTimestamp - 10000, latestTimestamp] }}
- />
-
- );
- } else {
- return (Error
);
- }
+ return (
+
+ {return new Date(d.x);}}
+ hoverAnimation={false}
+ circleRadius={0}
+ domain={{ x: [this.state.firstTimestamp, this.state.latestTimestamp] }}
+ />
+
+ );
}
}
diff --git a/src/components/widget-value.js b/src/components/widget-value.js
index 92987b6..c096695 100644
--- a/src/components/widget-value.js
+++ b/src/components/widget-value.js
@@ -10,19 +10,34 @@
import React, { Component } from 'react';
class WidgetValue extends Component {
- render() {
- // calculate value
- var value = null;
- const widget = this.props.widget;
+ constructor(props) {
+ super(props);
- if (this.props.data && this.props.data[widget.simulator] && this.props.data[widget.simulator].values) {
- const signalArray = this.props.data[widget.simulator].values[widget.signal];
- value = signalArray[signalArray.length - 1].y;
+ this.state = {
+ value: ''
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ // update value
+ const simulator = nextProps.widget.simulator;
+
+ if (nextProps.data == null || nextProps.data[simulator] == null || nextProps.data[simulator].values == null) {
+ this.setState({ value: '' });
+ return;
}
+ // check if value has changed
+ const signal = nextProps.data[simulator].values[nextProps.widget.signal];
+ if (this.state.value !== signal[signal.length - 1].y) {
+ this.setState({ value: signal[signal.length - 1].y });
+ }
+ }
+
+ render() {
return (
- {widget.name}: {value}
+ {this.props.widget.name}: {this.state.value}
);
}
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index 13dea0f..827d57d 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -117,8 +117,10 @@ class Visualization extends Component {
widget.signal = 0;
} else if (item.name === 'Plot') {
widget.simulator = this.state.simulation.models[0].simulator;
- widget.plotType = 'multiple';
widget.signals = [ 0 ];
+ widget.time = 300;
+ widget.width = 400;
+ widget.height = 200;
}
var visualization = this.state.visualization;
diff --git a/src/containers/widget.js b/src/containers/widget.js
index d6ac0d8..680cc6f 100644
--- a/src/containers/widget.js
+++ b/src/containers/widget.js
@@ -69,9 +69,9 @@ class Widget extends Component {
var element = null;
if (widget.type === 'Value') {
- element =
+ element =
} else if (widget.type === 'Plot') {
- element =
+ element =
}
if (this.props.editing) {
diff --git a/src/data-managers/rest-data-manager.js b/src/data-managers/rest-data-manager.js
index 0b5d178..5c5c68c 100644
--- a/src/data-managers/rest-data-manager.js
+++ b/src/data-managers/rest-data-manager.js
@@ -10,16 +10,22 @@
import RestAPI from '../api/rest-api';
import AppDispatcher from '../app-dispatcher';
+const API_URL = 'http://localhost:4000/api/v1';
+
class RestDataManager {
constructor(type, url) {
this.url = url;
this.type = type;
}
+ makeURL(part) {
+ return API_URL + part;
+ }
+
load(id) {
if (id != null) {
// load single object
- RestAPI.get(this.url + '/' + id).then(response => {
+ RestAPI.get(this.makeURL(this.url + '/' + id)).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/loaded',
data: response[this.type]
@@ -32,7 +38,7 @@ class RestDataManager {
});
} else {
// load all objects
- RestAPI.get(this.url).then(response => {
+ RestAPI.get(this.makeURL(this.url)).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/loaded',
data: response[this.type + 's']
@@ -50,7 +56,7 @@ class RestDataManager {
var obj = {};
obj[this.type] = object;
- RestAPI.post(this.url, obj).then(response => {
+ RestAPI.post(this.makeURL(this.url), obj).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/added',
data: response[this.type]
@@ -64,7 +70,7 @@ class RestDataManager {
}
remove(object) {
- RestAPI.delete(this.url + '/' + object._id).then(response => {
+ RestAPI.delete(this.makeURL(this.url + '/' + object._id)).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/removed',
data: response[this.type],
@@ -82,7 +88,7 @@ class RestDataManager {
var obj = {};
obj[this.type] = object;
- RestAPI.put(this.url + '/' + object._id, obj).then(response => {
+ RestAPI.put(this.makeURL(this.url + '/' + object._id), obj).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/edited',
data: response[this.type]
diff --git a/src/data-managers/simulator-data-data-manager.js b/src/data-managers/simulator-data-data-manager.js
index 2dffa9a..aded151 100644
--- a/src/data-managers/simulator-data-data-manager.js
+++ b/src/data-managers/simulator-data-data-manager.js
@@ -23,9 +23,13 @@ class SimulatorDataDataManager {
this._sockets.close();
this._sockets[identifier] = WebsocketAPI.addSocket(endpoint, { onOpen: (event) => this.onOpen(event, identifier, signals), onClose: (event) => this.onClose(event, identifier), onMessage: (event) => this.onMessage(event, identifier) });
+
+ console.log('Modified socket');
}
} else {
this._sockets[identifier] = WebsocketAPI.addSocket(endpoint, { onOpen: (event) => this.onOpen(event, identifier, signals), onClose: (event) => this.onClose(event, identifier), onMessage: (event) => this.onMessage(event, identifier) });
+
+ console.log('New socket');
}
}
@@ -47,6 +51,8 @@ class SimulatorDataDataManager {
onMessage(event, identifier) {
var message = this.bufferToMessage(event.data);
+ //console.log(message);
+
AppDispatcher.dispatch({
type: 'simulatorData/data-changed',
data: message,
diff --git a/src/stores/simulator-data-store.js b/src/stores/simulator-data-store.js
index 1fe5816..fb97e8f 100644
--- a/src/stores/simulator-data-store.js
+++ b/src/stores/simulator-data-store.js
@@ -12,7 +12,7 @@ import { ReduceStore } from 'flux/utils';
import AppDispatcher from '../app-dispatcher';
import SimulatorDataDataManager from '../data-managers/simulator-data-data-manager';
-const MAX_VALUES = 100;
+const MAX_VALUES = 1000;
class SimulationDataStore extends ReduceStore {
constructor() {
@@ -39,27 +39,34 @@ class SimulationDataStore extends ReduceStore {
state[action.identifier].values.push([]);
}
+ console.log('Socket opened');
+
return state;
case 'simulatorData/data-changed':
- // add data to simulator
- for (i = 0; i < state[action.identifier].signals; i++) {
- state[action.identifier].values[i].push({ x: action.data.timestamp, y: action.data.values[i] });
+ // only add data, if newer than current
+ if (state[action.identifier].sequence < action.data.sequence) {
+ // add data to simulator
+ for (i = 0; i < state[action.identifier].signals; i++) {
+ state[action.identifier].values[i].push({ x: action.data.timestamp, y: action.data.values[i] });
- // erase old values
- if (state[action.identifier].values[i].length > MAX_VALUES) {
- const pos = state[action.identifier].values[i].length - MAX_VALUES;
- state[action.identifier].values[i].splice(0, pos);
+ // erase old values
+ if (state[action.identifier].values[i].length > MAX_VALUES) {
+ const pos = state[action.identifier].values[i].length - MAX_VALUES;
+ state[action.identifier].values[i].splice(0, pos);
+ }
}
+
+ // update metadata
+ state[action.identifier].timestamp = action.data.timestamp;
+ state[action.identifier].sequence = action.data.sequence;
+
+ // explicit call to prevent array copy
+ this.__emitChange();
+ } else {
+ console.log('same sequence');
}
- // update metadata
- state[action.identifier].timestamp = action.data.timestamp;
- state[action.identifier].sequence = action.data.sequence;
-
- // explicit call to prevent array copy
- this.__emitChange();
-
return state;
case 'simulatorData/closed':
From 245188e1df4a202a62ed3b9d3dcf48d83d2b2e1e Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Tue, 14 Mar 2017 21:53:53 +0100
Subject: [PATCH 066/556] Add table widget
---
src/components/dialog/edit-widget-table.js | 55 +++++++++++++++++
src/components/dialog/edit-widget.js | 3 +
src/components/widget-table.js | 72 ++++++++++++++++++++++
src/containers/visualization.js | 5 ++
src/containers/widget.js | 4 ++
5 files changed, 139 insertions(+)
create mode 100644 src/components/dialog/edit-widget-table.js
create mode 100644 src/components/widget-table.js
diff --git a/src/components/dialog/edit-widget-table.js b/src/components/dialog/edit-widget-table.js
new file mode 100644
index 0000000..81d24a8
--- /dev/null
+++ b/src/components/dialog/edit-widget-table.js
@@ -0,0 +1,55 @@
+/**
+ * File: edit-widget-table.js
+ * Author: Markus Grigull
+ * Date: 14.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+ import React, { Component } from 'react';
+ import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
+
+ class EditTableWidget extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ widget: {
+ simulator: ''
+ }
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({ widget: nextProps.widget });
+ }
+
+ render() {
+ // get selected simulation model
+ var simulationModel = {};
+
+ if (this.props.simulation) {
+ this.props.simulation.models.forEach((model) => {
+ if (model.simulation === this.state.widget.simulation) {
+ simulationModel = model;
+ }
+ });
+ }
+
+ return (
+
+
+ Simulator
+ this.props.handleChange(e)}>
+ {this.props.simulation.models.map((model, index) => (
+ {model.name}
+ ))}
+
+
+
+ );
+ }
+ }
+
+ export default EditTableWidget;
diff --git a/src/components/dialog/edit-widget.js b/src/components/dialog/edit-widget.js
index bd9dbc5..4f63349 100644
--- a/src/components/dialog/edit-widget.js
+++ b/src/components/dialog/edit-widget.js
@@ -14,6 +14,7 @@ import Dialog from './dialog';
import EditValueWidget from './edit-widget-value';
import EditPlotWidget from './edit-widget-plot';
+import EditTableWidget from './edit-widget-table';
class EditWidgetDialog extends Component {
static propTypes = {
@@ -78,6 +79,8 @@ class EditWidgetDialog extends Component {
widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e) => this.handleChange(e)} />;
} else if (this.props.widget.type === 'Plot') {
widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />;
+ } else if (this.props.widget.type === 'Table') {
+ widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />;
}
}
diff --git a/src/components/widget-table.js b/src/components/widget-table.js
new file mode 100644
index 0000000..071c084
--- /dev/null
+++ b/src/components/widget-table.js
@@ -0,0 +1,72 @@
+/**
+ * File: widget-table.js
+ * Author: Markus Grigull
+ * Date: 14.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+
+import Table from './table';
+import TableColumn from './table-column';
+
+class WidgetTable extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ rows: [],
+ sequence: null
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ // check data
+ const simulator = nextProps.widget.simulator;
+
+ if (nextProps.simulation == null || nextProps.data == null || nextProps.data[simulator] == null || nextProps.data[simulator].length === 0 || nextProps.data[simulator].values[0].length === 0) {
+ // clear values
+ this.setState({ rows: [], sequence: null });
+ return;
+ }
+
+ // check if new data, otherwise skip
+ if (this.state.sequence >= nextProps.data[simulator].sequence) {
+ return;
+ }
+
+ // get simulation model
+ const simulationModel = nextProps.simulation.models.find((model) => {
+ return (model.simulator === simulator);
+ });
+
+ // get rows
+ var rows = [];
+
+ nextProps.data[simulator].values.forEach((signal, index) => {
+ rows.push({
+ name: simulationModel.mapping[index].name,
+ value: signal[signal.length - 1].y
+ })
+ });
+
+ this.setState({ rows: rows, sequence: nextProps.data[simulator].sequence });
+ }
+
+ render() {
+ return (
+
+
{this.props.widget.name}
+
+
+
+ );
+ }
+}
+
+export default WidgetTable;
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index 827d57d..54c1ab0 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -121,6 +121,10 @@ class Visualization extends Component {
widget.time = 300;
widget.width = 400;
widget.height = 200;
+ } else if (item.name === 'Table') {
+ widget.simulator = this.state.simulation.models[0].simulator;
+ widget.width = 400;
+ widget.height = 200;
}
var visualization = this.state.visualization;
@@ -204,6 +208,7 @@ class Visualization extends Component {
+
}
diff --git a/src/containers/widget.js b/src/containers/widget.js
index 680cc6f..d7d615f 100644
--- a/src/containers/widget.js
+++ b/src/containers/widget.js
@@ -13,8 +13,10 @@ import { ContextMenuTrigger } from 'react-contextmenu';
import Rnd from 'react-rnd';
import SimulatorDataStore from '../stores/simulator-data-store';
+
import WidgetValue from '../components/widget-value';
import WidgetPlot from '../components/widget-plot';
+import WidgetTable from '../components/widget-table';
import '../styles/widgets.css';
@@ -72,6 +74,8 @@ class Widget extends Component {
element =
} else if (widget.type === 'Plot') {
element =
+ } else if (widget.type === 'Table') {
+ element =
}
if (this.props.editing) {
From e504b4d726e578d5db7b2b95c7406f7fcccad4a7 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Tue, 14 Mar 2017 22:00:23 +0100
Subject: [PATCH 067/556] Add label widget
---
src/components/widget-label.js | 20 ++++++++++++++++++++
src/containers/visualization.js | 3 +++
src/containers/widget.js | 3 +++
3 files changed, 26 insertions(+)
create mode 100644 src/components/widget-label.js
diff --git a/src/components/widget-label.js b/src/components/widget-label.js
new file mode 100644
index 0000000..2c29650
--- /dev/null
+++ b/src/components/widget-label.js
@@ -0,0 +1,20 @@
+/**
+ * File: widget-label.js
+ * Author: Markus Grigull
+ * Date: 14.03.2017
+ * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
+ * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
+ * Unauthorized copying of this file, via any medium is strictly prohibited.
+ **********************************************************************************/
+
+import React, { Component } from 'react';
+
+class WidgetLabel extends Component {
+ render() {
+ return (
+ {this.props.widget.name}
+ );
+ }
+}
+
+export default WidgetLabel;
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index 54c1ab0..e6baf3c 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -125,6 +125,8 @@ class Visualization extends Component {
widget.simulator = this.state.simulation.models[0].simulator;
widget.width = 400;
widget.height = 200;
+ } else if (item.name === 'Label') {
+
}
var visualization = this.state.visualization;
@@ -209,6 +211,7 @@ class Visualization extends Component {
+
}
diff --git a/src/containers/widget.js b/src/containers/widget.js
index d7d615f..603691c 100644
--- a/src/containers/widget.js
+++ b/src/containers/widget.js
@@ -17,6 +17,7 @@ import SimulatorDataStore from '../stores/simulator-data-store';
import WidgetValue from '../components/widget-value';
import WidgetPlot from '../components/widget-plot';
import WidgetTable from '../components/widget-table';
+import WidgetLabel from '../components/widget-label';
import '../styles/widgets.css';
@@ -76,6 +77,8 @@ class Widget extends Component {
element =
} else if (widget.type === 'Table') {
element =
+ } else if (widget.type === 'Label') {
+ element =
}
if (this.props.editing) {
From 6af05ccfe3daa8d76651852b2fd4aa3e2093c366 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 15 Mar 2017 12:16:17 +0100
Subject: [PATCH 068/556] Add time property to plot widget
Add disabled toolbox items
---
src/components/dialog/edit-widget-plot.js | 30 ++++++++++------------
src/components/dialog/edit-widget-table.js | 11 --------
src/components/toolbox-item.js | 25 +++++++++++++-----
src/components/widget-plot.js | 21 ++++++++++-----
src/containers/visualization.js | 1 +
src/stores/simulator-data-store.js | 4 +--
src/styles/app.css | 8 ++++++
7 files changed, 57 insertions(+), 43 deletions(-)
diff --git a/src/components/dialog/edit-widget-plot.js b/src/components/dialog/edit-widget-plot.js
index 837e15c..a2371e3 100644
--- a/src/components/dialog/edit-widget-plot.js
+++ b/src/components/dialog/edit-widget-plot.js
@@ -8,7 +8,7 @@
**********************************************************************************/
import React, { Component } from 'react';
-import { FormGroup, FormControl, ControlLabel, Checkbox } from 'react-bootstrap';
+import { FormGroup, FormControl, ControlLabel, Checkbox, HelpBlock } from 'react-bootstrap';
class EditPlotWidget extends Component {
constructor(props) {
@@ -17,8 +17,8 @@ class EditPlotWidget extends Component {
this.state = {
widget: {
simulator: '',
- plotType: '',
- signals: []
+ signals: [],
+ time: 0
}
};
}
@@ -58,6 +58,11 @@ class EditPlotWidget extends Component {
return (
+
+ Time
+ this.props.handleChange(e)} />
+ Time in seconds
+
Simulator
this.props.handleChange(e)}>
@@ -66,21 +71,12 @@ class EditPlotWidget extends Component {
))}
-
- Type
- this.props.handleChange(e)}>
- Multiple
- Table
-
+
+ Signals
+ {simulationModel.mapping.map((signal, index) => (
+ this.handleSignalChange(e, index)}>{signal.name}
+ ))}
- {this.state.widget.plotType === 'multiple' &&
-
- Signals
- {simulationModel.mapping.map((signal, index) => (
- this.handleSignalChange(e, index)}>{signal.name}
- ))}
-
- }
);
}
diff --git a/src/components/dialog/edit-widget-table.js b/src/components/dialog/edit-widget-table.js
index 81d24a8..0388ebd 100644
--- a/src/components/dialog/edit-widget-table.js
+++ b/src/components/dialog/edit-widget-table.js
@@ -26,17 +26,6 @@
}
render() {
- // get selected simulation model
- var simulationModel = {};
-
- if (this.props.simulation) {
- this.props.simulation.models.forEach((model) => {
- if (model.simulation === this.state.widget.simulation) {
- simulationModel = model;
- }
- });
- }
-
return (
diff --git a/src/components/toolbox-item.js b/src/components/toolbox-item.js
index bedb46a..4cc0144 100644
--- a/src/components/toolbox-item.js
+++ b/src/components/toolbox-item.js
@@ -34,18 +34,31 @@ class ToolboxItem extends Component {
type: PropTypes.string.isRequired
};
+ static defaultProps = {
+ disabled: false
+ };
+
render() {
var itemClass = classNames({
'toolbox-item': true,
- 'toolbox-item-dragging': this.props.isDragging
+ 'toolbox-item-dragging': this.props.isDragging,
+ 'toolbox-item-disabled': this.props.disabled
});
var dropEffect = 'copy';
- return this.props.connectDragSource(
-
- {this.props.name}
-
- , {dropEffect});
+ if (this.props.disabled === false) {
+ return this.props.connectDragSource(
+
+ {this.props.name}
+
+ , {dropEffect});
+ } else {
+ return (
+
+ {this.props.name}
+
+ );
+ }
}
}
diff --git a/src/components/widget-plot.js b/src/components/widget-plot.js
index 140a0f6..96de856 100644
--- a/src/components/widget-plot.js
+++ b/src/components/widget-plot.js
@@ -38,13 +38,20 @@ class WidgetPlot extends Component {
}
// get timestamps
- const latestTimestamp = nextProps.data[simulator].values[0][nextProps.data[simulator].values[0].length - 1].x;
- const firstTimestamp = latestTimestamp - nextProps.widget.time * 100;
+ var latestTimestamp = nextProps.data[simulator].values[0][nextProps.data[simulator].values[0].length - 1].x;
+ var firstTimestamp = latestTimestamp - nextProps.widget.time * 1000;
+ var firstIndex;
- // find element index representing firstTimestamp
- const firstIndex = nextProps.data[simulator].values[0].findIndex((value) => {
- return value.x >= firstTimestamp;
- });
+ if (nextProps.data[simulator].values[0][0].x < firstTimestamp) {
+ // find element index representing firstTimestamp
+ firstIndex = nextProps.data[simulator].values[0].findIndex((value) => {
+ return value.x >= firstTimestamp;
+ });
+ } else {
+ firstIndex = 0;
+ firstTimestamp = nextProps.data[simulator].values[0][0].x;
+ latestTimestamp = firstTimestamp + nextProps.widget.time * 1000;
+ }
// copy all values for each signal in time region
var values = [];
@@ -71,7 +78,7 @@ class WidgetPlot extends Component {
data={this.state.values}
title={this.props.widget.name}
gridHorizontal={true}
- xAccessor={(d) => {return new Date(d.x);}}
+ xAccessor={(d) => { if (d != null) { return new Date(d.x); } }}
hoverAnimation={false}
circleRadius={0}
domain={{ x: [this.state.firstTimestamp, this.state.latestTimestamp] }}
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index e6baf3c..3a58018 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -212,6 +212,7 @@ class Visualization extends Component {
+
}
diff --git a/src/stores/simulator-data-store.js b/src/stores/simulator-data-store.js
index fb97e8f..7e5145b 100644
--- a/src/stores/simulator-data-store.js
+++ b/src/stores/simulator-data-store.js
@@ -12,7 +12,7 @@ import { ReduceStore } from 'flux/utils';
import AppDispatcher from '../app-dispatcher';
import SimulatorDataDataManager from '../data-managers/simulator-data-data-manager';
-const MAX_VALUES = 1000;
+const MAX_VALUES = 10000;
class SimulationDataStore extends ReduceStore {
constructor() {
@@ -71,7 +71,7 @@ class SimulationDataStore extends ReduceStore {
case 'simulatorData/closed':
// close and delete socket
- if (state[action.identifier]) {
+ if (state[action.identifier] != null) {
state[action.identifier].close();
state[action.identifier] = null;
diff --git a/src/styles/app.css b/src/styles/app.css
index b7d16e3..4c70f45 100644
--- a/src/styles/app.css
+++ b/src/styles/app.css
@@ -152,3 +152,11 @@ body {
.toolbox-item-dragging {
opacity: 0.4;
}
+
+.toolbox-item-disabled {
+ border-color: lightgray;
+
+ color: lightgray;
+
+ cursor: default !important;
+}
From 6c9cc8946afccf0baf3ab077186d2a7a7454d213 Mon Sep 17 00:00:00 2001
From: Markus Grigull
Date: Wed, 15 Mar 2017 13:13:39 +0100
Subject: [PATCH 069/556] Add widgets at cursor drop position, widget zIndex
Add context menu for zIndex ordering
Bug: zIndex is only applied after saving visualization
---
src/components/dialog/edit-simulator.js | 16 +----
src/components/dialog/edit-widget.js | 3 +
src/components/dialog/new-simulator.js | 17 +-----
src/components/dropzone.js | 12 +++-
src/containers/simulators.js | 1 -
src/containers/visualization.js | 61 +++++++++++++++++--
src/containers/widget.js | 5 +-
.../simulator-data-data-manager.js | 10 +--
src/stores/simulator-data-store.js | 2 -
src/styles/widgets.css | 2 +
10 files changed, 79 insertions(+), 50 deletions(-)
diff --git a/src/components/dialog/edit-simulator.js b/src/components/dialog/edit-simulator.js
index ad6fa39..2ed14fb 100644
--- a/src/components/dialog/edit-simulator.js
+++ b/src/components/dialog/edit-simulator.js
@@ -26,7 +26,6 @@ class EditSimulatorDialog extends Component {
this.state = {
name: '',
- simulatorid: '1',
endpoint: '',
_id: ''
};
@@ -47,7 +46,6 @@ class EditSimulatorDialog extends Component {
resetState() {
this.setState({
name: this.props.simulator.name,
- simulatorid: this.props.simulator.simulatorid,
endpoint: this.props.simulator.endpoint,
_id: this.props.simulator._id
});
@@ -55,7 +53,6 @@ class EditSimulatorDialog extends Component {
validateForm(target) {
// check all controls
- var simulatorid = true;
var endpoint = true;
var name = true;
@@ -63,20 +60,14 @@ class EditSimulatorDialog extends Component {
name = false;
}
- // test if simulatorid is a number (in a string, not type of number)
- if (!/^\d+$/.test(this.state.simulatorid)) {
- simulatorid = false;
- }
-
if (this.state.endpoint === '') {
endpoint = false;
}
- this.valid = simulatorid && endpoint && name;
+ this.valid = endpoint && name;
// return state to control
if (target === 'name') return name ? "success" : "error";
- else if (target === 'simulatorid') return simulatorid ? "success" : "error";
else return endpoint ? "success" : "error";
}
@@ -89,11 +80,6 @@ class EditSimulatorDialog extends Component {
this.handleChange(e)} />
-
- Simulator ID
- this.handleChange(e)} />
-
-
Endpoint
this.handleChange(e)} />
diff --git a/src/components/dialog/edit-widget.js b/src/components/dialog/edit-widget.js
index 4f63349..8a7c3b0 100644
--- a/src/components/dialog/edit-widget.js
+++ b/src/components/dialog/edit-widget.js
@@ -15,6 +15,7 @@ import Dialog from './dialog';
import EditValueWidget from './edit-widget-value';
import EditPlotWidget from './edit-widget-plot';
import EditTableWidget from './edit-widget-table';
+import EditImageWidget from './edit-widget-image';
class EditWidgetDialog extends Component {
static propTypes = {
@@ -81,6 +82,8 @@ class EditWidgetDialog extends Component {
widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />;
} else if (this.props.widget.type === 'Table') {
widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />;
+ } else if (this.props.widget.type === 'Image') {
+ widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />;
}
}
diff --git a/src/components/dialog/new-simulator.js b/src/components/dialog/new-simulator.js
index 87eb407..7726e85 100644
--- a/src/components/dialog/new-simulator.js
+++ b/src/components/dialog/new-simulator.js
@@ -25,7 +25,6 @@ class NewSimulatorDialog extends Component {
this.state = {
name: '',
- simulatorid: '1',
endpoint: ''
};
}
@@ -43,12 +42,11 @@ class NewSimulatorDialog extends Component {
}
resetState() {
- this.setState({ name: '', simulatorid: '1', endpoint: '' });
+ this.setState({ name: '', endpoint: '' });
}
validateForm(target) {
// check all controls
- var simulatorid = true;
var endpoint = true;
var name = true;
@@ -56,20 +54,14 @@ class NewSimulatorDialog extends Component {
name = false;
}
- // test if simulatorid is a number (in a string, not type of number)
- if (!/^\d+$/.test(this.state.simulatorid)) {
- simulatorid = false;
- }
-
if (this.state.endpoint === '') {
endpoint = false;
}
- this.valid = simulatorid && endpoint && name;
+ this.valid = endpoint && name;
// return state to control
if (target === 'name') return name ? "success" : "error";
- else if (target === 'simulatorid') return simulatorid ? "success" : "error";
else return endpoint ? "success" : "error";
}
@@ -82,11 +74,6 @@ class NewSimulatorDialog extends Component {
this.handleChange(e)} />
-
- Simulator ID
- this.handleChange(e)} />
-
-
Endpoint
this.handleChange(e)} />
diff --git a/src/components/dropzone.js b/src/components/dropzone.js
index de2986d..88572d2 100644
--- a/src/components/dropzone.js
+++ b/src/components/dropzone.js
@@ -12,8 +12,14 @@ import { DropTarget } from 'react-dnd';
import classNames from 'classnames';
const dropzoneTarget = {
- drop(props, monitor) {
- props.onDrop(monitor.getItem());
+ drop(props, monitor, component) {
+ // get drop position
+ var position = monitor.getSourceClientOffset();
+ var dropzoneRect = component.wrapper.getBoundingClientRect();
+ position.x -= dropzoneRect.left;
+ position.y -= dropzoneRect.top;
+
+ props.onDrop(monitor.getItem(), position);
}
};
@@ -41,7 +47,7 @@ class Dropzone extends Component {
});
return this.props.connectDropTarget(
-
+
this.wrapper = wrapper}>
{this.props.children}
);
diff --git a/src/containers/simulators.js b/src/containers/simulators.js
index 00ab175..6bbbe3d 100644
--- a/src/containers/simulators.js
+++ b/src/containers/simulators.js
@@ -79,7 +79,6 @@ class Simulators extends Component {
-
this.setState({ editModal: true, modalSimulator: this.state.simulators[index] })} onDelete={(index) => this.setState({ deleteModal: true, modalSimulator: this.state.simulators[index] })} />
diff --git a/src/containers/visualization.js b/src/containers/visualization.js
index 3a58018..4c77bc2 100644
--- a/src/containers/visualization.js
+++ b/src/containers/visualization.js
@@ -99,15 +99,15 @@ class Visualization extends Component {
});
}
- handleDrop(item) {
+ handleDrop(item, position) {
// add new widget
var widget = {
name: 'Name',
type: item.name,
width: 100,
height: 100,
- x: 0,
- y: 0,
+ x: position.x,
+ y: position.y,
z: 0
};
@@ -185,6 +185,54 @@ class Visualization extends Component {
this.forceUpdate();
}
+ moveWidgetAbove(e, data) {
+ // increase z-Order
+ var visualization = this.state.visualization;
+ var widget = visualization.widgets[data.index]
+ widget.z++;
+
+ visualization.widgets[data.index] = widget;
+ this.setState({ visualization: visualization });
+ this.forceUpdate();
+ }
+
+ moveWidgetToFront(e, data) {
+ // increase z-Order
+ var visualization = this.state.visualization;
+ var widget = visualization.widgets[data.index]
+ widget.z = 100;
+
+ visualization.widgets[data.index] = widget;
+ this.setState({ visualization: visualization });
+ this.forceUpdate();
+ }
+
+ moveWidgetUnderneath(e, data) {
+ // decrease z-Order
+ var visualization = this.state.visualization;
+ var widget = visualization.widgets[data.index]
+
+ widget.z--;
+ if (widget.z < 0) {
+ widget.z = 0;
+ }
+
+ visualization.widgets[data.index] = widget;
+ this.setState({ visualization: visualization });
+ this.forceUpdate();
+ }
+
+ moveWidgetToBack(e, data) {
+ // increase z-Order
+ var visualization = this.state.visualization;
+ var widget = visualization.widgets[data.index]
+ widget.z = 0;
+
+ visualization.widgets[data.index] = widget;
+ this.setState({ visualization: visualization });
+ this.forceUpdate();
+ }
+
render() {
return (
@@ -216,7 +264,7 @@ class Visualization extends Component {
}
- this.handleDrop(item)} editing={this.state.editing}>
+ this.handleDrop(item, position)} editing={this.state.editing}>
{this.state.visualization.widgets != null &&
this.state.visualization.widgets.map((widget, index) => (
this.widgetChange(w, i)} editing={this.state.editing} index={index} grid={this.state.grid} />
@@ -228,6 +276,11 @@ class Visualization extends Component {
))}
diff --git a/src/containers/widget.js b/src/containers/widget.js
index 603691c..968e5f6 100644
--- a/src/containers/widget.js
+++ b/src/containers/widget.js
@@ -61,6 +61,8 @@ class Widget extends Component {
}
render() {
+ console.log('render widget ' + this.props.data.z + this.props.data.type);
+
// configure grid
var grid = this.props.grid;
if (!grid) {
@@ -92,6 +94,7 @@ class Widget extends Component {
onDragStop={(event, ui) => this.dragStop(event, ui)}
moveGrid={grid}
resizeGrid={grid}
+ zIndex={widget.z}
>