Commit 7d5d697a by Jeffrey Phillips Committed by GitHub

Merge pull request #62 from spadgett/data-service-toast

Use Patternfly toast notifications for DataService errors
parents c9f3be2c 8f350d39
......@@ -35,7 +35,6 @@
"hopscotch": "~0.2.7",
"jquery": "~2.1.4",
"lodash": "~3.10.1",
"messenger": "~1.4.1",
"patternfly": "~3.21.0",
"uri.js": "~1.18.0"
},
......
//
// Default messenger included here instead of including messenger.css
// -------------------------------------------------
ul.messenger.messenger-theme-flat {
margin: 0;
padding: 0;
opacity: 1;
.transition(all .2s ease .2s);
> li {
list-style: none;
margin: 0;
padding: 0;
&.messenger-shown {
}
}
.messenger-message {
.clearfix();
&.messenger-hidden {
display: none;
}
.messenger-phrase, .messenger-actions a {
// padding-right: 5px;
}
.messenger-actions {
float: right;
a {
cursor: pointer;
text-decoration: underline;
}
}
ul, ol {
margin: 10px 18px 0;
}
}
&.messenger-fixed {
position: fixed;
z-index: 10000;
.messenger-message {
min-width: 0;
.box-sizing(border-box);
}
.message .messenger-actions {
float: left;
}
&.messenger-on-top {
top: 20px;
}
&.messenger-on-bottom {
bottom: 20px;
}
&.messenger-on-top, &.messenger-on-bottom {
left: 50%;
width: 800px;
margin-left: -400px;
&.messenger-on-right {
right: 20px;
left: auto;
}
&.messenger-on-left {
left: 20px;
margin-left: 0px;
}
}
&.messenger-on-right, &.messenger-on-left {
width: 90%;
.messenger-actions {
float: left;
}
}
@media (min-width: @screen-sm-min) {
&.messenger-on-right {
width: 45%;
}
}
@media (min-width: @screen-lg-min) {
&.messenger-on-right {
width: 35%;
}
}
&.messenger-empty.messenger-fixed.messenger-on-bottom.messenger-on-right {
display: block;
opacity: 0;
bottom: 20%;
}
}
.messenger-spinner {
display: none;
}
.messenger-clickable {
cursor: pointer;
}
}
//
// Messenger Flat Theme modifications
// -------------------------------------------------
ul.messenger-theme-flat {
background-color: transparent;
&.messenger-empty {
display: none;
}
}
@insetBackgroundColor: darken(@gray-darker, 10%);
ul.messenger-theme-flat .messenger-message {
box-shadow: 0 0 6px rgba(0,0,0,.175), inset 0px 1px rgba(255, 255, 255, 0.13), inset 50px 0px 0px @insetBackgroundColor !important;
border-radius: 0 !important;
position: relative;
border: 0px;
margin-bottom: 0px;
font-size: @font-size-base;
background: @gray-darker;
color: #f0f0f0;
font-weight: 500;
padding: 10px 30px 10px 65px;
line-height: 27px;
&:before,
.messenger-message-inner:before {
font-size: 20px;
position: absolute;
left: 15px;
top: 50%;
margin-top: -10px;
font-family: 'PatternFlyIcons-webfont';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.messenger-close {
line-height: 30px;
}
}
ul.messenger-theme-flat .messenger-message .messenger-actions a {
text-decoration: none;
color: #aaaaaa;
background: lighten(@gray-darker, 5%);
}
ul.messenger-theme-flat {
.messenger-message.alert-error {
&:before {
content: @pficon-var-error-circle-o;
color: @brand-danger;
display: inline-block;
}
.messenger-message-inner:before {
background-color: transparent;
}
}
.messenger-message.alert-warning {
&:before {
content: @pficon-var-warning-triangle-o;
color: @brand-warning;
display: inline-block;
left: 14px;
margin-top: -11px;
}
}
.messenger-message.alert-success .messenger-message-inner:before {
color: @brand-success;
content: @pficon-var-ok;
display: inline-block;
background-color: transparent;
}
.messenger-message.alert-info .messenger-message-inner:before {
color: @brand-info;
content: @pficon-var-info;
display: inline-block;
background-color: transparent;
}
}
......@@ -3,7 +3,6 @@
@import "_core.less";
@import "_forms.less";
@import "_guided-tour.less";
@import "_messages.less";
@import "_mixins.less";
@import "_notifications.less";
@import "_ui-select.less";
......
......@@ -1007,7 +1007,7 @@ angular.module('openshiftCommonServices')
/* jshint eqeqeq: false, unused: false, expr: true */
angular.module('openshiftCommonServices')
.factory('DataService', function($cacheFactory, $http, $ws, $rootScope, $q, API_CFG, APIService, Notification, Logger, $timeout, base64, base64util) {
.factory('DataService', function($cacheFactory, $http, $ws, $rootScope, $q, API_CFG, APIService, Logger, $timeout, base64, base64util) {
function Data(array) {
this._data = {};
......@@ -1415,7 +1415,12 @@ angular.module('openshiftCommonServices')
if (status !== 0) {
msg += " (" + status + ")";
}
Notification.error(msg);
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
type: 'error',
message: msg
});
}
deferred.reject({
data: data,
......@@ -1955,7 +1960,12 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
if (status !== 0) {
msg += " (" + status + ")";
}
Notification.error(msg);
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
type: 'error',
message: msg
});
});
});
}
......@@ -1981,7 +1991,12 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
if (status !== 0) {
msg += " (" + status + ")";
}
Notification.error(msg);
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
type: 'error',
message: msg
});
});
}
};
......@@ -2166,12 +2181,18 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
if (this._isTooManyWebsocketRetries(key)) {
// Show an error notication unless disabled in opts.
if (_.get(opts, 'errorNotification', true)) {
Notification.error("Server connection interrupted.", {
id: "websocket_retry_halted",
mustDismiss: true,
actions: {
refresh: {label: "Refresh", action: function() { window.location.reload(); }}
}
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
id: 'websocket_retry_halted',
type: 'error',
message: 'Server connection interrupted.',
links: [{
label: 'Refresh',
onClick: function() {
window.location.reload();
}
}]
});
}
return;
......@@ -2644,68 +2665,6 @@ angular.module('openshiftCommonServices')
};
});
;'use strict';
/* jshint unused: false */
angular.module('openshiftCommonServices')
.factory('Notification', function($rootScope) {
function Notification() {
this.messenger = Messenger({
extraClasses: 'messenger-fixed messenger-on-bottom messenger-on-right',
theme: 'flat',
messageDefaults: {
showCloseButton: true,
hideAfter: 10
}
});
var self = this;
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
self.clear();
});
}
// Opts:
// id - if an id is passed only one message with this id will ever be shown
// mustDismiss - the user must explicitly dismiss the message, it will not auto-hide
Notification.prototype.notify = function(type, message, opts) {
opts = opts || {};
var notifyOpts = {
type: type,
// TODO report this issue upstream to messenger, they don't handle messages with invalid html
// they should be escaping it
message: $('<div/>').text(message).html(),
id: opts.id,
actions: opts.actions
};
if (opts.mustDismiss) {
notifyOpts.hideAfter = false;
}
this.messenger.post(notifyOpts);
};
Notification.prototype.success = function(message, opts) {
this.notify("success", message, opts);
};
Notification.prototype.info = function(message, opts) {
this.notify("info", message, opts);
};
Notification.prototype.error = function(message, opts) {
this.notify("error", message, opts);
};
Notification.prototype.warning = function(message, opts) {
this.notify("warning", message, opts);
};
Notification.prototype.clear = function() {
this.messenger.hideAll();
};
return new Notification();
});
;'use strict';
angular.module('openshiftCommonServices')
.factory('ProjectsService',
......
......@@ -1438,7 +1438,7 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
this.dismissDelay = 8000;
this.autoDismissTypes = ['info', 'success'];
this.$get = function() {
this.$get = function($rootScope) {
var notifications = [];
var dismissDelay = this.dismissDelay;
var autoDismissTypes = this.autoDismissTypes;
......@@ -1451,9 +1451,9 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
return 'hide/notification/' + namespace + '/' + notificationID;
};
var addNotification = function (notification, notificationID, namespace) {
if (notificationID && isNotificationPermanentlyHidden(notificationID, namespace)) {
notification.hidden = true;
var addNotification = function (notification) {
if (isNotificationPermanentlyHidden(notification) || isNotificationVisible(notification)) {
return;
}
notifications.push(notification);
......@@ -1467,8 +1467,12 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
_.take(notifications, 0);
};
var isNotificationPermanentlyHidden = function (notificationID, namespace) {
var key = notificationHiddenKey(notificationID, namespace);
var isNotificationPermanentlyHidden = function (notification) {
if (!notification.id) {
return false;
}
var key = notificationHiddenKey(notification.id, notification.namespace);
return localStorage.getItem(key) === 'true';
};
......@@ -1477,12 +1481,28 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
localStorage.setItem(key, 'true');
};
// Is there a visible toast notification with the same ID right now?
var isNotificationVisible = function (notification) {
if (!notification.id) {
return false;
}
return _.some(notifications, function(next) {
return !next.hidden && notification.id === next.id;
});
};
var isAutoDismiss = function(notification) {
return _.find(autoDismissTypes, function(type) {
return type === notification.type;
});
};
// Also handle `addNotification` events on $rootScope, which is used by DataService.
$rootScope.$on('addNotification', function(event, data) {
addNotification(data);
});
return {
addNotification: addNotification,
getNotifications: getNotifications,
......
......@@ -171,176 +171,6 @@ div.hopscotch-bubble .hopscotch-nav-button.next {
div.hopscotch-bubble .hopscotch-nav-button.prev {
color: #030303;
}
ul.messenger.messenger-theme-flat {
margin: 0;
padding: 0;
opacity: 1;
-webkit-transition: all 0.2s ease 0.2s;
-o-transition: all 0.2s ease 0.2s;
transition: all 0.2s ease 0.2s;
}
ul.messenger.messenger-theme-flat > li {
list-style: none;
margin: 0;
padding: 0;
}
ul.messenger.messenger-theme-flat .messenger-message:before,
ul.messenger.messenger-theme-flat .messenger-message:after {
content: " ";
display: table;
}
ul.messenger.messenger-theme-flat .messenger-message:after {
clear: both;
}
ul.messenger.messenger-theme-flat .messenger-message.messenger-hidden {
display: none;
}
ul.messenger.messenger-theme-flat .messenger-message .messenger-actions {
float: right;
}
ul.messenger.messenger-theme-flat .messenger-message .messenger-actions a {
cursor: pointer;
text-decoration: underline;
}
ul.messenger.messenger-theme-flat .messenger-message ul,
ul.messenger.messenger-theme-flat .messenger-message ol {
margin: 10px 18px 0;
}
ul.messenger.messenger-theme-flat.messenger-fixed {
position: fixed;
z-index: 10000;
}
ul.messenger.messenger-theme-flat.messenger-fixed .messenger-message {
min-width: 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
ul.messenger.messenger-theme-flat.messenger-fixed .message .messenger-actions {
float: left;
}
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-top {
top: 20px;
}
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-bottom {
bottom: 20px;
}
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-top,
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-bottom {
left: 50%;
width: 800px;
margin-left: -400px;
}
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-top.messenger-on-right,
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-bottom.messenger-on-right {
right: 20px;
left: auto;
}
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-top.messenger-on-left,
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-bottom.messenger-on-left {
left: 20px;
margin-left: 0px;
}
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-right,
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-left {
width: 90%;
}
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-right .messenger-actions,
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-left .messenger-actions {
float: left;
}
@media (min-width: 768px) {
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-right {
width: 45%;
}
}
@media (min-width: 1200px) {
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-on-right {
width: 35%;
}
}
ul.messenger.messenger-theme-flat.messenger-fixed.messenger-empty.messenger-fixed.messenger-on-bottom.messenger-on-right {
display: block;
opacity: 0;
bottom: 20%;
}
ul.messenger.messenger-theme-flat .messenger-spinner {
display: none;
}
ul.messenger.messenger-theme-flat .messenger-clickable {
cursor: pointer;
}
ul.messenger-theme-flat {
background-color: transparent;
}
ul.messenger-theme-flat.messenger-empty {
display: none;
}
ul.messenger-theme-flat .messenger-message {
box-shadow: 0 0 6px rgba(0, 0, 0, 0.175), inset 0px 1px rgba(255, 255, 255, 0.13), inset 50px 0px 0px #0c0c0c !important;
border-radius: 0 !important;
position: relative;
border: 0px;
margin-bottom: 0px;
font-size: 12px;
background: #252525;
color: #f0f0f0;
font-weight: 500;
padding: 10px 30px 10px 65px;
line-height: 27px;
}
ul.messenger-theme-flat .messenger-message:before,
ul.messenger-theme-flat .messenger-message .messenger-message-inner:before {
font-size: 20px;
position: absolute;
left: 15px;
top: 50%;
margin-top: -10px;
font-family: 'PatternFlyIcons-webfont';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
ul.messenger-theme-flat .messenger-message .messenger-close {
line-height: 30px;
}
ul.messenger-theme-flat .messenger-message .messenger-actions a {
text-decoration: none;
color: #aaaaaa;
background: #323232;
}
ul.messenger-theme-flat .messenger-message.alert-error:before {
content: "\e61d";
color: #cc0000;
display: inline-block;
}
ul.messenger-theme-flat .messenger-message.alert-error .messenger-message-inner:before {
background-color: transparent;
}
ul.messenger-theme-flat .messenger-message.alert-warning:before {
content: "\e61c";
color: #ec7a08;
display: inline-block;
left: 14px;
margin-top: -11px;
}
ul.messenger-theme-flat .messenger-message.alert-success .messenger-message-inner:before {
color: #3f9c35;
content: "\e602";
display: inline-block;
background-color: transparent;
}
ul.messenger-theme-flat .messenger-message.alert-info .messenger-message-inner:before {
color: #00659c;
content: "\e604";
display: inline-block;
background-color: transparent;
}
.word-break {
word-wrap: break-word;
word-break: break-word;
......
......@@ -2307,7 +2307,7 @@ angular.module('openshiftCommonServices')
/* jshint eqeqeq: false, unused: false, expr: true */
angular.module('openshiftCommonServices')
.factory('DataService', ["$cacheFactory", "$http", "$ws", "$rootScope", "$q", "API_CFG", "APIService", "Notification", "Logger", "$timeout", "base64", "base64util", function($cacheFactory, $http, $ws, $rootScope, $q, API_CFG, APIService, Notification, Logger, $timeout, base64, base64util) {
.factory('DataService', ["$cacheFactory", "$http", "$ws", "$rootScope", "$q", "API_CFG", "APIService", "Logger", "$timeout", "base64", "base64util", function($cacheFactory, $http, $ws, $rootScope, $q, API_CFG, APIService, Logger, $timeout, base64, base64util) {
function Data(array) {
this._data = {};
......@@ -2715,7 +2715,12 @@ angular.module('openshiftCommonServices')
if (status !== 0) {
msg += " (" + status + ")";
}
Notification.error(msg);
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
type: 'error',
message: msg
});
}
deferred.reject({
data: data,
......@@ -3255,7 +3260,12 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
if (status !== 0) {
msg += " (" + status + ")";
}
Notification.error(msg);
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
type: 'error',
message: msg
});
});
});
}
......@@ -3281,7 +3291,12 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
if (status !== 0) {
msg += " (" + status + ")";
}
Notification.error(msg);
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
type: 'error',
message: msg
});
});
}
};
......@@ -3466,12 +3481,18 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
if (this._isTooManyWebsocketRetries(key)) {
// Show an error notication unless disabled in opts.
if (_.get(opts, 'errorNotification', true)) {
Notification.error("Server connection interrupted.", {
id: "websocket_retry_halted",
mustDismiss: true,
actions: {
refresh: {label: "Refresh", action: function() { window.location.reload(); }}
}
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
id: 'websocket_retry_halted',
type: 'error',
message: 'Server connection interrupted.',
links: [{
label: 'Refresh',
onClick: function() {
window.location.reload();
}
}]
});
}
return;
......@@ -3944,68 +3965,6 @@ angular.module('openshiftCommonServices')
}];
});
;'use strict';
/* jshint unused: false */
angular.module('openshiftCommonServices')
.factory('Notification', ["$rootScope", function($rootScope) {
function Notification() {
this.messenger = Messenger({
extraClasses: 'messenger-fixed messenger-on-bottom messenger-on-right',
theme: 'flat',
messageDefaults: {
showCloseButton: true,
hideAfter: 10
}
});
var self = this;
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
self.clear();
});
}
// Opts:
// id - if an id is passed only one message with this id will ever be shown
// mustDismiss - the user must explicitly dismiss the message, it will not auto-hide
Notification.prototype.notify = function(type, message, opts) {
opts = opts || {};
var notifyOpts = {
type: type,
// TODO report this issue upstream to messenger, they don't handle messages with invalid html
// they should be escaping it
message: $('<div/>').text(message).html(),
id: opts.id,
actions: opts.actions
};
if (opts.mustDismiss) {
notifyOpts.hideAfter = false;
}
this.messenger.post(notifyOpts);
};
Notification.prototype.success = function(message, opts) {
this.notify("success", message, opts);
};
Notification.prototype.info = function(message, opts) {
this.notify("info", message, opts);
};
Notification.prototype.error = function(message, opts) {
this.notify("error", message, opts);
};
Notification.prototype.warning = function(message, opts) {
this.notify("warning", message, opts);
};
Notification.prototype.clear = function() {
this.messenger.hideAll();
};
return new Notification();
}]);
;'use strict';
angular.module('openshiftCommonServices')
.factory('ProjectsService',
......@@ -4537,7 +4496,7 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
this.dismissDelay = 8000;
this.autoDismissTypes = ['info', 'success'];
this.$get = function() {
this.$get = ["$rootScope", function($rootScope) {
var notifications = [];
var dismissDelay = this.dismissDelay;
var autoDismissTypes = this.autoDismissTypes;
......@@ -4550,9 +4509,9 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
return 'hide/notification/' + namespace + '/' + notificationID;
};
var addNotification = function (notification, notificationID, namespace) {
if (notificationID && isNotificationPermanentlyHidden(notificationID, namespace)) {
notification.hidden = true;
var addNotification = function (notification) {
if (isNotificationPermanentlyHidden(notification) || isNotificationVisible(notification)) {
return;
}
notifications.push(notification);
......@@ -4566,8 +4525,12 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
_.take(notifications, 0);
};
var isNotificationPermanentlyHidden = function (notificationID, namespace) {
var key = notificationHiddenKey(notificationID, namespace);
var isNotificationPermanentlyHidden = function (notification) {
if (!notification.id) {
return false;
}
var key = notificationHiddenKey(notification.id, notification.namespace);
return localStorage.getItem(key) === 'true';
};
......@@ -4576,12 +4539,28 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
localStorage.setItem(key, 'true');
};
// Is there a visible toast notification with the same ID right now?
var isNotificationVisible = function (notification) {
if (!notification.id) {
return false;
}
return _.some(notifications, function(next) {
return !next.hidden && notification.id === next.id;
});
};
var isAutoDismiss = function(notification) {
return _.find(autoDismissTypes, function(type) {
return type === notification.type;
});
};
// Also handle `addNotification` events on $rootScope, which is used by DataService.
$rootScope.$on('addNotification', function(event, data) {
addNotification(data);
});
return {
addNotification: addNotification,
getNotifications: getNotifications,
......@@ -4592,7 +4571,7 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
dismissDelay: dismissDelay,
autoDismissTypes: autoDismissTypes
};
};
}];
this.setDismissDelay = function(delayInMs) {
this.dismissDelay = delayInMs;
......
......@@ -960,7 +960,7 @@ return data;
}), angular.module("openshiftCommonServices").factory("Constants", function() {
var constants = _.clone(window.OPENSHIFT_CONSTANTS || {}), version = _.clone(window.OPENSHIFT_VERSION || {});
return constants.VERSION = version, constants;
}), angular.module("openshiftCommonServices").factory("DataService", [ "$cacheFactory", "$http", "$ws", "$rootScope", "$q", "API_CFG", "APIService", "Notification", "Logger", "$timeout", "base64", "base64util", function($cacheFactory, $http, $ws, $rootScope, $q, API_CFG, APIService, Notification, Logger, $timeout, base64, base64util) {
}), angular.module("openshiftCommonServices").factory("DataService", [ "$cacheFactory", "$http", "$ws", "$rootScope", "$q", "API_CFG", "APIService", "Logger", "$timeout", "base64", "base64util", function($cacheFactory, $http, $ws, $rootScope, $q, API_CFG, APIService, Logger, $timeout, base64, base64util) {
function Data(array) {
this._data = {}, this._objectsByAttribute(array, "metadata.name", this._data);
}
......@@ -1142,7 +1142,10 @@ self._isImmutable(resource) && (existingImmutableData ? existingImmutableData.up
}).error(function(data, status, headers, config) {
if (opts.errorNotification !== !1) {
var msg = "Failed to get " + resource + "/" + name;
0 !== status && (msg += " (" + status + ")"), Notification.error(msg);
0 !== status && (msg += " (" + status + ")"), $rootScope.$emit("addNotification", {
type:"error",
message:msg
});
}
deferred.reject({
data:data,
......@@ -1351,7 +1354,10 @@ self._listInFlight(key, !1);
var deferred = self._listDeferred(key);
if (delete self._listDeferredMap[key], deferred.reject(data, status, headers, config), _.get(opts, "errorNotification", !0)) {
var msg = "Failed to list " + resource;
0 !== status && (msg += " (" + status + ")"), Notification.error(msg);
0 !== status && (msg += " (" + status + ")"), $rootScope.$emit("addNotification", {
type:"error",
message:msg
});
}
});
}) :$http({
......@@ -1365,7 +1371,10 @@ self._listInFlight(key, !1);
var deferred = self._listDeferred(key);
if (delete self._listDeferredMap[key], deferred.reject(data, status, headers, config), _.get(opts, "errorNotification", !0)) {
var msg = "Failed to list " + resource;
0 !== status && (msg += " (" + status + ")"), Notification.error(msg);
0 !== status && (msg += " (" + status + ")"), $rootScope.$emit("addNotification", {
type:"error",
message:msg
});
}
});
}, DataService.prototype._listOpComplete = function(key, resource, context, opts, data) {
......@@ -1430,17 +1439,16 @@ if (eventWS !== registeredWS) return void Logger.log("Skipping reopen, eventWS d
if (this._watchInFlight(key, !1), eventWS.shouldClose) return void Logger.log("Skipping reopen, eventWS was explicitly closed", eventWS);
if (event.wasClean) return void Logger.log("Skipping reopen, clean close", event);
if (!this._watchCallbacks(key).has()) return void Logger.log("Skipping reopen, no listeners registered for resource/context", resource, context);
if (this._isTooManyWebsocketRetries(key)) return void (_.get(opts, "errorNotification", !0) && Notification.error("Server connection interrupted.", {
if (this._isTooManyWebsocketRetries(key)) return void (_.get(opts, "errorNotification", !0) && $rootScope.$emit("addNotification", {
id:"websocket_retry_halted",
mustDismiss:!0,
actions:{
refresh:{
type:"error",
message:"Server connection interrupted.",
links:[ {
label:"Refresh",
action:function() {
onClick:function() {
window.location.reload();
}
}
}
} ]
}));
if (this._addWebsocketEvent(key, "close"), eventWS.shouldRelist) {
Logger.log("Relisting for resource/context", resource, context);
......@@ -1689,42 +1697,7 @@ token ? (authLogger.log("LocalStorageUserStore.setToken", token, ttl), localStor
}
};
} ];
}), angular.module("openshiftCommonServices").factory("Notification", [ "$rootScope", function($rootScope) {
function Notification() {
this.messenger = Messenger({
extraClasses:"messenger-fixed messenger-on-bottom messenger-on-right",
theme:"flat",
messageDefaults:{
showCloseButton:!0,
hideAfter:10
}
});
var self = this;
$rootScope.$on("$routeChangeStart", function(event, next, current) {
self.clear();
});
}
return Notification.prototype.notify = function(type, message, opts) {
opts = opts || {};
var notifyOpts = {
type:type,
message:$("<div/>").text(message).html(),
id:opts.id,
actions:opts.actions
};
opts.mustDismiss && (notifyOpts.hideAfter = !1), this.messenger.post(notifyOpts);
}, Notification.prototype.success = function(message, opts) {
this.notify("success", message, opts);
}, Notification.prototype.info = function(message, opts) {
this.notify("info", message, opts);
}, Notification.prototype.error = function(message, opts) {
this.notify("error", message, opts);
}, Notification.prototype.warning = function(message, opts) {
this.notify("warning", message, opts);
}, Notification.prototype.clear = function() {
this.messenger.hideAll();
}, new Notification();
} ]), angular.module("openshiftCommonServices").factory("ProjectsService", [ "$location", "$q", "AuthService", "DataService", "annotationNameFilter", "AuthorizationService", function($location, $q, AuthService, DataService, annotationNameFilter, AuthorizationService) {
}), angular.module("openshiftCommonServices").factory("ProjectsService", [ "$location", "$q", "AuthService", "DataService", "annotationNameFilter", "AuthorizationService", function($location, $q, AuthService, DataService, annotationNameFilter, AuthorizationService) {
var cleanEditableAnnotations = function(resource) {
var paths = [ annotationNameFilter("description"), annotationNameFilter("displayName") ];
return _.each(paths, function(path) {
......@@ -1979,27 +1952,34 @@ startTour:startTour,
cancelTour:cancelTour
};
}), angular.module("openshiftCommonUI").provider("NotificationsService", function() {
this.dismissDelay = 8e3, this.autoDismissTypes = [ "info", "success" ], this.$get = function() {
this.dismissDelay = 8e3, this.autoDismissTypes = [ "info", "success" ], this.$get = [ "$rootScope", function($rootScope) {
var notifications = [], dismissDelay = this.dismissDelay, autoDismissTypes = this.autoDismissTypes, notificationHiddenKey = function(notificationID, namespace) {
return namespace ? "hide/notification/" + namespace + "/" + notificationID :"hide/notification/" + notificationID;
}, addNotification = function(notification, notificationID, namespace) {
notificationID && isNotificationPermanentlyHidden(notificationID, namespace) && (notification.hidden = !0), notifications.push(notification);
}, addNotification = function(notification) {
isNotificationPermanentlyHidden(notification) || isNotificationVisible(notification) || notifications.push(notification);
}, getNotifications = function() {
return notifications;
}, clearNotifications = function() {
_.take(notifications, 0);
}, isNotificationPermanentlyHidden = function(notificationID, namespace) {
var key = notificationHiddenKey(notificationID, namespace);
}, isNotificationPermanentlyHidden = function(notification) {
if (!notification.id) return !1;
var key = notificationHiddenKey(notification.id, notification.namespace);
return "true" === localStorage.getItem(key);
}, permanentlyHideNotification = function(notificationID, namespace) {
var key = notificationHiddenKey(notificationID, namespace);
localStorage.setItem(key, "true");
}, isNotificationVisible = function(notification) {
return notification.id ? _.some(notifications, function(next) {
return !next.hidden && notification.id === next.id;
}) :!1;
}, isAutoDismiss = function(notification) {
return _.find(autoDismissTypes, function(type) {
return type === notification.type;
});
};
return {
return $rootScope.$on("addNotification", function(event, data) {
addNotification(data);
}), {
addNotification:addNotification,
getNotifications:getNotifications,
clearNotifications:clearNotifications,
......@@ -2009,7 +1989,7 @@ isAutoDismiss:isAutoDismiss,
dismissDelay:dismissDelay,
autoDismissTypes:autoDismissTypes
};
}, this.setDismissDelay = function(delayInMs) {
} ], this.setDismissDelay = function(delayInMs) {
this.dismissDelay = delayInMs;
}, this.setAutoDismissTypes = function(arrayOfTypes) {
this.autoDismissTypes = arrayOfTypes;
......
......@@ -2,7 +2,7 @@
/* jshint eqeqeq: false, unused: false, expr: true */
angular.module('openshiftCommonServices')
.factory('DataService', function($cacheFactory, $http, $ws, $rootScope, $q, API_CFG, APIService, Notification, Logger, $timeout, base64, base64util) {
.factory('DataService', function($cacheFactory, $http, $ws, $rootScope, $q, API_CFG, APIService, Logger, $timeout, base64, base64util) {
function Data(array) {
this._data = {};
......@@ -410,7 +410,12 @@ angular.module('openshiftCommonServices')
if (status !== 0) {
msg += " (" + status + ")";
}
Notification.error(msg);
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
type: 'error',
message: msg
});
}
deferred.reject({
data: data,
......@@ -950,7 +955,12 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
if (status !== 0) {
msg += " (" + status + ")";
}
Notification.error(msg);
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
type: 'error',
message: msg
});
});
});
}
......@@ -976,7 +986,12 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
if (status !== 0) {
msg += " (" + status + ")";
}
Notification.error(msg);
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
type: 'error',
message: msg
});
});
}
};
......@@ -1161,12 +1176,18 @@ DataService.prototype.createStream = function(resource, name, context, opts, isR
if (this._isTooManyWebsocketRetries(key)) {
// Show an error notication unless disabled in opts.
if (_.get(opts, 'errorNotification', true)) {
Notification.error("Server connection interrupted.", {
id: "websocket_retry_halted",
mustDismiss: true,
actions: {
refresh: {label: "Refresh", action: function() { window.location.reload(); }}
}
// Use `$rootScope.$emit` instead of NotificationsService directly
// so that DataService doesn't add a dependency on `openshiftCommonUI`
$rootScope.$emit('addNotification', {
id: 'websocket_retry_halted',
type: 'error',
message: 'Server connection interrupted.',
links: [{
label: 'Refresh',
onClick: function() {
window.location.reload();
}
}]
});
}
return;
......
'use strict';
/* jshint unused: false */
angular.module('openshiftCommonServices')
.factory('Notification', function($rootScope) {
function Notification() {
this.messenger = Messenger({
extraClasses: 'messenger-fixed messenger-on-bottom messenger-on-right',
theme: 'flat',
messageDefaults: {
showCloseButton: true,
hideAfter: 10
}
});
var self = this;
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
self.clear();
});
}
// Opts:
// id - if an id is passed only one message with this id will ever be shown
// mustDismiss - the user must explicitly dismiss the message, it will not auto-hide
Notification.prototype.notify = function(type, message, opts) {
opts = opts || {};
var notifyOpts = {
type: type,
// TODO report this issue upstream to messenger, they don't handle messages with invalid html
// they should be escaping it
message: $('<div/>').text(message).html(),
id: opts.id,
actions: opts.actions
};
if (opts.mustDismiss) {
notifyOpts.hideAfter = false;
}
this.messenger.post(notifyOpts);
};
Notification.prototype.success = function(message, opts) {
this.notify("success", message, opts);
};
Notification.prototype.info = function(message, opts) {
this.notify("info", message, opts);
};
Notification.prototype.error = function(message, opts) {
this.notify("error", message, opts);
};
Notification.prototype.warning = function(message, opts) {
this.notify("warning", message, opts);
};
Notification.prototype.clear = function() {
this.messenger.hideAll();
};
return new Notification();
});
//
// Default messenger included here instead of including messenger.css
// -------------------------------------------------
ul.messenger.messenger-theme-flat {
margin: 0;
padding: 0;
opacity: 1;
.transition(all .2s ease .2s);
> li {
list-style: none;
margin: 0;
padding: 0;
&.messenger-shown {
}
}
.messenger-message {
.clearfix();
&.messenger-hidden {
display: none;
}
.messenger-phrase, .messenger-actions a {
// padding-right: 5px;
}
.messenger-actions {
float: right;
a {
cursor: pointer;
text-decoration: underline;
}
}
ul, ol {
margin: 10px 18px 0;
}
}
&.messenger-fixed {
position: fixed;
z-index: 10000;
.messenger-message {
min-width: 0;
.box-sizing(border-box);
}
.message .messenger-actions {
float: left;
}
&.messenger-on-top {
top: 20px;
}
&.messenger-on-bottom {
bottom: 20px;
}
&.messenger-on-top, &.messenger-on-bottom {
left: 50%;
width: 800px;
margin-left: -400px;
&.messenger-on-right {
right: 20px;
left: auto;
}
&.messenger-on-left {
left: 20px;
margin-left: 0px;
}
}
&.messenger-on-right, &.messenger-on-left {
width: 90%;
.messenger-actions {
float: left;
}
}
@media (min-width: @screen-sm-min) {
&.messenger-on-right {
width: 45%;
}
}
@media (min-width: @screen-lg-min) {
&.messenger-on-right {
width: 35%;
}
}
&.messenger-empty.messenger-fixed.messenger-on-bottom.messenger-on-right {
display: block;
opacity: 0;
bottom: 20%;
}
}
.messenger-spinner {
display: none;
}
.messenger-clickable {
cursor: pointer;
}
}
//
// Messenger Flat Theme modifications
// -------------------------------------------------
ul.messenger-theme-flat {
background-color: transparent;
&.messenger-empty {
display: none;
}
}
@insetBackgroundColor: darken(@gray-darker, 10%);
ul.messenger-theme-flat .messenger-message {
box-shadow: 0 0 6px rgba(0,0,0,.175), inset 0px 1px rgba(255, 255, 255, 0.13), inset 50px 0px 0px @insetBackgroundColor !important;
border-radius: 0 !important;
position: relative;
border: 0px;
margin-bottom: 0px;
font-size: @font-size-base;
background: @gray-darker;
color: #f0f0f0;
font-weight: 500;
padding: 10px 30px 10px 65px;
line-height: 27px;
&:before,
.messenger-message-inner:before {
font-size: 20px;
position: absolute;
left: 15px;
top: 50%;
margin-top: -10px;
font-family: 'PatternFlyIcons-webfont';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.messenger-close {
line-height: 30px;
}
}
ul.messenger-theme-flat .messenger-message .messenger-actions a {
text-decoration: none;
color: #aaaaaa;
background: lighten(@gray-darker, 5%);
}
ul.messenger-theme-flat {
.messenger-message.alert-error {
&:before {
content: @pficon-var-error-circle-o;
color: @brand-danger;
display: inline-block;
}
.messenger-message-inner:before {
background-color: transparent;
}
}
.messenger-message.alert-warning {
&:before {
content: @pficon-var-warning-triangle-o;
color: @brand-warning;
display: inline-block;
left: 14px;
margin-top: -11px;
}
}
.messenger-message.alert-success .messenger-message-inner:before {
color: @brand-success;
content: @pficon-var-ok;
display: inline-block;
background-color: transparent;
}
.messenger-message.alert-info .messenger-message-inner:before {
color: @brand-info;
content: @pficon-var-info;
display: inline-block;
background-color: transparent;
}
}
......@@ -3,7 +3,6 @@
@import "_core.less";
@import "_forms.less";
@import "_guided-tour.less";
@import "_messages.less";
@import "_mixins.less";
@import "_notifications.less";
@import "_ui-select.less";
......
......@@ -4,7 +4,7 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
this.dismissDelay = 8000;
this.autoDismissTypes = ['info', 'success'];
this.$get = function() {
this.$get = function($rootScope) {
var notifications = [];
var dismissDelay = this.dismissDelay;
var autoDismissTypes = this.autoDismissTypes;
......@@ -17,9 +17,9 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
return 'hide/notification/' + namespace + '/' + notificationID;
};
var addNotification = function (notification, notificationID, namespace) {
if (notificationID && isNotificationPermanentlyHidden(notificationID, namespace)) {
notification.hidden = true;
var addNotification = function (notification) {
if (isNotificationPermanentlyHidden(notification) || isNotificationVisible(notification)) {
return;
}
notifications.push(notification);
......@@ -33,8 +33,12 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
_.take(notifications, 0);
};
var isNotificationPermanentlyHidden = function (notificationID, namespace) {
var key = notificationHiddenKey(notificationID, namespace);
var isNotificationPermanentlyHidden = function (notification) {
if (!notification.id) {
return false;
}
var key = notificationHiddenKey(notification.id, notification.namespace);
return localStorage.getItem(key) === 'true';
};
......@@ -43,12 +47,28 @@ angular.module('openshiftCommonUI').provider('NotificationsService', function()
localStorage.setItem(key, 'true');
};
// Is there a visible toast notification with the same ID right now?
var isNotificationVisible = function (notification) {
if (!notification.id) {
return false;
}
return _.some(notifications, function(next) {
return !next.hidden && notification.id === next.id;
});
};
var isAutoDismiss = function(notification) {
return _.find(autoDismissTypes, function(type) {
return type === notification.type;
});
};
// Also handle `addNotification` events on $rootScope, which is used by DataService.
$rootScope.$on('addNotification', function(event, data) {
addNotification(data);
});
return {
addNotification: addNotification,
getNotifications: getNotifications,
......
......@@ -22,7 +22,6 @@ module.exports = function(config) {
'bower_components/angular-mocks/angular-mocks.js',
"bower_components/angular-sanitize/angular-sanitize.js",
"bower_components/js-logger/src/logger.js",
"bower_components/messenger/build/js/messenger.js",
"bower_components/angular-utf8-base64/angular-utf8-base64.js",
"bower_components/uri.js/src/URI.js",
"bower_components/uri.js/src/URITemplate.js",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment