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/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