[CORD-2719] Refactoring the service graph to use a proper state machine

Change-Id: I5d92aa876c9769701c93b2f5e7d47bdc311b6eb1
diff --git a/docs/developer/service_graph.md b/docs/developer/service_graph.md
index 6b785f9..353f024 100644
--- a/docs/developer/service_graph.md
+++ b/docs/developer/service_graph.md
@@ -70,4 +70,5 @@
 ## Events listened by the Service Graph
 
 * `xos.sg.update` will render the graph again
+* `xos.sg.stateChange` will listen for changes in the state machine
 
diff --git a/package.json b/package.json
index 3ff2f9d..f5adc11 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,8 @@
     "oclazyload": "1.1.0",
     "pluralize": "3.1.0",
     "rxjs": "5.2.0",
-    "socket.io-client": "1.7.3"
+    "socket.io-client": "1.7.3",
+    "typestate": "^1.0.5"
   },
   "devDependencies": {
     "angular-mocks": "1.6.4",
diff --git a/src/app/service-graph/components/graph/graph.component.html b/src/app/service-graph/components/graph/graph.component.html
index 6510a9f..ad3d0da 100644
--- a/src/app/service-graph/components/graph/graph.component.html
+++ b/src/app/service-graph/components/graph/graph.component.html
@@ -22,4 +22,26 @@
   </div>
   <a ng-click="vm.closeFullscreen()" class="close-btn"><i class="fa fa-times"></i></a>
   <svg></svg>
+  <div class="row">
+    <div class="col-md-3">
+      <a ng-click="vm.toggleModel('services')" ng-class="{active: vm.currentState >= 0}" class="btn btn-block btn-accent">
+        <span>Services</span>
+      </a>
+    </div>
+    <div class="col-md-3">
+      <a ng-click="vm.toggleModel('serviceinstances')" ng-class="{active: vm.currentState >= 1}" class="btn btn-block btn-accent">
+        <span>Service Instances</span>
+      </a>
+    </div>
+    <div class="col-md-3">
+      <a ng-click="vm.toggleModel('instances')" ng-class="{active: vm.currentState >= 2}" class="btn btn-block btn-accent">
+        <span>Instances</span>
+      </a>
+    </div>
+    <div class="col-md-3">
+      <a ng-click="vm.toggleModel('networks')" ng-class="{active: vm.currentState >= 3}" class="btn btn-block btn-accent">
+        <span>Networks</span>
+      </a>
+    </div>
+  </div>
 </div>
diff --git a/src/app/service-graph/components/graph/graph.component.ts b/src/app/service-graph/components/graph/graph.component.ts
index ed36654..b0cabb9 100644
--- a/src/app/service-graph/components/graph/graph.component.ts
+++ b/src/app/service-graph/components/graph/graph.component.ts
@@ -28,6 +28,7 @@
 import {IXosNodeRenderer} from '../../services/renderer/node.renderer';
 import {IXosSgLink, IXosSgNode} from '../../interfaces';
 import {IXosGraphConfig} from '../../services/graph.config';
+import {GraphStates, IXosGraphStateMachine} from '../../services/graph-state-machine';
 
 class XosServiceGraphCtrl {
   static $inject = [
@@ -38,14 +39,18 @@
     'XosServiceGraphIcons',
     'XosNodePositioner',
     'XosNodeRenderer',
-    'XosGraphConfig'
+    'XosGraphConfig',
+    'XosGraphStateMachine'
   ];
 
+  // graph status
+  public currentState: number;
   public loader: boolean = true;
 
   private GraphSubscription: Subscription;
   private graph: any; // this is the Graph instance
 
+
   // graph element
   private svg;
   private linkGroup;
@@ -60,10 +65,13 @@
     private XosServiceGraphIcons: IXosServiceGraphIcons,
     private XosNodePositioner: IXosNodePositioner,
     private XosNodeRenderer: IXosNodeRenderer,
-    private XosGraphConfig: IXosGraphConfig
+    private XosGraphConfig: IXosGraphConfig,
+    public XosGraphStateMachine: IXosGraphStateMachine
   ) {
     this.$log.info('[XosServiceGraph] Component setup');
 
+    this.currentState = this.XosGraphStateMachine.getCurrentState();
+
     this.XosGraphConfig.setupKeyboardShortcuts();
 
     this.setupSvg();
@@ -74,6 +82,7 @@
         graph => {
           this.graph = graph;
           if (this.graph.nodes().length > 0) {
+            this.$log.info('[XosServiceGraph] Rendering graph: ', this.graph.nodes(), this.graph.edges());
             this.renderGraph(this.graph);
           }
         },
@@ -87,6 +96,13 @@
       this.renderGraph(this.graph);
     });
 
