-
Notifications
You must be signed in to change notification settings - Fork 230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Quota Notifications #2116
Quota Notifications #2116
Conversation
var setQuotaNotifications = function(quotas, clusterQuotas, projectName) { | ||
var notifications = QuotaService.getQuotaNotifications(quotas, clusterQuotas, projectName); | ||
_.each(notifications, function(notification) { | ||
// NotificationsService.restorePermanentlyHiddenNotification(notification.id, projectName); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops...debug op...I'll remove before final merge
@@ -259,6 +260,26 @@ | |||
onLinkClick: function(link) { | |||
link.onClick(); | |||
drawer.drawerHidden = true; | |||
}, | |||
handleAction: function(notification, action, index, group) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic shouldn't be in the drawer. Whoever adds the actions should be responsible for handling them.
switch (action.name) { | ||
case 'View Quotas': | ||
$location.url("/project/" + $routeParams.project + "/quota"); | ||
drawer.drawerHidden = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The link in the view should handle this for all actions on click.
app/scripts/services/quota.js
Outdated
@@ -254,6 +257,84 @@ angular.module("openshiftConsole") | |||
}); | |||
}; | |||
|
|||
var OBJECT_COUNT_QUOTAS = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This list is going to constantly be out of date as things are added upstream. Is it really needed? We should check whatever is declared in the quota.
app/scripts/services/quota.js
Outdated
var getNotificaitonMessage = function(used, usedValue, hard, hardValue, quotaKey) { | ||
var msgPrefix = "Your project is " + (hardValue < usedValue ? 'over' : 'at') + " quota. "; | ||
var msg; | ||
if (_.includes(OBJECT_COUNT_QUOTAS, quotaKey)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's remove OBJECT_COUNT_QUOTAS
and add a COMPUTE_RESOURCE_QUOTAS
, then check if quotaKey
is in COMPUTE_RESOURCE_QUOTAS
instead. The compute resource list is smaller, so will be easier to maintain. I'd also rather only call usageWithUnits
if we are sure it as a compute resource, not as a fallback. Otherwise that will be called for unrecognized types.
app/scripts/services/quota.js
Outdated
if (_.includes(OBJECT_COUNT_QUOTAS, quotaKey)) { | ||
msg = msgPrefix + "It is using " + usedValue + " of " + hardValue + " " + humanizeQuotaResource(quotaKey, true) + "."; | ||
} else { | ||
msg = msgPrefix + "It is using " + (usedValue / hardValue * 100) + "% of " + usageWithUnits(hard, quotaKey) + " " + humanizeQuotaResource(quotaKey, true) + "."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should round that percentage to avoid things like repeating decimals. I suggest using the percent
filter:
origin-web-console/app/scripts/filters/util.js
Lines 461 to 470 in c6ac85f
.filter('percent', function() { | |
// Takes a number like 0.33 and returns "33%". `precision` is the optional | |
// number of digits to appear after the decimal point. | |
return function(value, precision) { | |
if (value === null || value === undefined) { | |
return value; | |
} | |
return _.round(Number(value) * 100, precision) + "%"; | |
}; | |
}) |
app/scripts/services/quota.js
Outdated
message: getNotificaitonMessage(used, usedValue, hard, hardValue, quotaKey), | ||
skipToast: true, | ||
showInDrawer: true, | ||
actions: [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move the action on click handlers from the notification drawer to here. You can pass it as an onClick
property in the action.
@@ -35,7 +36,7 @@ | |||
href="" | |||
class="secondary-action" | |||
title="{{action.title}}" | |||
ng-click="$ctrl.customScope.handleAction(notification, action)"> | |||
ng-click="$ctrl.customScope.handleAction(notification, action, $parent.$parent.$index, notificationGroup)"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd change this to simply action.onClick()
if you take my suggestion above.
@@ -71,7 +72,7 @@ | |||
</span> | |||
|
|||
<span ng-if="!(notification.event.involvedObject)"> | |||
{{notification.message}} | |||
<span ng-bind-html="notification.message"></span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't assume that the message is HTML. We need a flag that says use HTML for the message. Otherwise plain text messages will not properly be escaped.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, should I check the message for HTML tags, or if I detect that a custom message is being used, is that enough to process it as HTML?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No way to reliably detect if it has markup. I would document that the custom quota messages are markup. Then add another a flag like notification.isHTML
that tells the drawer how to render it.
Hi @spadgett, I believe I have addressed all of your review issues. |
app/scripts/constants.js
Outdated
QUOTA_NOTIFICATION_MESSAGE: { | ||
// Example quota messages to show in notification drawer | ||
// "pods": "Upgrade to <a href='http://www.google.com'>OpenShift Pro</a> if you need additional resources.", | ||
// "limits.memory": "Upgrade to <a href='http://www.google.com'>OpenShift Online Pro</a> if you need additional resources." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can we change the URLs to openshift.com?
app/scripts/filters/util.js
Outdated
@@ -515,4 +515,13 @@ angular.module('openshiftConsole') | |||
return function(feature) { | |||
return _.get(Constants, ['ENABLE_TECH_PREVIEW_FEATURE', feature], false); | |||
}; | |||
}) | |||
.filter('hasHTML', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not try to test for HTML tags because this can have false positives. I would remove this filter.
app/scripts/services/quota.js
Outdated
|
||
if (Constants.QUOTA_NOTIFICATION_MESSAGE && Constants.QUOTA_NOTIFICATION_MESSAGE[quotaKey]) { | ||
msg += " " + Constants.QUOTA_NOTIFICATION_MESSAGE[quotaKey]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Always generate an HTML message here and set isHTML: true
below.
msg = _.escape(msg);
if (Constants.QUOTA_NOTIFICATION_MESSAGE && Constants.QUOTA_NOTIFICATION_MESSAGE[quotaKey]) {
msg += " " + Constants.QUOTA_NOTIFICATION_MESSAGE[quotaKey];
}
return msg;
app/scripts/services/quota.js
Outdated
namespace: projectName, | ||
type: (hardValue < usedValue ? 'warning' : 'info'), | ||
message: msg, | ||
isHTML: containsHTML, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isHTML: true
with the suggested changes above.
app/scripts/services/quota.js
Outdated
NotificationsService.permanentlyHideNotification(notification.uid, notification.namespace); | ||
EventsService.markCleared(notification.uid); | ||
group.notifications.splice(index, 1); | ||
drawer.customScope.countUnreadNotifications(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd change these onClick handlers to return true
if they should clear the notification and then move these two lines back to the drawer. The onClick
handler shouldn't need to take any parameters (you have a reference to the notification already through the closure).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notification drawer wrapper can check the onClick return value and then clear the notification if it's true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
action.onClick
isn't being called from the notificationDrawerWrapper.js, it is being called from the included notification-body.html
, here.
In quota.js
, I could throw $rootScope.$emit('NotificationDrawerWrapper.clear')
and also pass along the notification.id/uid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
action.onClick isn't being called from the notificationDrawerWrapper.js, it is being called from the included notification-body.html
Right, I understand. I'm proposing changing that to follow this basic pattern:
app/scripts/services/quota.js
Outdated
title: 'View project quotas', | ||
onClick: function(notification, action, index, group, drawer) { | ||
$location.url("/project/" + $routeParams.project + "/quota"); | ||
drawer.drawerHidden = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use something like
$rootScope.$emit('NotificationDrawerWrapper.hide');
to close the drawer? We're already listening for a toggle message in the drawer, so it should not be too tough to add another. I'd rather not pass the drawer
as a parameter.
Hi @spadgett, sorry, you lost me here, can you please elaborate? -thanks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dtaylor113 I don't need you need a reference to notification
at all in the onClick
callback. See my comment below.
app/scripts/services/quota.js
Outdated
name: "Don't Show Me Again", | ||
title: 'Permenantly hide this notificaiton until quota limit changes', | ||
onClick: function(notification, action, index, group, drawer) { | ||
NotificationsService.permanentlyHideNotification(notification.uid, notification.namespace); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't thinknotification.uid
is right. Where is uid
getting set?
It should be something like
var notificationID = 'openshift/hide-quota-warning/' + projectName + '/' + quotaKey;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
notification.uid
is being set here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I see. We should be scoping to a project. So maybe just above at line 313:
var notificationID = 'quota-warning/' + projectName + '/' + quotaKey;
Then we can use that value here and don't need a reference to the notification itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, I don't think the NotificationDrawerWrapper is setting a uid
anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
common's NotificationService already has an API for permanently hiding a notification. It takes an id and a 'namespace', which in this case is 'projectName'. So I don't think 'projectName' should be in the notificationID.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I see. That's fine then.
I think the point that the notification doesn't need to be passed back to the onClick
handlers stands, though. We already have quotaKey
and projectName
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, I don't think the NotificationDrawerWrapper is setting a uid anymore.
I still see it being set in Ben's PR here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I don't think that's needed in Ben's PR -- we shouldn't need 3 separate IDs -- but I'll leave well enough alone since it's in the merge queue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 IDs, wheeeee... 😄
Yeah I agree, oops on my part, I prob should have dropped one after adding trackByID
.
Hi @spadgett, updated with latest rounds of changes. I believe this is more inline with the separation of services. Quotas and the NotificationDrawer now communicate via events and hand off responsibilities appropriately. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @dtaylor113, looks good. Just a few small comments.
Ben's PR has merged, so you should be able to rebase.
@@ -217,6 +227,7 @@ | |||
hasUnread: false, | |||
showClearAll: true, | |||
showMarkAllRead: true, | |||
removeNotificationFromGroup: removeNotificationFromGroup, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't need to add to drawer
if it's not used in the view.
"limits.memory" | ||
]; | ||
|
||
var getNotificaitonMessage = function(used, usedValue, hard, hardValue, quotaKey) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth a comment that this function returns HTML markup, not plain text.
app/scripts/services/quota.js
Outdated
msg = _.escape(msg); | ||
|
||
if (Constants.QUOTA_NOTIFICATION_MESSAGE && Constants.QUOTA_NOTIFICATION_MESSAGE[quotaKey]) { | ||
msg += " " + Constants.QUOTA_NOTIFICATION_MESSAGE[quotaKey]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd comment here as well that the custom message is markup. Then it's clear why you don't need to call _.escape
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The custom message could just be a string and not contain HTML, right? Not sure what makes the custom message 'markup'? Is it escaped by being a Constant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if I wasn't clear. I'm saying to add a comment like
// QUOTA_NOTICIATION_MESSAGE can contain HTML and shouldn't be escaped.
I don't want someone to add an _.escape
call later thinking it was an oversight.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah..ok..will do
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment
app/scripts/services/quota.js
Outdated
var msgPrefix = "Your project is " + (hardValue < usedValue ? 'over' : 'at') + " quota. "; | ||
var msg; | ||
if (_.includes(COMPUTE_RESOURCE_QUOTAS, quotaKey)) { | ||
msg = msgPrefix + "It is using " + percent((usedValue/hardValue), 0) + " of " + usageWithUnits(hard, quotaKey) + " " + humanizeQuotaResource(quotaKey, true) + "."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not pass true
to humanizeResourceQuota
here and just below. We typically don't capitalize resource kinds in the console in sentences, only headings.
_.each(drawer.notificationGroups, function(group) { | ||
_.remove(group.notifications, function(grpNotification) { | ||
return grpNotification.uid === notification.uid && grpNotification.namespace === notification.namespace; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: this could be
_.remove(group.notifications, { uid: notification.uid, namespace: notification.namespace });
Hi, yes, filed a-pf issue: patternfly/angular-patternfly#614 |
Hi @spadgett, addressed your latest comments. Still have a question about escaping the custom message though. |
Thanks. I'm not 100% sure it's a a-pf bug since we're adding the dropdown. cc @rhamilto |
I see the clipping in our a-pf example with the notification drawer. I spend a little time trying |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work @dtaylor113. Really happy to see this going in.
One comment post rebase.
@@ -5,6 +5,8 @@ | |||
<a | |||
class="pull-right" | |||
href="" | |||
ng-if="!notification.actions.length" | |||
tabindex="0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove tabindex
. It's not needed now that we have an href
. Looks like this was accidentally added back on rebase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, removed tabindex
. -thanks
[merge] |
WebDriver flake [merge] |
Evaluated for origin web console merge up to b4407c9 |
Origin Web Console Merge Results: SUCCESS (https://ci.openshift.redhat.com/jenkins/job/merge_pull_request_origin_web_console/234/) (Base Commit: 1ceb0ff) (PR Branch Commit: b4407c9) |
@@ -555,5 +555,10 @@ angular.extend(window.OPENSHIFT_CONSTANTS, { | |||
// href: 'http://example.com/', | |||
// tooltip: 'Open Dashboard' | |||
// } | |||
] | |||
], | |||
QUOTA_NOTIFICATION_MESSAGE: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did we intend to leave this in as an empty object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe so. Similar to the other two empty objects right before this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, they're for custom messages. We generate a default message in code.
Push quota notifications to notification drawer:
Trello
Design