From 9553d5406d6f41491067caee3fef4bd20ae7302c Mon Sep 17 00:00:00 2001
From: Mathis Neumann <mathis@simpletechs.net>
Date: Mon, 20 Jun 2016 16:47:40 +0200
Subject: [PATCH] add bootstrap, navbar and layout selection for architecture
 view

---
 app/components/architecture-viewer.js         | 20 ++++++
 .../component.js                              | 67 +++++--------------
 app/services/graphing-service.js              |  2 +-
 app/styles/_custom_bootstrap.scss             | 56 ++++++++++++++++
 app/styles/app.scss                           |  8 ++-
 app/styles/components/_cytoscape.scss         |  5 +-
 app/templates/application.hbs                 | 29 ++++++--
 app/templates/architectures/single.hbs        |  4 +-
 app/templates/components/.gitkeep             |  0
 .../components/architecture-viewer.hbs        | 16 +++++
 bower.json                                    |  3 +-
 ember-cli-build.js                            |  3 +
 package.json                                  |  4 +-
 .../components/architecture-viewer-test.js    | 24 +++++++
 14 files changed, 176 insertions(+), 65 deletions(-)
 create mode 100644 app/components/architecture-viewer.js
 create mode 100644 app/styles/_custom_bootstrap.scss
 delete mode 100644 app/templates/components/.gitkeep
 create mode 100644 app/templates/components/architecture-viewer.hbs
 create mode 100644 tests/integration/components/architecture-viewer-test.js

diff --git a/app/components/architecture-viewer.js b/app/components/architecture-viewer.js
new file mode 100644
index 0000000..db4e486
--- /dev/null
+++ b/app/components/architecture-viewer.js
@@ -0,0 +1,20 @@
+import Ember from 'ember';
+
+export default Ember.Component.extend({
+    graph: null,
+    layoutAlgorithm: 'cose',
+    layoutAlgorithms: [
+        "cose",
+        "cola"
+    ],
+    init() {
+        this._super();
+        this.debug('init!', this.get('graph'), this.get('layoutAlgorithm'));
+    },
+    actions: {
+        selectLayoutAlgorithm(value) {
+            this.debug('value', value);
+            this.set('layoutAlgorithm', value);
+        }
+    }
+});
diff --git a/app/components/architecture-visualisation-cytoscape/component.js b/app/components/architecture-visualisation-cytoscape/component.js
index 0ceae58..33e4b7b 100644
--- a/app/components/architecture-visualisation-cytoscape/component.js
+++ b/app/components/architecture-visualisation-cytoscape/component.js
@@ -6,57 +6,21 @@ import cytoscapeStyle from './style';
 import _ from 'npm:lodash';
 
 export default Ember.Component.extend({
+    layoutAlgorithm: 'cose',
     classNames: ['cytoscapeRenderingSpace'],
-    dummyGraph: {
-        nodes: [
-            { data: { id: 'nodeWebnode', label: 'Webnode', type: 'node' } },
-            { data: { id: 'nodeLogicnode', label: 'Logicnode', type: 'node' } },
-            { data: { id: 'nodeAdapter', label: 'Adapter', type: 'node' } },
-            { data: { id: 'nodeDatabase', label: 'Database', type: 'node' } },
-            { data: { id: 'serviceInstanceFrontEnd', label: 'Database', type: 'serviceInstance', parent: 'nodeWebnode' } },
-            { data: { id: 'serviceInstanceCashDesk', label: 'CashDesk', type: 'serviceInstance', parent: 'nodeLogicnode' } },
-            { data: { id: 'serviceInstanceInventory', label: 'Inventory', type: 'serviceInstance' }, parent: 'nodeLogicnode' },
-            { data: { id: 'serviceInstanceData', label: 'Data', type: 'serviceInstance', parent: 'nodeLogicnode' } },
-            { data: { id: 'serviceInstancePostgresSQL', label: 'PostgresSQL', type: 'serviceInstance', parent: 'nodeDatabase' } },
-        ],
-        edges: [
-            { data: { id: 'ad', source: 'a', target: 'd', weight: 100 } },
-        ]
-    },
     init: function() {
-        cycola( cytoscape, cola );
-
+        cycola( cytoscape, window.cola );
         this._super();
-        const self = this;
-        const log = self.debug.bind(self);
-        log('loaded');
-        // this.interval = setInterval(function() {
-        //     const graph = self.get('graph');
-
-        //     log('update interval called', graph);
-
-        //     if(!graph) {
-        //         return; // eventual consistent
-        //     }
-        //     const edges = graph.edges || [];
-        //     const index = Math.floor(Math.random()*edges.length);
-        //     if(Math.random() > 0.5) {
-        //         edges.splice(index, 1);
-        //     } else { // FIXME: does not render updates
-        //         const children = _.get(graph, 'children', []);
-        //         const randomNodeIndex = Math.floor(Math.random()*children.length);
-        //         const randomNodeId = children[randomNodeIndex].id;
-        //         graph.edges = _.set(edges, `${index}.target`, randomNodeId);
-        //         log(`updating random edge (${index}) to target a random node id ${randomNodeId}`, randomNodeIndex, edges);
-        //     }
-        //     self.set('graph', graph);
-        //     self.renderGraph();
-        // }, 1000);
+        this.debug('loaded', this.get('graph'));
     },
     willDestroyElement() {
         clearInterval(this.interval);
     },
-    didInsertElement: function() {
+    layoutChanged: Ember.observer('layout', function(newLayout) {
+        this.debug('layout changed!', newLayout);
+    }),
+    renderGraph: function() {
+        this.debug('graph', this.get('graph'));
         this.cytoscape = cytoscape({
           container: this.element,
 
@@ -65,13 +29,18 @@ export default Ember.Component.extend({
 
           style: cytoscapeStyle,
 
-          elements: this.get('graph'), // TODO!
+          elements: _.cloneDeep(this.get('graph')), // TODO!
 
           layout: {
-            name: 'cola',
-            padding: 5,
-            maxSimulationTime: 1000
+            name: this.get('layoutAlgorithm'),
+            maxSimulationTime: 1000,
+            padding: 6,
+            ungrabifyWhileSimulating: true,
+            infinite: false
           }
         });
-    }
+
+        window.cy = cytoscape;
+        window.cytoscape = this.cytoscape;
+    }.on('didInsertElement').observes('layoutAlgorithm', 'graph')
 });
diff --git a/app/services/graphing-service.js b/app/services/graphing-service.js
index c9b7f0c..5983992 100644
--- a/app/services/graphing-service.js
+++ b/app/services/graphing-service.js
@@ -47,10 +47,10 @@ export default Ember.Service.extend({
 
     communicationInstances.forEach(instance => {
         const data = instance.toJSON({includeId: true});
-        data.label = data.name;
         data.source = data.sourceId;
         data.target = data.targetId;
         data.technology = instance.store.peekRecord('communication', data.communicationId).get('technology');
+        data.label = data.technology;
         this.debug('technology', data.technology);
 
       network.edges.push({
diff --git a/app/styles/_custom_bootstrap.scss b/app/styles/_custom_bootstrap.scss
new file mode 100644
index 0000000..2533e71
--- /dev/null
+++ b/app/styles/_custom_bootstrap.scss
@@ -0,0 +1,56 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+// Core variables and mixins
+@import "bootstrap/variables";
+@import "bootstrap/mixins";
+
+// Reset and dependencies
+@import "bootstrap/normalize";
+@import "bootstrap/print";
+@import "bootstrap/glyphicons";
+
+// Core CSS
+@import "bootstrap/scaffolding";
+@import "bootstrap/type";
+@import "bootstrap/code";
+@import "bootstrap/grid";
+@import "bootstrap/tables";
+@import "bootstrap/forms";
+@import "bootstrap/buttons";
+
+// Components
+// @import "bootstrap/component-animations";
+// @import "bootstrap/dropdowns";
+// @import "bootstrap/button-groups";
+// @import "bootstrap/input-groups";
+@import "bootstrap/navs";
+@import "bootstrap/navbar";
+// @import "bootstrap/breadcrumbs";
+// @import "bootstrap/pagination";
+// @import "bootstrap/pager";
+@import "bootstrap/labels";
+// @import "bootstrap/badges";
+// @import "bootstrap/jumbotron";
+// @import "bootstrap/thumbnails";
+@import "bootstrap/alerts";
+// @import "bootstrap/progress-bars";
+// @import "bootstrap/media";
+// @import "bootstrap/list-group";
+// @import "bootstrap/panels";
+// @import "bootstrap/responsive-embed";
+// @import "bootstrap/wells";
+// @import "bootstrap/close";
+
+// Components w/ JavaScript
+// @import "bootstrap/modals";
+// @import "bootstrap/tooltip";
+// @import "bootstrap/popovers";
+// @import "bootstrap/carousel";
+
+// Utility classes
+@import "bootstrap/utilities";
+@import "bootstrap/responsive-utilities";
\ No newline at end of file
diff --git a/app/styles/app.scss b/app/styles/app.scss
index 9fb42c0..0be045f 100644
--- a/app/styles/app.scss
+++ b/app/styles/app.scss
@@ -1,7 +1,9 @@
-body {
-    font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
-}
 
 @import "components/_architecture";
 @import "components/_cytoscape";
 
+$navbar-default-bg: #312312;
+$light-orange: #ff8c00;
+$navbar-default-color: $light-orange;
+
+@import "custom_bootstrap";
\ No newline at end of file
diff --git a/app/styles/components/_cytoscape.scss b/app/styles/components/_cytoscape.scss
index 4fe0241..61c56f4 100644
--- a/app/styles/components/_cytoscape.scss
+++ b/app/styles/components/_cytoscape.scss
@@ -1,7 +1,8 @@
 .cytoscapeRenderingSpace {
-  height: 100%;
+  height: 720px;
+  max-height: 100%;
   width: 100%;
-  position: absolute;
   left: 0;
   top: 0;
+  border: solid 1px #ccc;
 }
\ No newline at end of file
diff --git a/app/templates/application.hbs b/app/templates/application.hbs
index afbc629..b8ae549 100644
--- a/app/templates/application.hbs
+++ b/app/templates/application.hbs
@@ -1,8 +1,27 @@
 {{loading-slider isLoading=loading duration=250}}
-<h2 id="title">Welcome to Ember</h2>
-<ul>
-    <li>Go to {{#link-to 'home'}}Home{{/link-to}}</li>
-    <li>Go to {{#link-to 'architectures'}}Architekturen{{/link-to}}</li>
-</ul>
+
+<nav class="navbar">
+  <div class="container">
+    <div class="navbar-header">
+      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
+        <span class="sr-only">Toggle navigation</span>
+        <span class="icon-bar"></span>
+        <span class="icon-bar"></span>
+        <span class="icon-bar"></span>
+      </button>
+      {{#link-to 'home' class="navbar-brand"}}iObserve{{/link-to}}
+    </div>
+    <div id="navbar" class="navbar-collapse collapse">
+      <ul class="nav navbar-nav">
+        {{#link-to 'home' tagName='li'}}
+            {{#link-to 'home'}}Startseite{{/link-to}}
+        {{/link-to}}
+        {{#link-to 'architectures' tagName='li'}}
+            {{#link-to 'architectures'}}Architekturen{{/link-to}}
+        {{/link-to}}
+      </ul>
+    </div><!--/.nav-collapse -->
+  </div>
+</nav>
 
 {{outlet}}
diff --git a/app/templates/architectures/single.hbs b/app/templates/architectures/single.hbs
index f4a058b..c46db69 100644
--- a/app/templates/architectures/single.hbs
+++ b/app/templates/architectures/single.hbs
@@ -1,3 +1 @@
-<div class="visualisationContainer">
-    {{architecture-visualisation-cytoscape graph=model}}
-</div>
+{{architecture-viewer graph=model}}
\ No newline at end of file
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/architecture-viewer.hbs b/app/templates/components/architecture-viewer.hbs
new file mode 100644
index 0000000..9f185d5
--- /dev/null
+++ b/app/templates/components/architecture-viewer.hbs
@@ -0,0 +1,16 @@
+<div class="row">
+    <div class="col-md-10 visualisationContainer">
+        {{architecture-visualisation-cytoscape graph=graph layoutAlgorithm=layoutAlgorithm}}
+    </div>
+    <div class="col-md-2">
+        <div class="form-group">
+          <label for="layoutAlgorithm">Layout:</label>
+          <select class="form-control" id="layoutAlgorithm" onchange={{action "selectLayoutAlgorithm" value="target.value"}}>
+            {{#each layoutAlgorithms as |algorithm|}}
+                <option>{{algorithm}}</option>
+            {{/each}}
+          </select>
+        </div>
+    </div>
+</div>
+
diff --git a/bower.json b/bower.json
index d24ee72..0dc2645 100644
--- a/bower.json
+++ b/bower.json
@@ -7,6 +7,7 @@
     "ember-qunit-notifications": "0.1.0",
     "d3": "^3.5.16",
     "visionmedia-debug": "2.2",
-    "webcola": "^3.1.3"
+    "webcola": "^3.1.3",
+    "bootstrap-sass": "^3.3.6"
   }
 }
diff --git a/ember-cli-build.js b/ember-cli-build.js
index ac770c2..93dde05 100644
--- a/ember-cli-build.js
+++ b/ember-cli-build.js
@@ -5,6 +5,9 @@ var EmberApp = require('ember-cli/lib/broccoli/ember-app');
 module.exports = function(defaults) {
   var app = new EmberApp(defaults, {
     // Add options here
+    'ember-cli-bootstrap-sassy': {
+        'js': []
+    }
   });
 
   // Use `app.import` to add additional libraries to the generated
diff --git a/package.json b/package.json
index 6966775..95085c4 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
     "ember-cli": "2.4.2",
     "ember-cli-app-version": "^1.0.0",
     "ember-cli-babel": "^5.1.5",
+    "ember-cli-bootstrap-sassy": "0.5.3",
     "ember-cli-d3": "1.1.6",
     "ember-cli-dependency-checker": "^1.2.0",
     "ember-cli-htmlbars": "^1.0.1",
@@ -46,7 +47,8 @@
     "ember-load-initializers": "^0.5.0",
     "ember-resolver": "^2.0.3",
     "loader.js": "^4.0.0",
-    "lodash": "^4.11.1"
+    "lodash": "^4.11.1",
+    "node-sass": "^3.8.0"
   },
   "dependencies": {
     "cytoscape": "^2.6.12",
diff --git a/tests/integration/components/architecture-viewer-test.js b/tests/integration/components/architecture-viewer-test.js
new file mode 100644
index 0000000..8046093
--- /dev/null
+++ b/tests/integration/components/architecture-viewer-test.js
@@ -0,0 +1,24 @@
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('architecture-viewer', 'Integration | Component | architecture viewer', {
+  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`{{architecture-viewer}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:
+  this.render(hbs`
+    {{#architecture-viewer}}
+      template block text
+    {{/architecture-viewer}}
+  `);
+
+  assert.equal(this.$().text().trim(), 'template block text');
+});
-- 
GitLab