+    this.$scope.$on('xos.sg.stateChange', (event, state: number) => {
+      this.$log.info(`[XosServiceGraph] Received event: xos.sg.stateChange. New state is ${state}`);
+      this.$scope.$applyAsync(() => {
+        this.currentState = state;
+      });
+    });
+
     $(window).resize(() => {
       this.renderGraph(this.graph);
     });
@@ -100,17 +116,34 @@
     this.XosGraphConfig.toggleFullscreen();
   }
 
+  public toggleModel(modelName: string): void {
+    switch (modelName) {
+      case 'services':
+        this.XosGraphStateMachine.go(GraphStates.Services);
+        break;
+      case 'serviceinstances':
+        this.XosGraphStateMachine.go(GraphStates.ServiceInstances);
+        break;
+      case 'instances':
+        this.XosGraphStateMachine.go(GraphStates.Instances);
+        break;
+      case 'networks':
+        this.XosGraphStateMachine.go(GraphStates.Networks);
+        break;
+    }
+  }
+
   private setupSvg() {
     this.svg = d3.select('xos-service-graph svg');
 
     this.linkGroup = this.svg.append('g')
       .attr({
-        class: 'link-group'
+        'class': 'link-group'
       });
 
     this.nodeGroup = this.svg.append('g')
       .attr({
-        class: 'node-group'
+        'class': 'node-group'
       });
   }
 
@@ -147,6 +180,7 @@
   }
 
   private renderGraph(graph: any) {
+
     let nodes: IXosSgNode[] = this.XosGraphStore.nodesFromGraph(graph);
     let links = this.XosGraphStore.linksFromGraph(graph);
     const svgDim = this.getSvgDimensions();
@@ -190,7 +224,7 @@
     entering.append('line')
       .attr({
         id: n => n.id,
-        class: n => n.type
+        'class': n => n.type
       });
 
     link.exit().remove();
diff --git a/src/app/service-graph/index.ts b/src/app/service-graph/index.ts
index 0bed24b..334f90a 100644
--- a/src/app/service-graph/index.ts
+++ b/src/app/service-graph/index.ts
@@ -23,6 +23,7 @@
 import {XosGraphConfig} from './services/graph.config';
 import {XosNodeRenderer} from './services/renderer/node.renderer';
 import {XosServiceGraphLegend} from './components/graph-legend/graph-legend.component';
+import {XosGraphStateMachine} from './services/graph-state-machine';
 
 export const xosServiceGraph = 'xosServiceGraph';
 
@@ -34,6 +35,7 @@
   .service('XosServiceGraphIcons', XosServiceGraphIcons)
   .service('XosNodePositioner', XosNodePositioner)
   .service('XosGraphConfig', XosGraphConfig)
+  .service('XosGraphStateMachine', XosGraphStateMachine)
   .service('XosNodeRenderer', XosNodeRenderer)
   .component('xosServiceGraph', XosServiceGraph)
   .component('xosServiceGraphLegend', XosServiceGraphLegend)
diff --git a/src/app/service-graph/services/graph-state-machine.ts b/src/app/service-graph/services/graph-state-machine.ts
new file mode 100644
index 0000000..6f406af
--- /dev/null
+++ b/src/app/service-graph/services/graph-state-machine.ts
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {TypeState} from 'typestate';
+import {IXosGraphStore} from './graph.store';
+
+export interface IXosGraphStateMachine {
+  states: GraphStates;
+  go(state: GraphStates): void;
+  getCurrentState(): number;
+}
+
+export enum GraphStates {
+  Services,
+  ServiceInstances,
+  Instances,
+  Networks
+}
+
+export class XosGraphStateMachine {
+  static $inject = [
+    '$log',
+    '$rootScope',
+    'XosGraphStore'
+  ];
+
+  private graphStateMachine: TypeState.FiniteStateMachine<GraphStates>;
+
+  constructor(
+    private $log: ng.ILogService,
+    private $scope: ng.IRootScopeService,
+    private XosGraphStore: IXosGraphStore
+  ) {
+    this.$log.info(`[XosGraphStateMachine] Creating Graph StateMachine`);
+
+    this.graphStateMachine = new TypeState.FiniteStateMachine<GraphStates>(GraphStates.Services);
+
+    // I want to be able to move between any state in the state machine
+    this.graphStateMachine.fromAny(GraphStates).toAny(GraphStates);
+
+    this.graphStateMachine.onTransition = (from: GraphStates, to: GraphStates) => {
+      this.$log.info(`[XosGraphStateMachine] From ${GraphStates[from]} to ${GraphStates[to]}`);
+
+      const toName = GraphStates[to];
+
+      switch (toName) {
+        case 'Services':
+          if (from > to) {
+            this.removeNetworks();
+            this.removeInstances();
+            this.removeServiceInstances();
+          }
+          break;
+        case 'ServiceInstances':
+          if (from > to) {
+            this.removeNetworks();
+            this.removeInstances();
+          }
+          else {
+            this.addServiceInstances();
+          }
+          break;
+        case 'Instances':
+          if (from > to) {
+            this.removeNetworks();
+          }
+          else {
+            this.addServiceInstances();
+            this.addInstances();
+          }
+          break;
+        case 'Networks':
+          if (from > to) {
+            // this will never happen
+          }
+          else {
+            this.addServiceInstances();
+            this.addInstances();
+            this.addNetworks();
+          }
+          break;
+      }
+    };
+  }
+
+  public go(state: GraphStates) {
+    this.graphStateMachine.go(state);
+
+    this.$scope.$broadcast('xos.sg.stateChange', this.getCurrentState());
+  }
+
+  public getCurrentState(): number {
+    return this.graphStateMachine.currentState;
+  }
+
+  private addServiceInstances() {
+    // add service instances to the graph
+    this.$log.debug(`[XosGraphStateMachine] Add ServiceInstances`);
+    this.XosGraphStore.addServiceInstances();
+  }
+
+  private addInstances () {
+    // add instances to the graph
+    this.$log.debug(`[XosGraphStateMachine] Add Instances`);
+    this.XosGraphStore.addInstances();
+  }
+
+  private addNetworks () {
+    // add networks to the graph
+    this.$log.debug(`[XosGraphStateMachine] Add Networks`);
+    this.XosGraphStore.addNetworks();
+  }
+
+  private removeServiceInstances() {
+    // remove service instances to the graph
+    this.$log.debug(`[XosGraphStateMachine] Remove ServiceInstances`);
+    this.XosGraphStore.removeServiceInstances();
+  }
+
+  private removeInstances () {
+    // remove instances to the graph
+    this.$log.debug(`[XosGraphStateMachine] Remove Instances`);
+    this.XosGraphStore.removeInstances();
+  }
+
+  private removeNetworks () {
+    // remove networks to the graph
+    this.$log.debug(`[XosGraphStateMachine] Remove Networks`);
+    this.XosGraphStore.removeNetworks();
+  }
+}
diff --git a/src/app/service-graph/services/graph.config.ts b/src/app/service-graph/services/graph.config.ts
index cc316a2..8907952 100644
--- a/src/app/service-graph/services/graph.config.ts
+++ b/src/app/service-graph/services/graph.config.ts
@@ -16,8 +16,8 @@
 
 import * as $ from 'jquery';
 import {IXosKeyboardShortcutService} from '../../core/services/keyboard-shortcut';
-import {IXosGraphStore} from './graph.store';
 import {IXosSidePanelService} from '../../core/side-panel/side-panel.service';
+import {GraphStates, IXosGraphStateMachine} from './graph-state-machine';
 
 export interface IXosGraphConfig {
   setupKeyboardShortcuts(): void;
@@ -33,36 +33,9 @@
     '$timeout',
     'XosSidePanel',
     'XosKeyboardShortcut',
-    'XosGraphStore'
+    'XosGraphStateMachine'
   ];
 
-  private instanceEnabled = false;
-  private instanceBinding = {
-    key: 'i',
-    modifiers: ['shift'],
-    cb: () => {
-      // NOTE anytime the graph change the observable is updated,
-      // no need to manually retrigger here
-      this.XosGraphStore.toggleInstances();
-      this.toggleNetworkShortcuts();
-    },
-    label: 'i',
-    description: 'Toggle Instances'
-  };
-
-  private networkEnabled = false;
-  private networkBinding = {
-    key: 'n',
-    modifiers: ['shift'],
-    cb: () => {
-      // NOTE anytime the graph change the observable is updated,
-      // no need to manually retrigger here
-      this.XosGraphStore.toggleNetwork();
-    },
-    label: 'n',
-    description: 'Toggle Networks'
-  };
-
   constructor (
     private $log: ng.ILogService,
     private $cookies: ng.cookies.ICookiesService,
@@ -70,7 +43,7 @@
     private $timeout: ng.ITimeoutService,
     private XosSidePanel: IXosSidePanelService,
     private XosKeyboardShortcut: IXosKeyboardShortcutService,
-    private XosGraphStore: IXosGraphStore
+    private XosGraphStateMachine: IXosGraphStateMachine
   ) {
 
   }
@@ -101,14 +74,43 @@
     });
 
     this.XosKeyboardShortcut.registerKeyBinding({
+      key: 'c',
+      modifiers: ['shift'],
+      cb: () => {
+        this.XosGraphStateMachine.go(GraphStates.Services);
+      },
+      label: 'c',
+      description: 'Clean the Service graph'
+    });
+
+    this.XosKeyboardShortcut.registerKeyBinding({
       key: 's',
       modifiers: ['shift'],
       cb: () => {
-        this.XosGraphStore.toggleServiceInstances();
-        this.toggleInstanceShortcuts();
+        this.XosGraphStateMachine.go(GraphStates.ServiceInstances);
       },
       label: 's',
-      description: 'Toggle ServiceInstances'
+      description: 'Show ServiceInstances'
+    });
+
+    this.XosKeyboardShortcut.registerKeyBinding({
+      key: 'i',
+      modifiers: ['shift'],
+      cb: () => {
+        this.XosGraphStateMachine.go(GraphStates.Instances);
+      },
+      label: 'i',
+      description: 'Show Instances'
+    });
+
+    this.XosKeyboardShortcut.registerKeyBinding({
+      key: 'n',
+      modifiers: ['shift'],
+      cb: () => {
+        this.XosGraphStateMachine.go(GraphStates.Networks);
+      },
+      label: 'n',
+      description: 'Show Networks'
     });
 
   }
