diff options
author | Yoshie Muranaka <yoshiemuranaka@gmail.com> | 2019-05-24 14:33:56 -0500 |
---|---|---|
committer | Gunnar Mills <gmills@us.ibm.com> | 2019-06-21 14:29:40 +0000 |
commit | e4194ce0dc8a941c4f30fd0995f9ba4c13cec560 (patch) | |
tree | 15887d0e4061b7dec40991f2f2fb8a590d9835af | |
parent | e4ae854c217344b4f35717e922083a253f43bfa0 (diff) | |
download | phosphor-webui-e4194ce0dc8a941c4f30fd0995f9ba4c13cec560.tar.gz phosphor-webui-e4194ce0dc8a941c4f30fd0995f9ba4c13cec560.zip |
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
-rw-r--r-- | app/common/services/api-utils.js | 59 | ||||
-rw-r--r-- | app/common/styles/base/forms.scss | 11 | ||||
-rw-r--r-- | app/common/styles/base/icons.scss | 15 | ||||
-rw-r--r-- | app/common/styles/elements/modals.scss | 25 | ||||
-rw-r--r-- | app/index.js | 3 | ||||
-rw-r--r-- | app/overview/controllers/system-overview-controller.html | 2 | ||||
-rw-r--r-- | app/server-health/controllers/log-controller.html | 7 | ||||
-rw-r--r-- | app/server-health/directives/remote-logging-server-modal.html | 42 | ||||
-rw-r--r-- | app/server-health/directives/remote-logging-server.html | 21 | ||||
-rw-r--r-- | app/server-health/directives/remote-logging-server.js | 157 | ||||
-rw-r--r-- | app/server-health/styles/log.scss | 28 |
11 files changed, 366 insertions, 4 deletions
diff --git a/app/common/services/api-utils.js b/app/common/services/api-utils.js index 6e46c9c..e796f43 100644 --- a/app/common/services/api-utils.js +++ b/app/common/services/api-utils.js @@ -1557,6 +1557,65 @@ window.angular && (function(angular) { }); return $q.all(promises); }, + setRemoteLoggingServer: (data) => { + const ip = data.hostname; + const port = data.port; + const setIPRequest = $http({ + method: 'PUT', + url: DataService.getHost() + + '/xyz/openbmc_project/logging/config/remote/attr/Address', + withCredentials: true, + data: {'data': ip} + }); + const setPortRequest = $http({ + method: 'PUT', + url: DataService.getHost() + + '/xyz/openbmc_project/logging/config/remote/attr/Port', + withCredentials: true, + data: {'data': port} + }); + const promises = [setIPRequest, setPortRequest]; + return $q.all(promises); + }, + getRemoteLoggingServer: () => { + return $http({ + method: 'GET', + url: DataService.getHost() + + '/xyz/openbmc_project/logging/config/remote', + withCredentials: true + }) + .then((response) => { + const remoteServer = response.data.data; + if (remoteServer === undefined) { + return undefined; + } + const hostname = remoteServer.Address; + const port = remoteServer.Port; + if (hostname === '') { + return undefined; + } else { + return { + hostname, port + } + } + }); + }, + disableRemoteLoggingServer: () => { + return SERVICE.setRemoteLoggingServer({hostname: '', port: 0}); + }, + updateRemoteLoggingServer: (data) => { + // Recommended to disable existing configuration + // before updating config to new server + // https://github.com/openbmc/phosphor-logging#changing-the-rsyslog-server + return SERVICE.disableRemoteLoggingServer() + .then(() => { + return SERVICE.setRemoteLoggingServer(data); + }) + .catch(() => { + // try updating server even if initial disable attempt fails + return SERVICE.setRemoteLoggingServer(data); + }); + }, getPowerConsumption: function() { return $http({ method: 'GET', diff --git a/app/common/styles/base/forms.scss b/app/common/styles/base/forms.scss index 21253e7..5e75bcc 100644 --- a/app/common/styles/base/forms.scss +++ b/app/common/styles/base/forms.scss @@ -10,6 +10,13 @@ label, legend { } } +.label__helper-text { + color: $darkgrey; + line-height: 1.2; + font-size: 0.9em; + margin-bottom: 0.4em; +} + input[type='email'], input[type='number'], input[type='password'], @@ -113,3 +120,7 @@ select{ max-height: none; } } +.form__validation-message { + color: $error-color; + font-size: 0.9em; +} diff --git a/app/common/styles/base/icons.scss b/app/common/styles/base/icons.scss index 43d3669..557c857 100644 --- a/app/common/styles/base/icons.scss +++ b/app/common/styles/base/icons.scss @@ -126,3 +126,18 @@ @extend .icon__up-arrow; transform: rotate(180deg); } + +.icon__edit { + @include status-icon; + background-image: url(../assets/images/icon-edit-blue.svg); +} + +.icon__delete { + @include status-icon; + background-image: url(../assets/images/icon-trashcan-blue.svg); +} + +.icon__close { + @include status-icon; + background-image: url(../assets/images/crit-x-black.svg); +} diff --git a/app/common/styles/elements/modals.scss b/app/common/styles/elements/modals.scss index 1a8b71f..0bb81d5 100644 --- a/app/common/styles/elements/modals.scss +++ b/app/common/styles/elements/modals.scss @@ -18,7 +18,7 @@ @include fastTransition-all; } -.modal { +.modal:not(.uib-modal) { width: auto; height: auto; left: 50%; @@ -79,3 +79,26 @@ } } } + +.uib-modal.fade.in { + opacity: 1; +} +.uib-modal.in .modal-dialog { + transform: translate(0, 10vh); + margin-top: 50px; + .icon__close { + margin: 0; + padding: 0; + } + .modal-content { + border-radius: 0; + border-color: $black; + } +} + +.modal-backdrop.in { + opacity: 0.5; +} +.uib-modal__content { + padding: 1em; +} diff --git a/app/index.js b/app/index.js index 6303142..1d54b45 100644 --- a/app/index.js +++ b/app/index.js @@ -22,7 +22,6 @@ import ngToast from 'ng-toast'; import ngToast_animate from 'ng-toast/dist/ngToast-animations.css'; import ngToast_style from 'ng-toast/dist/ngToast.css'; - require('./styles/index.scss'); var config = require('../config.json'); @@ -77,6 +76,7 @@ import log_controller from './server-health/controllers/log-controller.js'; import sensors_overview_controller from './server-health/controllers/sensors-overview-controller.js'; import syslog_controller from './server-health/controllers/syslog-controller.js'; import syslog_filter from './common/directives/syslog-filter.js'; +import remote_logging_server from './server-health/directives/remote-logging-server.js'; import redfish_index from './redfish/index.js'; import redfish_controller from './redfish/controllers/redfish-controller.js'; @@ -100,6 +100,7 @@ window.angular && (function(angular) { // Dependencies 'ngRoute', 'angular-clipboard', 'ngToast', 'ngAnimate', 'ngMessages', 'app.common.directives.dirPagination', 'ngSanitize', + 'ui.bootstrap', // Basic resources 'app.common.services', 'app.common.directives', 'app.common.filters', diff --git a/app/overview/controllers/system-overview-controller.html b/app/overview/controllers/system-overview-controller.html index 31e2917..0403a85 100644 --- a/app/overview/controllers/system-overview-controller.html +++ b/app/overview/controllers/system-overview-controller.html @@ -204,7 +204,7 @@ <form name="edit_hostname_text"> <label for="editServerName">Hostname</label> - <p>Hostname must be less than 64 characters and must not contain spaces.</p> + <p class="label__helper-text">Hostname must be less than 64 characters and must not contain spaces.</p> <input id="editServerName" class="modal__edit-server-name" type="text" ng-model="newHostname" ng-trim="false" name="hostname" ng-pattern="/^\S{0,64}$/" required autofocus /> <span class="modal__error" ng-show="edit_hostname_text.hostname.$error.pattern">Invalid format. 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 |