Skip to content

Commit 03fac47

Browse files
Add notification-drawer to show curated list of events to user
- Show events that pass the white list in OPENSHIFT_CONSTANTS.EVENTS_TO_SHOW - Internal Notifications coming in next iteration - Add patternfly.notifications - add notification counter to top bar - add notification event service - add drawer-wrapper as a proxy to pf-notification-drawer - need our own controller for filtering, etc - Update event system to use $rootScope.$emit rather than a custom service - add sessionStorage cache to keep track of read/unread state - Debounce watch in notification service based on work recently done in DataService to support - Update web-common to 0.0.43, includes DataService.watch() flag - Add FEATURE_FLAG.global_event_watch_for_notification_drawer - kill switch in case watching events is too expensive - would still allow internal notifications to appear in drawer - Add link to events page, update index.html - Migrate EVENTS_TO_SHOW map out of EventsService into Constants - Add naviateEventInvolvedObjectURL filter for drawer & events - Update Events service to track read, cleared, namespace SessionStorage, etc - Animate w/a fade-out when a notification is cleared to ensure user notices the subtle change - Add BrowserStorage service - auto namespace openshift- on all Local & Session storage keys - Add links to objects in event-sidebar - Disabled in IE & Edge due to insufficient watches
1 parent cf0278b commit 03fac47

24 files changed

+1187
-42
lines changed

Diff for: app/index.html

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
<!-- Add your site or application content here -->
4343

4444
<toast-notifications></toast-notifications>
45+
<notification-drawer-wrapper></notification-drawer-wrapper>
46+
4547
<div ng-view>
4648
<!-- Include default simple nav and shaded background as a placeholder until API discovery finishes -->
4749
<nav class="navbar navbar-pf-alt top-header" role="navigation">
@@ -190,6 +192,7 @@ <h1>JavaScript Required</h1>
190192

191193
<script src="scripts/constants.js"></script>
192194
<script src="scripts/app.js"></script>
195+
<script src="scripts/services/browserStore.js"></script>
193196
<script src="scripts/services/discovery.js"></script>
194197
<script src="scripts/services/applicationGenerator.js"></script>
195198
<script src="scripts/services/navigate.js"></script>
@@ -233,6 +236,7 @@ <h1>JavaScript Required</h1>
233236
<script src="scripts/services/listRowUtils.js"></script>
234237
<script src="scripts/services/ownerReferences.js"></script>
235238
<script src="scripts/controllers/landingPage.js"></script>
239+
<script src="scripts/services/events.js"></script>
236240
<script src="scripts/controllers/projects.js"></script>
237241
<script src="scripts/controllers/pods.js"></script>
238242
<script src="scripts/controllers/pod.js"></script>
@@ -391,6 +395,8 @@ <h1>JavaScript Required</h1>
391395
<script src="scripts/directives/affix.js"></script>
392396
<script src="scripts/directives/editEnvironmentVariables.js"></script>
393397
<script src="scripts/directives/initContainersSummary.js"></script>
398+
<script src="scripts/directives/notifications/notificationCounter.js"></script>
399+
<script src="scripts/directives/notifications/notificationDrawerWrapper.js"></script>
394400
<script src="scripts/filters/date.js"></script>
395401
<script src="scripts/filters/resources.js"></script>
396402
<script src="scripts/filters/canI.js"></script>

Diff for: app/scripts/app.js

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ angular
2222
'patternfly.charts',
2323
'patternfly.navigation',
2424
'patternfly.sort',
25+
'patternfly.notification',
2526
'openshiftConsoleTemplates',
2627
'ui.ace',
2728
'extension-registry',

Diff for: app/scripts/constants.js