@@ -120,26 +122,4 @@
       this.$rootScope.$broadcast('xos.sg.update');
     }, 500);
   }
-
-  private toggleInstanceShortcuts(): void {
-    if (!this.instanceEnabled) {
-      this.XosKeyboardShortcut.registerKeyBinding(this.instanceBinding);
-    }
-    else {
-      this.XosKeyboardShortcut.removeKeyBinding(this.instanceBinding);
-      this.XosKeyboardShortcut.removeKeyBinding(this.networkBinding);
-    }
-    this.instanceEnabled = !this.instanceEnabled;
-  }
-
-  private toggleNetworkShortcuts(): void {
-    if (!this.networkEnabled) {
-      this.XosKeyboardShortcut.registerKeyBinding(this.networkBinding);
-    }
-    else {
-      this.XosKeyboardShortcut.removeKeyBinding(this.networkBinding);
-    }
-
-    this.networkEnabled = !this.networkEnabled;
-  }
 }
diff --git a/src/app/service-graph/services/graph.store.spec.ts b/src/app/service-graph/services/graph.store.spec.ts
index a41809c..53f24fc 100644
--- a/src/app/service-graph/services/graph.store.spec.ts
+++ b/src/app/service-graph/services/graph.store.spec.ts
@@ -27,7 +27,6 @@
 
   // state
   serviceGraph: Graph;
-  serviceInstanceShown: boolean;
 
   // private methods
   getNodeId: any;
@@ -35,7 +34,6 @@
   addNode: any;
   addEdge: any;
   nodesFromGraph: any;
-  toggleServiceInstances: any;
 
   // observables
   ServiceInstanceSubscription: any;
@@ -269,66 +267,57 @@
     });
   });
 
