Skip to content
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

Merged
merged 1 commit into from
Sep 20, 2017
Merged

Quota Notifications #2116

merged 1 commit into from
Sep 20, 2017

Conversation

dtaylor113
Copy link
Contributor

Push quota notifications to notification drawer:

quotas

Trello
Design

var setQuotaNotifications = function(quotas, clusterQuotas, projectName) {
var notifications = QuotaService.getQuotaNotifications(quotas, clusterQuotas, projectName);
_.each(notifications, function(notification) {
// NotificationsService.restorePermanentlyHiddenNotification(notification.id, projectName);
Copy link
Contributor Author

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) {
Copy link
Member

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;
Copy link
Member

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.

@@ -254,6 +257,84 @@ angular.module("openshiftConsole")
});
};

var OBJECT_COUNT_QUOTAS = [
Copy link
Member

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.

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)) {
Copy link
Member

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.

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) + ".";
Copy link
Member

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:

.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) + "%";
};
})

message: getNotificaitonMessage(used, usedValue, hard, hardValue, quotaKey),
skipToast: true,
showInDrawer: true,
actions: [
Copy link
Member

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)">
Copy link
Member

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>
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

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.

@dtaylor113
Copy link
Contributor Author

Hi @spadgett, I believe I have addressed all of your review issues.
Thanks,
Dave

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."
Copy link
Member

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?

@@ -515,4 +515,13 @@ angular.module('openshiftConsole')
return function(feature) {
return _.get(Constants, ['ENABLE_TECH_PREVIEW_FEATURE', feature], false);
};
})
.filter('hasHTML', function() {
Copy link
Member

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.


if (Constants.QUOTA_NOTIFICATION_MESSAGE && Constants.QUOTA_NOTIFICATION_MESSAGE[quotaKey]) {
msg += " " + Constants.QUOTA_NOTIFICATION_MESSAGE[quotaKey];
}
Copy link
Member

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;

namespace: projectName,
type: (hardValue < usedValue ? 'warning' : 'info'),
message: msg,
isHTML: containsHTML,
Copy link
Member

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.

NotificationsService.permanentlyHideNotification(notification.uid, notification.namespace);
EventsService.markCleared(notification.uid);
group.notifications.splice(index, 1);
drawer.customScope.countUnreadNotifications();
Copy link
Member

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).

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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:

https://github.com/openshift/origin-web-console/blob/master/app/views/_alerts.html#L24

https://github.com/openshift/origin-web-console/blob/master/app/scripts/directives/alerts.js#L34-L42

title: 'View project quotas',
onClick: function(notification, action, index, group, drawer) {
$location.url("/project/" + $routeParams.project + "/quota");
drawer.drawerHidden = true;
Copy link
Member

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.

@dtaylor113
Copy link
Contributor Author

The onClick handler shouldn't need to take any parameters (you have a reference to the notification already through the closure).

Hi @spadgett, sorry, you lost me here, can you please elaborate? -thanks

Copy link
Member

@spadgett spadgett left a 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.

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);
Copy link
Member

@spadgett spadgett Sep 19, 2017

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;

Copy link
Contributor Author

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

Copy link
Member

@spadgett spadgett Sep 19, 2017

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.

Copy link
Member

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.

Copy link
Contributor Author

@dtaylor113 dtaylor113 Sep 19, 2017

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.

Copy link
Member

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.

Copy link
Contributor Author

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

Copy link
Member

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.

Copy link
Contributor

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.

@openshift-bot openshift-bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Sep 19, 2017
@dtaylor113
Copy link
Contributor Author

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.

Copy link
Member

@spadgett spadgett left a 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,
Copy link
Member

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) {
Copy link
Member

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.

msg = _.escape(msg);

if (Constants.QUOTA_NOTIFICATION_MESSAGE && Constants.QUOTA_NOTIFICATION_MESSAGE[quotaKey]) {
msg += " " + Constants.QUOTA_NOTIFICATION_MESSAGE[quotaKey];
Copy link
Member

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.

Copy link
Contributor Author

@dtaylor113 dtaylor113 Sep 20, 2017

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?

Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah..ok..will do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comment

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) + ".";
Copy link
Member

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;
});
Copy link
Member

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 });

@spadgett
Copy link
Member

I noticed that the dropdown can get clipped if there's only one notification:

screen shot 2017-09-20 at 7 00 35 am

@dtaylor113
Copy link
Contributor Author

I noticed that the dropdown can get clipped if there's only one notification:

Hi, yes, filed a-pf issue: patternfly/angular-patternfly#614

@dtaylor113
Copy link
Contributor Author

Hi @spadgett, addressed your latest comments. Still have a question about escaping the custom message though.

@dtaylor113 dtaylor113 changed the title [WIP] Quota Notifications Quota Notifications Sep 20, 2017
@spadgett
Copy link
Member

Hi, yes, filed a-pf issue: patternfly/angular-patternfly#614

Thanks. I'm not 100% sure it's a a-pf bug since we're adding the dropdown.

cc @rhamilto

@dtaylor113
Copy link
Contributor Author

dtaylor113 commented Sep 20, 2017

Thanks. I'm not 100% sure it's a a-pf bug since we're adding the dropdown.

I see the clipping in our a-pf example with the notification drawer. I spend a little time trying overflow and z-index properties but couldn't get it to work the way I wanted.

Copy link
Member

@spadgett spadgett left a 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"
Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, removed tabindex. -thanks

@spadgett spadgett removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Sep 20, 2017
@spadgett
Copy link
Member

[merge]

@spadgett
Copy link
Member

WebDriver flake

[merge]

@openshift-bot
Copy link

Evaluated for origin web console merge up to b4407c9

@openshift-bot
Copy link

openshift-bot commented Sep 20, 2017

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: {
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants