Add remote logging server

Remote logging enables the user to configure a remote
server to stream out local logs. This feature will be
available on the Event Log page. The user can add a
remote server, edit/change an existing server
configuration and remove/disable the remote server.

Resolves openbmc/phosphor-webui#68

Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com>
Change-Id: I8284cbdbdaaf85f5c95f237efc72290c66904b40
diff --git a/app/server-health/controllers/log-controller.html b/app/server-health/controllers/log-controller.html
index 0a985c5..34a2ec3 100644
--- a/app/server-health/controllers/log-controller.html
+++ b/app/server-health/controllers/log-controller.html
@@ -1,7 +1,12 @@
 <loader loading="loading"></loader>
 <div id="event-log">
   <div class="row column">
-    <h1>Event log</h1>
+   <div class="column small-6 large-7 no-padding">
+     <h1>Event log</h1>
+   </div>
+   <div class="column small-6 large-5">
+     <remote-logging-server class="remote-logging-server"></remote-logging-server>
+   </div>
   </div>
   <section class="row column">
     <div class="page-header">
diff --git a/app/server-health/directives/remote-logging-server-modal.html b/app/server-health/directives/remote-logging-server-modal.html
new file mode 100644
index 0000000..eba57af
--- /dev/null
+++ b/app/server-health/directives/remote-logging-server-modal.html
@@ -0,0 +1,42 @@
+<div role="dialog" class="uib-modal__content  remote-logging-server__modal">
+  <button type="button" class="icon  icon__close  float-right" ng-click="$close()"></button>
+  <div class="modal-header">
+    <h2 class="modal-title" id="dialog_label">{{activeModalProps.title}}</h2>
+  </div>
+  <form name="form">
+    <div ng-if="activeModal !== 2" class="modal-body">
+      <label for="remoteServerIP">Hostname or IP Address</label>
+      <input id="remoteServerIP" type="text" required name="hostname"
+        ng-model="remoteServerForm.hostname" />
+      <div ng-if="form.hostname.$invalid && form.hostname.$dirty"
+        class="form__validation-message">
+        <span ng-show="form.hostname.$error.required">Field is required</span>
+      </div>
+      <label for="remoteServerPort">Port</label>
+      <p class="label__helper-text">Value must be between 0 – 65535</p>
+      <input id="remoteServerPort" type="number" required name="port"
+        min="0" max="65535" ng-model="remoteServerForm.port"/>
+      <div ng-if="form.port.$invalid && form.port.$dirty"
+        class="form__validation-message">
+        <span ng-show="form.port.$error.required">Field is required</span>
+        <span ng-show="form.port.$error.min || form.port.$error.max">
+          Value must be between 0 – 65535
+        </span>
+      </div>
+    </div>
+    <div ng-if="activeModal === 2" class="modal-body">
+      <p>Are you sure you want to remove remote logging server
+      {{remoteServer.hostname}}?</p>
+    </div>
+    <div class="modal-footer">
+      <button class="button btn-secondary" ng-click="$close()" type="button">
+        Cancel
+      </button>
+      <button class="button btn-primary" type="submit"
+        ng-click="$close(activeModal)" ng-disabled="form.$invalid"
+        ng-class="{'disabled': form.$invalid}">
+        {{activeModalProps.actionLabel}}
+      </button>
+    </div>
+  </form>
+</div>
diff --git a/app/server-health/directives/remote-logging-server.html b/app/server-health/directives/remote-logging-server.html
new file mode 100644
index 0000000..28fc313
--- /dev/null
+++ b/app/server-health/directives/remote-logging-server.html
@@ -0,0 +1,21 @@
+<p class="content-label">Remote Logging Server</p>
+<div ng-if="!loadError && !remoteServer">
+  <button ng-click="initModal(0)" class="modal__trigger">
+    <span class="icon  icon__plus"></span>
+    Add server
+  </button>
+</div>
+<div ng-if="!loadError && remoteServer">
+  <p class="inline remote-logging-server__details">
+    {{remoteServer.hostname}}
+  </p>
+  <button ng-click="initModal(1)" class="modal__trigger">
+    <span class="icon icon__edit"></span>
+  </button>
+  <button ng-click="initModal(2)" class="modal__trigger">
+    <span class="icon icon__delete"></span>
+  </button>
+</div>
+<div class="text-right" ng-if="loadError">
+  <p>--</p>
+</div>
diff --git a/app/server-health/directives/remote-logging-server.js b/app/server-health/directives/remote-logging-server.js
new file mode 100644
index 0000000..4e8ad6f
--- /dev/null
+++ b/app/server-health/directives/remote-logging-server.js
@@ -0,0 +1,157 @@
+window.angular && (function(angular) {
+  'use strict';
+
+  angular.module('app.common.directives').directive('remoteLoggingServer', [
+    'APIUtils',
+    function(APIUtils) {
+      return {
+        'restrict': 'E', 'template': require('./remote-logging-server.html'),
+            'controller': [
+              '$scope', '$uibModal', 'toastService',
+              function($scope, $uibModal, toastService) {
+                const modalActions = {
+                  ADD: 0,
+                  EDIT: 1,
+                  REMOVE: 2,
+                  properties: {
+                    0: {
+                      title: 'Add remote logging server',
+                      actionLabel: 'Add',
+                      successMessage: 'Connected to remote logging server.',
+                      errorMessage: 'Unable to connect to server.'
+                    },
+                    1: {
+                      title: 'Edit remote logging server',
+                      actionLabel: 'Save',
+                      successMessage: 'Connected to remote logging server.',
+                      errorMessage: 'Unable to save remote logging server.'
+                    },
+                    2: {
+                      title: 'Remove remote logging server',
+                      actionLabel: 'Remove',
+                      successMessage: 'Remote logging server removed.',
+                      errorMessage: 'Unable to remove remote logging server.'
+                    }
+                  }
+                };
+
+                const modalTemplate =
+                    require('./remote-logging-server-modal.html');
+
+                $scope.activeModal;
+                $scope.activeModalProps;
+
+                $scope.remoteServer;
+                $scope.remoteServerForm;
+                $scope.loadError = true;
+
+                $scope.initModal = (type) => {
+                  if (type === undefined) {
+                    return;
+                  }
+                  $scope.activeModal = type;
+                  $scope.activeModalProps = modalActions.properties[type];
+
+                  $uibModal
+                      .open({
+                        template: modalTemplate,
+                        windowTopClass: 'uib-modal',
+                        scope: $scope,
+                        ariaLabelledBy: 'dialog_label'
+                      })
+                      .result
+                      .then((action) => {
+                        switch (action) {
+                          case modalActions.ADD:
+                            addServer();
+                            break;
+                          case modalActions.EDIT:
+                            editServer();
+                            break;
+                          case modalActions.REMOVE:
+                            removeServer();
+                            break;
+                          default:
+                            setFormValues();
+                        }
+                      })
+                      .catch(() => {
+                        // reset form when modal overlay clicked
+                        // and modal closes
+                        setFormValues();
+                      })
+                };
+
+                const addServer = () => {
+                  $scope.loading = true;
+                  APIUtils.setRemoteLoggingServer($scope.remoteServerForm)
+                      .then(() => {
+                        $scope.loading = false;
+                        $scope.remoteServer = {...$scope.remoteServerForm};
+                        toastService.success(
+                            $scope.activeModalProps.successMessage);
+                      })
+                      .catch(() => {
+                        $scope.loading = false;
+                        $scope.remoteServer = undefined;
+                        setFormValues();
+                        toastService.error(
+                            $scope.activeModalProps.errorMessage);
+                      })
+                };
+
+                const editServer = () => {
+                  $scope.loading = true;
+                  APIUtils.updateRemoteLoggingServer($scope.remoteServerForm)
+                      .then(() => {
+                        $scope.loading = false;
+                        $scope.remoteServer = {...$scope.remoteServerForm};
+                        toastService.success(
+                            $scope.activeModalProps.successMessage);
+                      })
+                      .catch(() => {
+                        $scope.loading = false;
+                        setFormValues();
+                        toastService.error(
+                            $scope.activeModalProps.errorMessage);
+                      })
+                };
+
+                const removeServer = () => {
+                  $scope.loading = true;
+                  APIUtils.disableRemoteLoggingServer()
+                      .then(() => {
+                        $scope.loading = false;
+                        $scope.remoteServer = undefined;
+                        setFormValues();
+                        toastService.success(
+                            $scope.activeModalProps.successMessage);
+                      })
+                      .catch(() => {
+                        $scope.loading = false;
+                        toastService.error(
+                            $scope.activeModalProps.errorMessage);
+                      })
+                };
+
+                const setFormValues = () => {
+                  $scope.remoteServerForm = {...$scope.remoteServer};
+                };
+
+                this.$onInit = () => {
+                  APIUtils.getRemoteLoggingServer()
+                      .then((remoteServer) => {
+                        $scope.loadError = false;
+                        $scope.remoteServer = remoteServer;
+                        setFormValues();
+                      })
+                      .catch(() => {
+                        $scope.loadError = true;
+                      })
+                };
+              }
+            ]
+      }
+    }
+  ])
+})(window.angular);
\ No newline at end of file
diff --git a/app/server-health/styles/log.scss b/app/server-health/styles/log.scss
index cc58a60..675dc26 100644
--- a/app/server-health/styles/log.scss
+++ b/app/server-health/styles/log.scss
@@ -370,6 +370,34 @@
   word-break: break-word;
 }
 
+.remote-logging-server {
+  float: right;
+  .modal__trigger {
+    padding: 0;
+    color: $primebtn__bg;
+    .icon {
+      margin: 0;
+      width: 20px;
+      height: 20px;
+      vertical-align: text-bottom;
+    }
+  }
+}
+
+.remote-logging-server__details {
+  margin-right: 0.4em;
+}
+
+.remote-logging-server__modal {
+  input {
+    margin-bottom: 30px;
+    max-width: 70%;
+    + .form__validation-message {
+      position: absolute;
+      margin-top: -30px;
+    }
+  }
+}
 //end event-log__events