+55-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ angular.extend(window.OPENSHIFT_CONSTANTS, {
8484

8585
// This blacklist hides certain kinds from the "Other Resources" page because they are unpersisted, disallowed for most end users, or not supported by openshift but exist in kubernetes
8686
AVAILABLE_KINDS_BLACKLIST: [],
87-
87+
// Currently disables watch on events used by the drawer
88+
DISABLE_GLOBAL_EVENT_WATCH: false,
8889
ENABLE_TECH_PREVIEW_FEATURE: {
8990
// Enable the new landing page and service catalog experience
9091
service_catalog_landing_page: false,
@@ -139,6 +140,59 @@ angular.extend(window.OPENSHIFT_CONSTANTS, {
139140
{resource: 'services', group: ''},
140141
{resource: 'statefulsets', group: 'apps'}
141142
],
143+
// TODO:
144+
// This map can drive both the drawer & toast messages by
145+
// updating it to the following format:
146+
// { drawer: true, toast: true }
147+
// or perhaps this, where an event may apply to multiple resources
148+
// (though reuse of events is not super common, this could be overkill):
149+
// Failed: {
150+
// resources: [{ group: 'apps', resource: 'deployments' }],
151+
// drawer: true,
152+
// toast: true
153+
// }
154+
// TODO: Also consider an API_OBJECTS_TO_IGNORE
155+
// map that can blacklist some, for example, if FailedCreate
156+
// applies to many but we don't want to see all.
157+
EVENTS_TO_SHOW: {
158+
// CRUD events that apply to more than one api object
159+
FailedCreate: true,
160+
FailedDelete: true,
161+
FailedUpdate: true,
162+
// Build
163+
BuildStarted: true,
164+
BuildCompleted: true,
165+
BuildFailed: true,
166+
BuildCancelled: true,
167+
// BuildConfig
168+
//
169+
// Deployment
170+
Failed: true,
171+
ScalingReplicaSet: true,
172+
DeploymentCancelled: true,
173+
// DeploymentConfig
174+
DeploymentCreated: true,
175+
DeploymentCreationFailed: true,
176+
// Pod
177+
FailedSync: true,
178+
BackOff: true,
179+
Unhealthy: true,
180+
// Image/Pod
181+
Pulling: true,
182+
Pulled: true,
183+
// SuccessfulDelete: true,
184+
// Cron
185+
//
186+
// PodAutoscaler
187+
SuccessfulRescale: true,
188+
FailedRescale: true,
189+
// Service
190+
LoadBalancerUpdateFailed: true,
191+
// PVC
192+
VolumeDeleted: true,
193+
FailedBinding: true,
194+
ProvisioningFailed: true
195+
},
142196

143197
// href's will be prefixed with /project/{{projectName}} unless they are absolute URLs
144198
PROJECT_NAVIGATION: [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
'use strict';
2+
(function() {
3+
4+
angular
5+
.module('openshiftConsole')
6+
.component('notificationCounter', {
7+
templateUrl: 'views/directives/notifications/notification-counter.html',
8+
bindings: {},
9+
controller: [
10+
'$filter',
11+
'$routeParams',
12+
'$rootScope',
13+
'AuthService',
14+
'Constants',
15+
NotificationCounter
16+
]
17+
});
18+
19+
function NotificationCounter($filter, $routeParams, $rootScope, AuthService, Constants) {
20+
21+
var counter = this;
22+
var DISABLE_GLOBAL_EVENT_WATCH = _.get(Constants, 'DISABLE_GLOBAL_EVENT_WATCH');
23+
var LIMIT_WATCHES = $filter('isIE')() || $filter('isEdge')();
24+
25+
counter.hide = true;
26+
27+
var rootScopeWatches = [];
28+
// this one is treated separately from the rootScopeWatches as
29+
// it may need to be updated outside of the lifecycle of init/destroy
30+
var notificationListeners = [];
31+
32+
var watchNotificationDrawerCount = function(projectName, cb) {
33+
if(!projectName) {
34+
return;
35+
}
36+
notificationListeners.push($rootScope.$on('NotificationDrawerWrapper.count', cb));
37+
};
38+
39+
var deregisterNotificationListeners = function() {
40+
_.each(notificationListeners, function(listener) {
41+
listener && listener();
42+
});
43+
notificationListeners = [];
44+
};
45+
46+
var deregisterRootScopeWatches = function() {
47+
_.each(rootScopeWatches, function(deregister) {
48+
deregister();
49+
});
50+
rootScopeWatches = [];
51+
};
52+
53+
var hideIfNoProject = function(projectName) {
54+
if(!projectName) {
55+
counter.hide = true;
56+
} else {
57+
counter.hide = false;
58+
}
59+
};
60+
61+
counter.onClick = function() {
62+
$rootScope.$emit('NotificationDrawerWrapper.toggle');
63+
};
64+
65+
var drawerCountCallback = function(event, newCount) {
66+
// NOTE: unread !== seen. We do not automatically mark
67+
// notifications unread when the drawer is closed.
68+
if(newCount) {
69+
counter.showUnreadNotificationsIndicator = true;
70+
} else {
71+
counter.showUnreadNotificationsIndicator = false;
72+
}
73+
};
74+
75+
var projectChanged = function(next, current) {
76+
return _.get(next, 'params.project') !== _.get(current, 'params.project');
77+
};
78+
79+
var reset = function() {
80+
watchNotificationDrawerCount($routeParams.project, drawerCountCallback);
81+
hideIfNoProject($routeParams.project);
82+
};
83+
84+
var initWatches = function() {
85+
reset();
86+
rootScopeWatches.push($rootScope.$on("$routeChangeSuccess", function (evt, next, current) {
87+
if(projectChanged(next, current)) {
88+
reset();
89+
}
90+
}));
91+
92+
rootScopeWatches.push($rootScope.$on('NotificationDrawerWrapper.onMarkAllRead', function() {
93+
counter.showUnreadNotificationsIndicator = false;
94+
}));
95+
};
96+
97+
counter.$onInit = function() {
98+
if(DISABLE_GLOBAL_EVENT_WATCH || LIMIT_WATCHES) {
99+
counter.hide = true;
100+
return;
101+
}
102+
if (AuthService.isLoggedIn()) {
103+
initWatches();
104+
} else {
105+
AuthService.onUserChanged(initWatches);
106+
}
107+
};
108+
109+
counter.$onDestroy = function() {
110+
deregisterNotificationListeners();
111+
deregisterRootScopeWatches();
112+
};
113+
}
114+
})();

0 commit comments

Comments
 (0)