Adding interfaces and fixing JSON parsing issues

Change-Id: I8675390ccd11020752d210332c1d7e2297823af2
diff --git a/xos/gui/.dockerignore b/xos/gui/.dockerignore
new file mode 100644
index 0000000..40b878d
--- /dev/null
+++ b/xos/gui/.dockerignore
@@ -0,0 +1 @@
+node_modules/
\ No newline at end of file
diff --git a/xos/gui/src/app/interfaces/rcord-subscriber.interface.ts b/xos/gui/src/app/interfaces/rcord-subscriber.interface.ts
new file mode 100644
index 0000000..57d2b84
--- /dev/null
+++ b/xos/gui/src/app/interfaces/rcord-subscriber.interface.ts
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+export interface IRCordSubscriber {
+  id: string;
+  service_specific_attribute: any; // stringified JSON
+}
+
+export interface IRCordSubscriberDevice {
+  name: string;
+  mac: string;
+  level: string;
+}
\ No newline at end of file
diff --git a/xos/gui/src/app/subscriber-dashboard/subscriber-dashboard.component.ts b/xos/gui/src/app/subscriber-dashboard/subscriber-dashboard.component.ts
index fb98e4c..8dcff63 100644
--- a/xos/gui/src/app/subscriber-dashboard/subscriber-dashboard.component.ts
+++ b/xos/gui/src/app/subscriber-dashboard/subscriber-dashboard.component.ts
@@ -16,8 +16,9 @@
 
 import * as _ from 'lodash';
 import './subscriber-dashboard.scss';
+import {IRCordSubscriber, IRCordSubscriberDevice} from '../interfaces/rcord-subscriber.interface';
 
-class rcordSubscriberDashboardCtrl {
+class RcordSubscriberDashboardCtrl {
 
   static $inject = [
     'toastr',
@@ -26,7 +27,7 @@
   ];
 
   public levelOptions = [];
-  public subscribers = [];
+  public subscribers: IRCordSubscriber[] = [];
   public statusFieldOptions = [];
   public slider = {
     floor: 0,
@@ -35,6 +36,7 @@
       return Math.floor(value / 1000000);
     }
   };
+  public selectedSubscriber: IRCordSubscriber;
 
   private subscriberDef;
 
@@ -66,40 +68,61 @@
     this.statusFieldOptions = _.find(this.subscriberDef.fields, {name: 'status'}).options;
   }
 
-  public addDevice(subscriber) {
+  public addDevice(subscriber: IRCordSubscriber) {
+    if (angular.isUndefined(subscriber.service_specific_attribute.devices)) {
+      subscriber.service_specific_attribute.devices = [];
+    }
     subscriber.service_specific_attribute.devices.push({
       name: '',
       mac: '',
       level: 'PG_13'
-    })
+    });
   }
 
-  public removeDevice(subscriber, device) {
-    _.remove(subscriber.service_specific_attribute.devices, {name:device.name})
+  public removeDevice(subscriber: IRCordSubscriber, device: IRCordSubscriberDevice) {
+    _.remove(subscriber.service_specific_attribute.devices, {name: device.name});
   }
 
-  public save(subscriber) {
-    console.log(subscriber);
+  public save(subscriber: IRCordSubscriber) {
     const item: any = angular.copy(subscriber);
+
+    _.forEach(Object.keys(item), prop => {
+      if (prop.indexOf('-formatted') > -1 || prop.indexOf('_ptr') > -1) {
+        delete item[prop];
+      }
+    });
+
     item.service_specific_attribute = JSON.stringify(item.service_specific_attribute);
     item.$save()
       .then(() => {
         this.toastr.success(`Subscriber successfully saved`);
+      })
+      .catch(e => {
+        this.toastr.error(`Error while saving subscriber`);
+        console.error(e);
       });
   }
 
-  private parseSubscribers(subscribers) {
+  private parseSubscribers(subscribers: IRCordSubscriber) {
     return _.map(subscribers, (s) => {
       if (angular.isString(s.service_specific_attribute)) {
-        s.service_specific_attribute = JSON.parse(s.service_specific_attribute);
+        try {
+          s.service_specific_attribute = JSON.parse(s.service_specific_attribute);
+        } catch (e) {
+          s.service_specific_attribute = {};
+        }
       }
       return s;
-    })
+    });
+  }
+
+  $onDestroy() {
+    this.selectedSubscriber.service_specific_attribute = JSON.stringify(this.selectedSubscriber.service_specific_attribute);
   }
 }
 
 export const rcordSubscriberDashboard: angular.IComponentOptions = {
   template: require('./subscriber-dashboard.html'),
   controllerAs: 'vm',
-  controller: rcordSubscriberDashboardCtrl
-};
\ No newline at end of file
+  controller: RcordSubscriberDashboardCtrl
+};