← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wallyworld/launchpad/show-ajax-notifications into lp:launchpad

 

Ian Booth has proposed merging lp:~wallyworld/launchpad/show-ajax-notifications into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wallyworld/launchpad/show-ajax-notifications/+merge/54342

Display notifications that may be included in an xhr response object. These are of type informational, error, warning or debug.
-- 
https://code.launchpad.net/~wallyworld/launchpad/show-ajax-notifications/+merge/54342
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wallyworld/launchpad/show-ajax-notifications into lp:launchpad.
=== modified file 'lib/canonical/launchpad/webapp/configure.zcml'
--- lib/canonical/launchpad/webapp/configure.zcml	2011-02-03 19:01:10 +0000
+++ lib/canonical/launchpad/webapp/configure.zcml	2011-03-28 01:50:57 +0000
@@ -58,6 +58,11 @@
         provides="lazr.restful.interfaces.IWebBrowserOriginatingRequest"
         factory="canonical.launchpad.webapp.servers.web_service_request_to_browser_request"
         />
+    <adapter
+        for="canonical.launchpad.layers.WebServiceLayer"
+        provides="lazr.restful.interfaces.INotificationsProvider"
+        factory="canonical.launchpad.webapp.servers.web_service_request_to_notification_request"
+        />
 
     <!-- lazr.batchnavigator hook -->
     <adapter

=== modified file 'lib/canonical/launchpad/webapp/servers.py'
--- lib/canonical/launchpad/webapp/servers.py	2010-12-06 14:59:43 +0000
+++ lib/canonical/launchpad/webapp/servers.py	2011-03-28 01:50:57 +0000
@@ -21,7 +21,6 @@
     WebServiceRequestTraversal,
     )
 from lazr.uri import URI
-import pytz
 import transaction
 from transaction.interfaces import ISynchronizer
 from zc.zservertracelog.tracelog import Server as ZServerTracelogServer
@@ -704,6 +703,11 @@
     return LaunchpadBrowserRequest(body, environ)
 
 
+def web_service_request_to_notification_request(request):
+    """Convert a given webservice request into one providing notifications."""
+    return INotificationRequest(request)
+
+
 class Zope3WidgetsUseIBrowserFormNGMonkeyPatch:
     """Make Zope3 widgets use IBrowserFormNG.
 

=== modified file 'lib/lp/app/javascript/client.js'
--- lib/lp/app/javascript/client.js	2011-02-25 01:54:00 +0000
+++ lib/lp/app/javascript/client.js	2011-03-28 01:50:57 +0000
@@ -242,6 +242,8 @@
         var media_type = response.getResponseHeader('Content-Type');
         if (media_type.substring(0,16) == 'application/json') {
             representation = Y.JSON.parse(response.responseText);
+            display_notifications(
+                    response.getResponseHeader('X-Lazr-Notifications'));
             wrapped = client.wrap_resource(uri, representation);
             result = old_on_success(wrapped);
             if (update_cache) {
@@ -254,6 +256,73 @@
     }
 };
 
+/**
+ * Display a list of notifications - error, warning, informational or debug.
+ * @param notifications An json encoded array of (level, message) tuples.
+ */
+function display_notifications(notifications) {
+    if (notifications === undefined)
+        return;
+
+    // First remove any existing notifications.
+    function remove_notifications(div_class) {
+        var nodes = Y.all('div.'+div_class);
+        nodes.each(function(node) {
+            var parent = node.get('parentNode');
+            parent.removeChild(node);
+        });
+    }
+    remove_notifications('error');
+    remove_notifications('warning');
+    remove_notifications('informational');
+    remove_notifications('debug');
+
+    // Now display the new ones.
+    notifications = Y.JSON.parse(notifications);
+    var warnings = new Array();
+    var errors = new Array();
+    var infos = new Array();
+    var debugs = new Array();
+
+    Y.each(notifications, function(notification, key) {
+        var level = notification[0];
+        var message = notification[1];
+        switch (level) {
+            case 10:
+                debugs.push(message);
+                break;
+            case 20:
+                infos.push(message);
+                break;
+            case 30:
+                warnings.push(message);
+                break;
+            case 40:
+                errors.push(message);
+                break;
+        }
+    });
+    // The place where we want to insert the notification divs.
+    var last_message = Y.one('div.context-publication');
+    var display_notification = function(notification, div_class) {
+        var node = Y.Node.create("<div class='"+div_class+"'/>");
+        node.set('innerHTML', notification);
+        last_message.insert(node, 'after');
+        last_message = node;
+    };
+    Y.each(errors, function(notification, key) {
+        display_notification(notification, 'error message');
+    });
+    Y.each(warnings, function(notification, key) {
+        display_notification(notification, 'warning message');
+    });
+    Y.each(infos, function(notification, key) {
+        display_notification(notification, 'informational message');
+    });
+    Y.each(debugs, function(notification, key) {
+        display_notification(notification, 'debug message');
+    });
+}
 
 // The resources that come together to make Launchpad.
 

=== modified file 'lib/lp/app/javascript/tests/test_lp_client.html'
--- lib/lp/app/javascript/tests/test_lp_client.html	2011-02-25 01:54:00 +0000
+++ lib/lp/app/javascript/tests/test_lp_client.html	2011-03-28 01:50:57 +0000
@@ -18,7 +18,9 @@
   <script type="text/javascript" src="test_lp_client.js"></script>
 </head>
 <body class="yui3-skin-sam">
-  <div id="container-of-stuff">
+  <div class="context-publication">
+    <div id="container-of-stuff">
+    </div>
   </div>
 </body>
 </html>

=== modified file 'lib/lp/app/javascript/tests/test_lp_client.js'
--- lib/lp/app/javascript/tests/test_lp_client.js	2011-02-25 02:51:27 +0000
+++ lib/lp/app/javascript/tests/test_lp_client.js	2011-03-28 01:50:57 +0000
@@ -171,6 +171,53 @@
       }
 }));
 
+function MockHttpResponse () {
+    this.responseText = '[]';
+    this.responseHeaders = {};
+}
+
+MockHttpResponse.prototype = {
+    setResponseHeader: function (header, value) {
+        this.responseHeaders[header] = value;
+    },
+
+    getResponseHeader: function(header) {
+        return this.responseHeaders[header];
+    }
+};
+
+suite.add(new Y.Test.Case({
+    name: "lp.client.notifications",
+
+    setUp: function() {
+        this.client = new Y.lp.client.Launchpad();
+        this.args=[this.client, null, this._on_success, false];
+        this.response = new MockHttpResponse();
+        this.response.setResponseHeader('Content-Type', 'application/json');
+    },
+
+    _on_success: function(entry) {
+    },
+
+    _checkNotificationNode: function(node_class, node_text) {
+        var node = Y.one('div.'+node_class);
+        Assert.areEqual(node_text, node.get("innerHTML"));
+    },
+
+    test_display_notifications: function() {
+        var notifications = '[ [10, "A debug"], [20, "An info"], ' +
+            '[30, "A warning"], [40, "An error"] ]';
+        this.response.setResponseHeader(
+                'X-Lazr-Notifications', notifications);
+        Y.lp.client.wrap_resource_on_success(null, this.response, this.args);
+        this._checkNotificationNode('debug', 'A debug');
+        this._checkNotificationNode('informational', 'An info');
+        this._checkNotificationNode('warning', 'A warning');
+        this._checkNotificationNode('error', 'An error');
+    }
+
+}));
+
 
 // Lock, stock, and two smoking barrels.
 var handle_complete = function(data) {

=== modified file 'versions.cfg'
--- versions.cfg	2011-03-23 16:28:51 +0000
+++ versions.cfg	2011-03-28 01:50:57 +0000
@@ -34,7 +34,7 @@
 lazr.delegates = 1.2.0
 lazr.enum = 1.1.2
 lazr.lifecycle = 1.1
-lazr.restful = 0.18.0
+lazr.restful = 0.18.1
 lazr.restfulclient = 0.11.2
 lazr.smtptest = 1.1
 lazr.testing = 0.1.1