-  describe(`the toggleServiceInstances method`, () => {
-    describe('when they are disabled', () => {
+  describe('the addServiceInstance method', () => {
+    beforeEach(() => {
+      MockModelStore.query.calls.reset();
+    });
 
-      beforeEach(() => {
-        MockModelStore.query.calls.reset();
+    it('should add them to the graph', () => {
+      service.addServiceInstances();
+      expect(MockModelStore.query).toHaveBeenCalledWith(`ServiceInstance`, '/core/serviceinstances');
+      expect(MockModelStore.query).toHaveBeenCalledWith(`ServiceInstanceLink`, '/core/serviceinstancelinks');
+      expect(service.ServiceInstanceSubscription).toBeDefined();
+      expect(service.ServiceInstanceLinkSubscription).toBeDefined();
+      // TODO wait for the Observable to return and check the graph
+    });
+  });
+
+  describe('the removeServiceInstance method', () => {
+    beforeEach(() => {
+      service.ServiceInstanceSubscription = {
+        unsubscribe: jasmine.createSpy('ServiceInstanceSubscription')
+      };
+      service.ServiceInstanceLinkSubscription = {
+        unsubscribe: jasmine.createSpy('ServiceInstanceLinkSubscription')
+      };
+
+      service.serviceGraph = new Graph();
+
+      services.forEach(s => {
+        service.addNode(s);
       });
 
-      it('should fetch them', () => {
-        service.toggleServiceInstances();
-        expect(service.serviceInstanceShown).toBeTruthy();
-        expect(MockModelStore.query).toHaveBeenCalledWith(`ServiceInstance`, '/core/serviceinstances');
-        expect(MockModelStore.query).toHaveBeenCalledWith(`ServiceInstanceLink`, '/core/serviceinstancelinks');
-        expect(service.ServiceInstanceSubscription).toBeDefined();
-        expect(service.ServiceInstanceLinkSubscription).toBeDefined();
+      serviceInstances.forEach(si => {
+        service.addNode(si);
+      });
+
+      serviceInstanceLinks.forEach(sil => {
+        service.addEdge(sil);
       });
     });
 
-    describe('when they are enabled', () => {
-      beforeEach(() => {
-        service.ServiceInstanceSubscription = {
-          unsubscribe: jasmine.createSpy('ServiceInstanceSubscription')
-        };
-        service.ServiceInstanceLinkSubscription = {
-          unsubscribe: jasmine.createSpy('ServiceInstanceLinkSubscription')
-        };
-        service.serviceInstanceShown = true;
-      });
+    it('should cancel subscriptions', () => {
+      service.removeServiceInstances();
+      expect(service.ServiceInstanceSubscription.unsubscribe).toHaveBeenCalled();
+      expect(service.ServiceInstanceLinkSubscription.unsubscribe).toHaveBeenCalled();
+    });
 
-      it('should cancel subscriptions', () => {
-        service.toggleServiceInstances();
-        expect(service.serviceInstanceShown).toBeFalsy();
-        expect(service.ServiceInstanceSubscription.unsubscribe).toHaveBeenCalled();
-        expect(service.ServiceInstanceLinkSubscription.unsubscribe).toHaveBeenCalled();
-      });
-
-      describe('and loaded in the graph', () => {
-        beforeEach(() => {
-          service.serviceGraph = new Graph();
-
-          services.forEach(s => {
-            service.addNode(s);
-          });
-
-          serviceInstances.forEach(si => {
-            service.addNode(si);
-          });
-
-          serviceInstanceLinks.forEach(sil => {
-            service.addEdge(sil);
-          });
-        });
-        it('should remove ServiceInstance and related nodes/edges from the graph', () => {
-          let filteredGraph = service.toggleServiceInstances();
-          expect(service.serviceInstanceShown).toBeFalsy();
-          expect(filteredGraph.nodes().length).toBe(2);
-          expect(filteredGraph.edges().length).toBe(0);
-          expect(service.serviceGraph.nodes().length).toBe(2);
-          expect(service.serviceGraph.edges().length).toBe(0);
-        });
-      });
+    it('should remove ServiceInstance and related nodes/edges from the graph', () => {
+      let filteredGraph = service.removeServiceInstances();
+      expect(filteredGraph.nodes().length).toBe(2);
+      expect(filteredGraph.edges().length).toBe(0);
+      expect(service.serviceGraph.nodes().length).toBe(2);
+      expect(service.serviceGraph.edges().length).toBe(0);
     });
   });
 });
diff --git a/src/app/service-graph/services/graph.store.ts b/src/app/service-graph/services/graph.store.ts
index 52100e7..cf438e6 100644
--- a/src/app/service-graph/services/graph.store.ts
+++ b/src/app/service-graph/services/graph.store.ts
@@ -29,9 +29,12 @@
   get(): Observable<Graph>;
   nodesFromGraph(graph: Graph): IXosSgNode[];
   linksFromGraph(graph: Graph): IXosSgLink[];
-  toggleServiceInstances(): Graph;
-  toggleInstances(): Graph;
-  toggleNetwork(): Graph;
+  addServiceInstances(): Graph;
+  removeServiceInstances(): Graph;
+  addInstances(): Graph;
+  removeInstances(): Graph;
+  addNetworks(): Graph;
+  removeNetworks(): Graph;
 }
 
 export class XosGraphStore implements IXosGraphStore {
@@ -41,11 +44,6 @@
     'XosDebouncer'
   ];
 
-  // state
-  private serviceInstanceShown: boolean = false;
-  private instanceShown: boolean = false;
-  private networkShown: boolean = false;
-
   // graphs
   private serviceGraph: any;
   private ServiceGraphSubject: BehaviorSubject<any>;
@@ -141,70 +139,47 @@
     });
   }
 
-  public toggleServiceInstances(): Graph {
-    if (this.serviceInstanceShown) {
-      // NOTE remove subscriptions
-      this.ServiceInstanceSubscription.unsubscribe();
-      this.ServiceInstanceLinkSubscription.unsubscribe();
-
-      // remove nodes from the graph
-      this.removeElementsFromGraph('serviceinstance'); // NOTE links are automatically removed by the graph library
-
-      if (this.instanceShown) {
-        // NOTE if we remove ServiceInstances we also need to remove Instances
-        this.removeElementsFromGraph('instance');
-        this.instanceShown = false;
-      }
-
-      if (this.networkShown) {
-        // NOTE if we remove ServiceInstances we also need to remove Networks
-        this.removeElementsFromGraph('network');
-        this.networkShown = false;
-      }
-    }
-    else {
-      // NOTE subscribe to ServiceInstance and ServiceInstanceLink observables
-      this.loadServiceInstances();
-      this.loadServiceInstanceLinks();
-    }
-    this.serviceInstanceShown = !this.serviceInstanceShown;
+  public addServiceInstances(): Graph {
+    this.loadServiceInstances();
+    this.loadServiceInstanceLinks();
     return this.serviceGraph;
   }
 
-  public toggleInstances(): Graph {
-    if (this.instanceShown) {
+  public removeServiceInstances(): Graph {
+    // NOTE remove subscriptions
+    this.ServiceInstanceSubscription.unsubscribe();
+    this.ServiceInstanceLinkSubscription.unsubscribe();
 
-      this.InstanceSubscription.unsubscribe();
-      this.TenantWithContainerSubscription.unsubscribe();
-
-      this.removeElementsFromGraph('instance'); // NOTE links are automatically removed by the graph library
-
-      if (this.networkShown) {
-        // NOTE if we remove Instances we also need to remove Networks
-        this.removeElementsFromGraph('network');
-        this.networkShown = false;
-      }
-    }
-    else {
-      this.loadInstances();
-      this.loadInstanceLinks();
-    }
-    this.instanceShown = !this.instanceShown;
+    // remove nodes from the graph
+    this.removeElementsFromGraph('serviceinstance');
     return this.serviceGraph;
   }
 
-  public toggleNetwork() {
-    if (this.networkShown) {
-      this.NetworkSubscription.unsubscribe();
-      this.PortSubscription.unsubscribe();
-      this.removeElementsFromGraph('network');
-    }
-    else {
-      this.loadNetworks();
-      this.loadPorts(); // Ports define the connection of an Instance to a Network
-    }
+  public addInstances(): Graph {
+    this.loadInstances();
+    this.loadInstanceLinks();
+    return this.serviceGraph;
+  }
 
-    this.networkShown = !this.networkShown;
+  public removeInstances(): Graph {
+    this.InstanceSubscription.unsubscribe();
+    this.TenantWithContainerSubscription.unsubscribe();
+
+    this.removeElementsFromGraph('instance');
+
+    return this.serviceGraph;
+  }
+
+  public addNetworks(): Graph {
+    this.loadNetworks();
+    this.loadPorts();
+    return this.serviceGraph;
+  }
+
+  public removeNetworks(): Graph {
+    this.NetworkSubscription.unsubscribe();
+    this.PortSubscription.unsubscribe();
+    this.removeElementsFromGraph('network');
     return this.serviceGraph;
   }