Display log events in user time
Allows user to display events in their timezone or in UTC.
Previously allowed either ETC or UTC, but listed ETC as
'user timezone'. Updates date time page from GMT offset to
UTC offset for overall consistency. Also updates overview
page to list critical events in user timezone
Resolves openbmc/phosphor-webui#36
Tested: changed timezone settings locally and validated
that correct timezone and UTC offset was presented in
the UI.
Change-Id: I89ca5045eeb789527aa07f5b1baebaa3fbd6b1fa
Signed-off-by: beccabroek <beccabroek@gmail.com>
diff --git a/app/common/directives/log-event.html b/app/common/directives/log-event.html
index b2ab09e..3ec3c91 100644
--- a/app/common/directives/log-event.html
+++ b/app/common/directives/log-event.html
@@ -1,65 +1,67 @@
<div class="row column event-log__single-event"
- ng-class="{'active': event.meta, 'selected': event.selected}">
- <div class="row">
- <div class="inline__confirm" ng-class="{active: event.confirm}">
- <div class="inline__confirm-message">
- <p class="h3"><i></i>Are you sure you want to <strong class="ng-binding">delete this
- event</strong>?</p>
- </div>
- <div class="inline__confirm-buttons">
- <button class="btn-primary" ng-click="accept(event)">Yes</button>
- <button class="btn-primary" ng-click="event.confirm=false;">No</button>
- </div>
- </div>
- <div class="column small-1 large-2 event-log__col-check">
- <label class="control-check">
- <input type="checkbox" name="events__check" ng-click="event.selected= ! event.selected"
- ng-checked="event.selected"/>
- <span class="control__indicator"></span>
- </label>
- </div>
- <div class="column small-9 large-10 event-log__event-info"
- ng-click="event.meta = ! event.meta">
- <p class="inline event__id">#{{event.Id}}</p>
- <p class="inline event__priority event-resolved" ng-hide="event.Resolved == 0">Resolved</p>
- <p class="inline event__priority" ng-class="{'low-priority': event.priority == 'Low', 'medium-priority': event.priority == 'Medium', 'high-priority': event.priority == 'High'}">{{event.priority}}</p>
- <p class="inline event__severity" ng-class="{'low-priority': event.priority == 'Low', 'medium-priority': event.priority == 'Medium', 'high-priority': event.priority == 'High'}">{{event.severity_code}}</p>
- <p class="inline event__timestamp">{{(event.Timestamp | date:'medium': tmz) + ' ' + tmz}}</p></div>
- <div>
- <p class="inline event__description">{{getTitle(event)}}</p>
- </div>
- <div class="column small-1 large-1">
- <button class="accord-trigger" ng-class="{'active': event.meta}"
- ng-click="event.meta = ! event.meta"></button>
- </div>
+ ng-class="{'active': event.meta, 'selected': event.selected}">
+ <div class="row">
+ <div class="inline__confirm" ng-class="{active: event.confirm}">
+ <div class="inline__confirm-message">
+ <p class="h3"><i></i>Are you sure you want to <strong class="ng-binding">delete this event</strong>?</p>
+ </div>
+ <div class="inline__confirm-buttons">
+ <button class="btn-primary" ng-click="accept(event)">Yes</button>
+ <button class="btn-primary" ng-click="event.confirm=false;">No</button>
+ </div>
+ </div>
+ <div class="row">
+ <div class="column small-1 large-2 event-log__col-check">
+ <label class="control-check">
+ <input type="checkbox" name="events__check" ng-click="event.selected= ! event.selected"
+ ng-checked="event.selected"/>
+ <span class="control__indicator"></span>
+ </label>
+ </div>
+ <div class="column small-9 large-10 event-log__event-info"
+ ng-click="event.meta = ! event.meta">
+ <p class="inline event__id">#{{event.Id}}</p>
+ <p class="inline event__priority event-resolved" ng-hide="event.Resolved == 0">Resolved</p>
+ <p class="inline event__priority" ng-class="{'low-priority': event.priority == 'Low', 'medium-priority': event.priority == 'Medium', 'high-priority': event.priority == 'High'}">{{event.priority}}</p>
+ <p class="inline event__severity" ng-class="{'low-priority': event.priority == 'Low', 'medium-priority': event.priority == 'Medium', 'high-priority': event.priority == 'High'}">{{event.severity_code}}</p>
+ <p class="event__timestamp">{{(tmz == 'UTC' ? (event.Timestamp | date:'medium': tmz) : (event.Timestamp | date:'medium')) + ' ' + tmz}}</p>
+ <div>
+ <p class="inline event__description">{{getTitle(event)}}</p>
</div>
- <div class="row event__metadata-row" ng-class="{'active': event.meta}">
- <div class="column small-1 large-1 event-log__col-check"> </div>
- <div class="column small-11 large-11 end">
- <div class="event__metadata">{{getAdditionalData(event)}}
- </div>
- <div>
- <div class="event__actions">
- <button class="btn-meta-copy" clipboard text="copyText(event)" on-copied="copySuccess(event)" on-error="copyfailed(err)">
- <img class="event__icon" src="../../assets/images/icon-copy.svg" alt=""/><span ng-if="!event.copied">Copy</span><span ng-if="event.copied">Copied</span>
- </button>
- <button
- class="btn-delete"
- ng-class="{'disabled': multiSelected}"
- ng-click="event.confirm= ! event.confirm"
- ng-disabled="multiSelected">
- <img
- class="event__icon"
- src="../../assets/images/icon-trashcan.svg"
- alt=""/>Delete
- </button>
- <button class="btn-resolve" ng-class="{'disabled': (event.Resolved == 1 || multiSelected)}" ng-click="resolveEvent(event)" ng-disabled="event.Resolved == 1 || multiSelected"><img class="event__icon" src="../../assets/images/icon-check.svg" alt=""/>Mark as resolved</button>
- </div>
- <div class="event__related" ng-show="event.related_items.length">
- <p class="inline event__related-label">Related items:</p>
- <p class="event__related-item" ng-repeat="item in event.related_items">{{item}}</p>
- </div>
- </div>
- </div>
- </div>
+ </div>
+ <div class="column small-1 large-1">
+ <button class="accord-trigger" ng-class="{'active': event.meta}"
+ ng-click="event.meta = ! event.meta"></button>
+ </div>
+ </div>
+ <div class="row event__metadata-row" ng-class="{'active': event.meta}">
+ <div class="column small-1 large-1 event-log__col-check"> </div>
+ <div class="column small-11 large-11 end">
+ <div class="event__metadata">{{getAdditionalData(event)}}
+ </div>
+ <div>
+ <div class="event__actions">
+ <button class="btn-meta-copy" clipboard text="copyText(event)" on-copied="copySuccess(event)" on-error="copyfailed(err)">
+ <img class="event__icon" src="../../assets/images/icon-copy.svg" alt=""/><span ng-if="!event.copied">Copy</span><span ng-if="event.copied">Copied</span>
+ </button>
+ <button
+ class="btn-delete"
+ ng-class="{'disabled': multiSelected}"
+ ng-click="event.confirm= ! event.confirm"
+ ng-disabled="multiSelected">
+ <img
+ class="event__icon"
+ src="../../assets/images/icon-trashcan.svg"
+ alt=""/>Delete
+ </button>
+ <button class="btn-resolve" ng-class="{'disabled': (event.Resolved == 1 || multiSelected)}" ng-click="resolveEvent(event)" ng-disabled="event.Resolved == 1 || multiSelected"><img class="event__icon" src="../../assets/images/icon-check.svg" alt=""/>Mark as resolved</button>
+ </div>
+ <div class="event__related" ng-show="event.related_items.length">
+ <p class="inline event__related-label">Related items:</p>
+ <p class="event__related-item" ng-repeat="item in event.related_items">{{item}}</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
</div>
diff --git a/app/common/styles/elements/quicklinks.scss b/app/common/styles/elements/quicklinks.scss
index 25dab0f..aeb7f5f 100644
--- a/app/common/styles/elements/quicklinks.scss
+++ b/app/common/styles/elements/quicklinks.scss
@@ -1,7 +1,7 @@
//Quick links block
.quick-links {
background-color: $lightgrey;
- padding: 1em 1.4em;
+ padding: .5em 1em;
font-size: .9em;
font-weight: 400;
margin: 1em 0;
@@ -35,6 +35,11 @@
transform: translateY(-50%);
}
&.no-icon {
+ overflow: auto;
+ .bmc-time {
+ text-align: right;
+ max-width: 17em;
+ }
&:after {
display: none;
}
diff --git a/app/configuration/controllers/date-time-controller.js b/app/configuration/controllers/date-time-controller.js
index aca4c4c..5d2459d 100644
--- a/app/configuration/controllers/date-time-controller.js
+++ b/app/configuration/controllers/date-time-controller.js
@@ -36,9 +36,10 @@
// Don't care about milliseconds and don't want them displayed
$scope.bmc.date.setMilliseconds(0);
// https://stackoverflow.com/questions/1091372/getting-the-clients-timezone-in-javascript
- // GMT-0400 (EDT)
+ // EDT (UTC - 04:00)
$scope.bmc.timezone =
- $scope.bmc.date.toString().match(/([A-Z]+[\+-][0-9]+.*)/)[1];
+ $scope.bmc.date.toString().match(/\(([A-Za-z\s].*)\)/)[1] +
+ ' ' + createOffset($scope.bmc.date);
}
if (data.data[timePath + 'host'] &&
data.data[timePath + 'host'].hasOwnProperty('Elapsed')) {
@@ -184,6 +185,17 @@
// microseconds.
return APIUtils.setHostTime(time);
}
+ function createOffset(date) {
+ // https://stackoverflow.com/questions/9149556/how-to-get-utc-offset-in-javascript-analog-of-timezoneinfo-getutcoffset-in-c
+ var sign = (date.getTimezoneOffset() > 0) ? '-' : '+';
+ var offset = Math.abs(date.getTimezoneOffset());
+ var hours = pad(Math.floor(offset / 60));
+ var minutes = pad(offset % 60);
+ return '(UTC' + sign + hours + ':' + minutes + ')';
+ }
+ function pad(value) {
+ return value < 10 ? '0' + value : value;
+ }
}
]);
})(angular);
diff --git a/app/overview/controllers/system-overview-controller.html b/app/overview/controllers/system-overview-controller.html
index 5a05bc2..48ede3e 100644
--- a/app/overview/controllers/system-overview-controller.html
+++ b/app/overview/controllers/system-overview-controller.html
@@ -85,7 +85,7 @@
</a>
<div class="quick-links__item no-icon">
<p class="inline quick-links__label">BMC time</p>
- <p class="inline courier-bold float-right">{{bmc_time | date:'medium'}}</p>
+ <p class="inline courier-bold float-right bmc-time">{{(bmc_time | date:'medium') + ' ' + tmz}}</p>
</div>
<div class="quick-links__item no-icon">
<p class="inline quick-links__label">Turn <span ng-if="dataService.LED_state == 'off'">on</span><span ng-if="dataService.LED_state == 'on'">off</span> server LED</p>
@@ -132,7 +132,7 @@
<p class="inline event__id">#{{event.Id}}</p>
<p class="inline event__priority high-priority">High</p>
<p class="inline event__severity high-priority">{{event.severity_code}}</p>
- <p class="inline event__timestamp">{{(event.Timestamp | date:'medium': tmz) + ' ' + tmz}}</p>
+ <p class="inline event__timestamp">{{(event.Timestamp | date:'medium') + ' ' + tmz}}</p>
<div>
<p class="inline event__description">{{getEventLogTitle(event)}}</p>
</div>
diff --git a/app/overview/controllers/system-overview-controller.js b/app/overview/controllers/system-overview-controller.js
index e7d9c6b..6393ebc 100644
--- a/app/overview/controllers/system-overview-controller.js
+++ b/app/overview/controllers/system-overview-controller.js
@@ -14,7 +14,7 @@
function($scope, $window, APIUtils, dataService, Constants, $q) {
$scope.dataService = dataService;
$scope.dropdown_selected = false;
- $scope.tmz = 'EDT';
+ $scope.tmz = getUserTimezone();
$scope.logs = [];
$scope.server_info = {};
$scope.bmc_firmware = '';
@@ -159,6 +159,9 @@
}
return title;
};
+ function getUserTimezone() {
+ return new Date().toString().match(/\(([A-Za-z\s].*)\)/)[1];
+ }
}
]);
})(angular);
diff --git a/app/server-health/controllers/log-controller.html b/app/server-health/controllers/log-controller.html
index 8fc99bc..62bd831 100644
--- a/app/server-health/controllers/log-controller.html
+++ b/app/server-health/controllers/log-controller.html
@@ -1,75 +1,76 @@
<loader loading="loading"></loader>
<div id="event-log">
- <div class="row column">
- <h1>Event log</h1>
+ <div class="row column">
+ <h1>Event log</h1>
+ </div>
+ <section class="row column">
+ <div class="page-header">
+ <h2 class="inline h4">All events from the BMC</h2>
+ <div class="event-log__timezone inline float-right">
+ <button class="dropdown__button" ng-click="timezone = timezone == true ? false : true;" toggle-flag="timezone">
+ <span>{{tmz === 'UTC'? 'UTC Timezone' : 'User Timezone'}}</span>
+ </button>
+ <ul class="dropdown__list inline" ng-show="timezone">
+ <li>
+ <button ng-click="selectUserTimezone();">User Timezone</button>
+ </li>
+ <li>
+ <button ng-click="tmz = 'UTC'">UTC Timezone</button>
+ </li>
+ </ul>
+ </div>
</div>
- <section class="row column">
- <div class="page-header">
- <h2 class="inline h4">All events from the BMC</h2>
- <div class="event-log__timezone inline float-right">
- <button class="dropdown__button" ng-click="timezone = timezone == true ? false : true;" toggle-flag="timezone"
- >User timezone: <span ng-show="tmz== 'EDT'">EDT (UTC-4)</span><span ng-show="tmz=='UTC'">UTC - 0</span>
- </button>
- <ul class="dropdown__list inline" ng-show="timezone">
- <li>
- <button ng-click="tmz = 'EDT'; timezone=false;">User timezone: EDT (UTC-4)</button>
- </li>
- <li>
- <button ng-click="tmz = 'UTC'; timezone=false;">UTC Timezone : UTC - 0</button>
- </li>
- </ul>
- </div>
- </div>
- </section>
- <!-- Filters -->
- <section class="row column">
- <!-- search -->
- <log-search-control></log-search-control>
- <!-- filters -->
- <log-filter></log-filter>
- </section> <!-- end filter -->
+ </section>
+ <!-- Filters -->
+ <section class="row column">
+ <!-- search -->
+ <log-search-control></log-search-control>
+ <!-- filters -->
+ <log-filter></log-filter>
+ </section>
+ <!-- end filter -->
- <section id="event-log__events" class="row column">
- <div id="event__actions-bar" class="row header__actions-bar no-margin">
- <div class="column small-1 large-1 event-log__col-check">
- <label class="control-check">
- <input type="checkbox" name="events__check-all" ng-model="all" ng-checked="((filteredLogs|filter:{selected: true}).length == filteredLogs.length) && filteredLogs.length != 0"/>
- <span class="control__indicator"></span>
- </label>
- </div>
- <div class="column small-11 end col-logged-events">
- <!-- top bar confirmation - ADD ACTIVE CLASS TO DISPLAY-->
- <div class="inline__confirm event__confirm" ng-class="{active: confirm}">
- <div class="inline__confirm-message">
- <p class="h3"><i></i>Are you sure you want to <strong class="ng-binding">delete {{selectedEvents.length}} logs</strong>?
- </p>
- </div>
- <div class="inline__confirm-buttons">
- <button class="btn-primary" ng-click="accept()">Yes</button>
- <button class="btn-primary" ng-click="confirm = false">No</button>
- </div>
- </div>
- <p class="inline" ng-show="selectedEvents.length"><span class="event__select-count">{{selectedEvents.length}}</span> Events are selected</p>
- <p class="inline" ng-hide="selectedEvents.length"><span class="event__select-count">{{filteredLogs.length}}</span> Events are logged</p>
- <!-- when logs are selected, this text changes to show how many logs are checked -->
- <div class="event__actions">
- <button class="inline btn-delete" ng-show="selectedEvents.length || all" ng-click="confirm= ! confirm">
- <img class="event__icon" src="../../assets/images/icon-trashcan-white.svg" alt="">Delete
- </button>
- <button class="inline btn-resolve" ng-class="{'disabled': ((selectedEvents|unResolvedCount) == 0)}" ng-show="selectedEvents.length || all" ng-click="resolve()" ng-disabled="(selectedEvents|unResolvedCount) == 0">
- <img class="event__icon" src="../../assets/images/icon-check-white.svg" alt="">Mark as resolved
- </button>
- <a ng-href="data:text/json;charset=utf-8,{{export_data}}" class="inline btn-export" download="{{export_name}}" ng-show="selectedEvents.length || all">Export</a>
- </div>
- </div>
+ <section id="event-log__events" class="row column">
+ <div id="event__actions-bar" class="row header__actions-bar no-margin">
+ <div class="column small-1 large-1 event-log__col-check">
+ <label class="control-check">
+ <input type="checkbox" name="events__check-all" ng-model="all" ng-checked="((filteredLogs|filter:{selected: true}).length == filteredLogs.length) && filteredLogs.length != 0"/>
+ <span class="control__indicator"></span>
+ </label>
+ </div>
+ <div class="column small-11 end col-logged-events">
+ <!-- top bar confirmation - ADD ACTIVE CLASS TO DISPLAY-->
+ <div class="inline__confirm event__confirm" ng-class="{active: confirm}">
+ <div class="inline__confirm-message">
+ <p class="h3"><i></i>Are you sure you want to <strong class="ng-binding">delete {{selectedEvents.length}} logs</strong>?
+ </p>
+ </div>
+ <div class="inline__confirm-buttons">
+ <button class="btn-primary" ng-click="accept()">Yes</button>
+ <button class="btn-primary" ng-click="confirm = false">No</button>
+ </div>
</div>
- <log-event
- dir-paginate="event in (filteredLogs = (logs|filter:filterBySeverity|filter:filterByStatus|filter:filterByDate|filter:filterBySearchTerms | orderBy:'-Id'))| itemsPerPage: itemsPerPage"
- event="event"
- tmz="tmz"
- multi-selected="selectedEvents.length > 1"
- >
- </log-event>
- <dir-pagination-controls></dir-pagination-controls>
- </section>
+ <p class="inline" ng-show="selectedEvents.length"><span class="event__select-count">{{selectedEvents.length}}</span> Events are selected</p>
+ <p class="inline" ng-hide="selectedEvents.length"><span class="event__select-count">{{filteredLogs.length}}</span> Events are logged</p>
+ <!-- when logs are selected, this text changes to show how many logs are checked -->
+ <div class="event__actions">
+ <button class="inline btn-delete" ng-show="selectedEvents.length || all" ng-click="confirm= ! confirm">
+ <img class="event__icon" src="../../assets/images/icon-trashcan-white.svg" alt="">Delete
+ </button>
+ <button class="inline btn-resolve" ng-class="{'disabled': ((selectedEvents|unResolvedCount) == 0)}" ng-show="selectedEvents.length || all" ng-click="resolve()" ng-disabled="(selectedEvents|unResolvedCount) == 0">
+ <img class="event__icon" src="../../assets/images/icon-check-white.svg" alt="">Mark as resolved
+ </button>
+ <a ng-href="data:text/json;charset=utf-8,{{export_data}}" class="inline btn-export" download="{{export_name}}" ng-show="selectedEvents.length || all">Export</a>
+ </div>
+ </div>
+ </div>
+ <log-event
+ dir-paginate="event in (filteredLogs = (logs|filter:filterBySeverity|filter:filterByStatus|filter:filterByDate|filter:filterBySearchTerms | orderBy:'-Id'))| itemsPerPage: itemsPerPage"
+ event="event"
+ tmz="tmz"
+ multi-selected="selectedEvents.length > 1"
+ >
+ </log-event>
+ <dir-pagination-controls></dir-pagination-controls>
+ </section>
</div> <!-- end event log -->
diff --git a/app/server-health/controllers/log-controller.js b/app/server-health/controllers/log-controller.js
index 5e6db6d..0303854 100644
--- a/app/server-health/controllers/log-controller.js
+++ b/app/server-health/controllers/log-controller.js
@@ -25,7 +25,7 @@
$scope.dataService = dataService;
$scope.logs = [];
$scope.filteredLogs = [];
- $scope.tmz = 'EDT';
+ $scope.tmz = '';
$scope.itemsPerPage = Constants.PAGINATION.LOG_ITEMS_PER_PAGE;
$scope.loading = false;
var expandedSelectedIdOnce = false;
@@ -69,6 +69,7 @@
dataService.updateServerHealth(result.data);
$scope.logs = result.data;
$scope.originalData = result.original;
+ $scope.selectUserTimezone();
$scope.loading = false;
});
};
@@ -159,6 +160,10 @@
$scope.export_data = JSON.stringify(data);
}
+ $scope.selectUserTimezone = function() {
+ $scope.tmz = new Date().toString().match(/\(([A-Za-z\s].*)\)/)[1];
+ };
+
$scope.accept = function() {
APIUtils.deleteLogs($scope.selectedEvents).then(function() {
$scope.confirm = false;
diff --git a/app/server-health/styles/log.scss b/app/server-health/styles/log.scss
index f50a152..50c19b6 100644
--- a/app/server-health/styles/log.scss
+++ b/app/server-health/styles/log.scss
@@ -283,10 +283,12 @@
}
.event__timestamp {
+ text-align: right;
@include fontCourierBold;
font-size: .9em;
color: $darkgrey;
- @media (min-width: 1105px ) {
+ max-width: 18em;
+ @media (min-width: 1105px) {
float: right;
}
}