diff --git a/static/js/pages/user-view.js b/static/js/pages/user-view.js index 4bd387e2d..33b31e74b 100644 --- a/static/js/pages/user-view.js +++ b/static/js/pages/user-view.js @@ -10,7 +10,7 @@ }) }]); - function UserViewCtrl($scope, $routeParams, $timeout, ApiService, UserService, UIService, AvatarService, Config, ExternalLoginService) { + function UserViewCtrl($scope, $routeParams, $timeout, ApiService, UserService, UIService, AvatarService, Config, ExternalLoginService, CookieService) { var username = $routeParams.username; $scope.Config = Config; @@ -184,5 +184,53 @@ $scope.showBilling = function() { $scope.showBillingCounter++; }; + + + $scope.notificationsPermissionsEnabled = window['Notification'] + && Notification.permission === 'granted' + && CookieService.get('quay.enabledDesktopNotifications') === 'on'; + + $scope.desktopNotificationsPermissionIsDisabled = () => window['Notification'] && Notification.permission === 'denied'; + + $scope.toggleDesktopNotifications = () => { + if (!window['Notification']) { // unsupported in IE & some older browsers, we'll just tell the user it's not available + bootbox.dialog({ + "message": 'Desktop Notifications unsupported in this browser', + "title": 'Unsupported Option', + "buttons": { + "close": { + "label": "Close", + "className": "btn-primary" + } + } + }); + + return; + } + + if (CookieService.get('quay.enabledDesktopNotifications') === 'on') { + CookieService.putPermanent('quay.enabledDesktopNotifications', 'off'); + CookieService.clear('quay.notifications.mostRecentTimestamp'); + $scope.notificationsPermissionsEnabled = false; + } else { + if (Notification.permission === 'default') { + Notification.requestPermission() + .then((newPermission) => { + if (newPermission === 'granted') { + CookieService.putPermanent('quay.enabledDesktopNotifications', 'on'); + CookieService.putPermanent('quay.notifications.mostRecentTimestamp', new Date().getTime().toString()); + $scope.notificationsPermissionsEnabled = true; + } else { + $scope.notificationsPermissionsEnabled = false; + } + }); + } else if (Notification.permission === 'granted') { + CookieService.putPermanent('quay.enabledDesktopNotifications', 'on'); + CookieService.putPermanent('quay.notifications.mostRecentTimestamp', new Date().getTime().toString()); + $scope.notificationsPermissionsEnabled = true; + } + } + }; + } })(); \ No newline at end of file diff --git a/static/js/services/features-config.js b/static/js/services/features-config.js index c3cb99817..734b06963 100644 --- a/static/js/services/features-config.js +++ b/static/js/services/features-config.js @@ -71,8 +71,12 @@ angular.module('quay').factory('Config', ['Features', function(Features) { return value; }; - config.getEnterpriseLogo = function() { + config.getEnterpriseLogo = function(opt_defaultValue) { if (!config.ENTERPRISE_LOGO_URL) { + if (opt_defaultValue) { + return opt_defaultValue; + } + if (Features.BILLING) { return '/static/img/quay-horizontal-color.svg'; } else { diff --git a/static/js/services/notification-service.js b/static/js/services/notification-service.js index ff337542e..73d70d227 100644 --- a/static/js/services/notification-service.js +++ b/static/js/services/notification-service.js @@ -3,9 +3,9 @@ * in the sidebar) and provides helper methods for working with them. */ angular.module('quay').factory('NotificationService', - ['$rootScope', '$interval', 'UserService', 'ApiService', 'StringBuilderService', 'PlanService', 'UserService', 'Features', 'Config', '$location', 'VulnerabilityService', + ['$rootScope', '$interval', 'UserService', 'ApiService', 'StringBuilderService', 'PlanService', 'CookieService', 'Features', 'Config', '$location', 'VulnerabilityService', -function($rootScope, $interval, UserService, ApiService, StringBuilderService, PlanService, UserService, Features, Config, $location, VulnerabilityService) { +function($rootScope, $interval, UserService, ApiService, StringBuilderService, PlanService, CookieService, Features, Config, $location, VulnerabilityService) { var notificationService = { 'user': null, 'notifications': [], @@ -266,6 +266,10 @@ function($rootScope, $interval, UserService, ApiService, StringBuilderService, P notificationService.notifications = resp['notifications']; notificationService.additionalNotifications = resp['additional']; notificationService.notificationClasses = notificationService.getClasses(notificationService.notifications); + + if (notificationService.notifications.length > 0 && CookieService.get('quay.enabledDesktopNotifications') === 'on') { + notificationService.sendBrowserNotifications(); + } }); if (Features.APP_SPECIFIC_TOKENS) { @@ -277,6 +281,33 @@ function($rootScope, $interval, UserService, ApiService, StringBuilderService, P }); } }; + + notificationService.sendBrowserNotifications = () => { + let mostRecentTimestamp = parseInt(CookieService.get('quay.notifications.mostRecentTimestamp'), 10); + if (!mostRecentTimestamp) { + mostRecentTimestamp = new Date(notificationService.notifications[0].created).getTime(); + } + + const newNotifications = notificationService.notifications + .filter(obj => new Date(obj.created).getTime() > mostRecentTimestamp); + + if (newNotifications.length > 0) { + let message = 'You have unread notifications'; + if (newNotifications.length === 1) { + message = notificationService.getMessage(newNotifications[0]); + } + + new Notification(message, { + // Chrome doesn't display SVGs for notifications, so we'll use a default if we don't have an enterprise logo + icon: window.location.origin + Config.getEnterpriseLogo('/static/img/quay-logo.png'), + image: window.location.origin + Config.getEnterpriseLogo('/static/img/quay-logo.png'), + }); + + const newTimestamp = new Date(newNotifications[0].created).getTime(); + CookieService.putPermanent('quay.notifications.mostRecentTimestamp', newTimestamp.toString()); + } + }; + notificationService.reset = function() { $interval.cancel(pollTimerHandle); pollTimerHandle = $interval(notificationService.update, 5 * 60 * 1000 /* five minutes */); diff --git a/static/partials/user-view.html b/static/partials/user-view.html index 93c341d2e..1ced21c45 100644 --- a/static/partials/user-view.html +++ b/static/partials/user-view.html @@ -170,6 +170,23 @@ Individual account +