← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~rvb/launchpad/ppa-copy-notifications-javascript into lp:launchpad

 

Raphaël Badin has proposed merging lp:~rvb/launchpad/ppa-copy-notifications-javascript into lp:launchpad with lp:~rvb/launchpad/ppa-copy-notifications-template as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~rvb/launchpad/ppa-copy-notifications-javascript/+merge/87763

This branch is the javascript part of a work to show the job notifications on a ppa's +packages page. This branch adds a new YUI widget to control the interaction with the notifications that can be cancelled via an ajax call to the api.

= Tests =
lib/lp/soyuz/javascript/tests/test_archive-packages.html

= Q/A =
Copy a few packages into a ppa making sure that some copy will fail.  The ppa's +package page should display the related notifications along with a "Remove notification" link that should allow one to remove the notification's information.
-- 
https://code.launchpad.net/~rvb/launchpad/ppa-copy-notifications-javascript/+merge/87763
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~rvb/launchpad/ppa-copy-notifications-javascript into lp:launchpad.
=== added file 'lib/lp/soyuz/javascript/archive-packages.js'
--- lib/lp/soyuz/javascript/archive-packages.js	1970-01-01 00:00:00 +0000
+++ lib/lp/soyuz/javascript/archive-packages.js	2012-01-06 16:35:52 +0000
@@ -0,0 +1,130 @@
+/* Copyright 2012 Canonical Ltd.  This software is licensed under the
+ * GNU Affero General Public License version 3 (see the file LICENSE).
+ *
+ * Code for handling the JavaScript side of archive-package.
+ *
+ * @module lp.soyuz.archive_packages
+ * @requires node
+ */
+
+YUI.add('lp.soyuz.archive_packages', function(Y) {
+
+// Grab the namespace in order to be able to expose the connect method.
+var namespace = Y.namespace('lp.soyuz.archive_packages');
+
+var PendingCopyJobWidget = function() {
+    PendingCopyJobWidget.superclass.constructor.apply(this, arguments);
+};
+
+PendingCopyJobWidget.NAME = 'pending-copy-job-widget';
+
+PendingCopyJobWidget.ATTRS = {
+    /**
+     * The id for this job.
+     *
+     * @attribute job_id
+     * @type String
+     * @default null
+     */
+    job_id: {
+        value: null
+    },
+    /**
+     * The uri for the context archive.
+     *
+     * @attribute archive_uri
+     * @type String
+     * @default null
+     */
+    archive_uri: {
+        value: null
+    }
+};
+
+PendingCopyJobWidget.HTML_PARSER = {
+    job_id: function(srcNode) {
+        return srcNode.getAttribute('job_id');
+    }
+};
+
+Y.extend(PendingCopyJobWidget, Y.Widget, {
+    initializer: function(cfg) {
+        this.client = new Y.lp.client.Launchpad();
+        this.set('archive_uri', cfg.archive_uri);
+    },
+
+    bindUI: function() {
+        this.constructor.superclass.bindUI.call(this);
+        // Wire up the cancel link.
+        var cancel_link = this.get('srcNode').one('.remove-notification');
+        if (Y.Lang.isValue(cancel_link)) {
+            var self = this;
+            cancel_link.on('click', function(e) {
+                e.halt();
+                self.cancel();
+            });
+        }
+    },
+
+    /**
+     * Show the spinner.
+     *
+     * @method showSpinner
+     */
+    showSpinner: function() {
+        var spinnerNode = Y.Node.create('<img />')
+            .set('src', '/@@/spinner')
+            .addClass('spinner');
+        var cancel_link = this.get('srcNode').one('.remove-notification');
+        cancel_link.insert(spinnerNode, 'after');
+    },
+
+    /**
+     * Hide the spinner.
+     *
+     * @method hideSpinner
+     */
+    hideSpinner: function() {
+        this.get('srcNode').all('.spinner').remove();
+    },
+
+    /**
+     * Cancel this copy job: call the removeCopyNotification api method and
+     * delete the node from the page.
+     *
+     * @method cancel
+     */
+    cancel: function() {
+        var self = this;
+        var config = {
+            on: {
+                start: function() {
+                    self.showSpinner();
+                },
+                end: function() {
+                    self.hideSpinner();
+                },
+                success: function() {
+                    Y.lp.anim.green_flash({node: self.get('srcNode')}).run();
+                    self.get('srcNode').remove();
+                },
+                failure: function() {
+                    Y.lp.anim.red_flash({node: self.get('srcNode')}).run();
+                }
+            },
+            parameters: {
+                job_id: this.get('job_id')
+            }
+        };
+        this.client.named_post(
+            this.get('archive_uri'), 'removeCopyNotification', config);
+
+        this.fire('cancel');
+    }
+
+});
+
+namespace.PendingCopyJobWidget = PendingCopyJobWidget;
+
+}, '0.1', {requires: ['event', 'io', 'node', 'widget', 'lp.client',
+                      'lp.anim']});

=== added file 'lib/lp/soyuz/javascript/tests/test_archive-packages.html'
--- lib/lp/soyuz/javascript/tests/test_archive-packages.html	1970-01-01 00:00:00 +0000
+++ lib/lp/soyuz/javascript/tests/test_archive-packages.html	2012-01-06 16:35:52 +0000
@@ -0,0 +1,53 @@
+<!DOCTYPE
+   HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+   "http://www.w3.org/TR/html4/strict.dtd";>
+<html>
+  <head>
+  <title>Launchpad Archive Packages</title>
+
+  <!-- YUI and test setup -->
+  <script type="text/javascript"
+          src="../../../../canonical/launchpad/icing/yui/yui/yui.js">
+  </script>
+  <link rel="stylesheet" href="../../../app/javascript/testing/test.css" />
+  <script type="text/javascript"
+          src="../../../app/javascript/testing/testrunner.js"></script>
+
+  <script type="text/javascript"
+          src="../../../app/javascript/testing/mockio.js"></script>
+  <script type="text/javascript" src="../../../app/javascript/client.js"></script>
+  <script type="text/javascript" src="../../../app/javascript/lp.js"></script>
+  <script type="text/javascript" src="../../../app/javascript/anim/anim.js"></script>
+  <script type="text/javascript"
+          src="../../../app/javascript/extras/extras.js"></script>
+
+  <!-- The module under test -->
+  <script type="text/javascript"
+          src="../archive-packages.js"></script>
+
+  <!-- The test suite -->
+  <script type="text/javascript"
+          src="test_archive-packages.js"></script>
+
+  </head>
+  <body class="yui3-skin-sam">
+    <ul id="suites">
+      <li>lp.soyuz.archive_packages.test</li>
+    </ul>
+
+    <div id="placeholder">
+    </div>
+
+    <script type="text/x-template" id="pending-job-template">
+      <div class="pending-job" job_id="3">
+        <a class="remove-notification">Remove notification</a>
+      </div>
+    </script>
+    <script type="text/x-template" id="pending-job-template-no-link">
+      <div class="pending-job" job_id="3">
+      </div>
+    </script>
+
+
+  </body>
+</html>

=== added file 'lib/lp/soyuz/javascript/tests/test_archive-packages.js'
--- lib/lp/soyuz/javascript/tests/test_archive-packages.js	1970-01-01 00:00:00 +0000
+++ lib/lp/soyuz/javascript/tests/test_archive-packages.js	2012-01-06 16:35:52 +0000
@@ -0,0 +1,124 @@
+/**
+ * Copyright 2012 Canonical Ltd. This software is licensed under the
+ * GNU Affero General Public License version 3 (see the file LICENSE).
+ *
+ * Tests for lp.soyuz.archive_packages.
+ *
+ * @module lp.soyuz.archive_packages
+ * @submodule test
+ */
+
+YUI.add('lp.soyuz.archive_packages.test', function(Y) {
+
+    var namespace = Y.namespace('lp.soyuz.archive_packages.test');
+
+    var suite = new Y.Test.Suite("archive_packages Tests");
+    var module = Y.lp.soyuz.archive_packages;
+
+    var pending_job = Y.one('#pending-job-template').getContent();
+    var pending_job_no_link = Y.one(
+        '#pending-job-template-no-link').getContent();
+
+    var TestPendingCopyJobWidgetNoLink = {
+        name: "TestPendingCopyJobWidgetNoLink",
+
+        setUp: function() {
+            Y.one("#placeholder")
+                .empty()
+                .append(Y.Node.create(pending_job));
+        },
+
+        test_instanciation: function() {
+            // The widget is instanciated even without a link to delete the
+            // widget's html.
+            var area = Y.one('.pending-job-no-link');
+            this.widget = new module.PendingCopyJobWidget(
+                {srcNode: area, archive_uri: '/archive/4'});
+            this.widget.render();
+        }
+
+    };
+
+    suite.add(new Y.Test.Case(TestPendingCopyJobWidgetNoLink));
+
+    var TestPendingCopyJobWidget = {
+        name: "TestPendingCopyJobWidget",
+
+        setUp: function() {
+            Y.one("#placeholder")
+                .empty()
+                .append(Y.Node.create(pending_job));
+            var area = Y.one('.pending-job');
+            this.widget = new module.PendingCopyJobWidget(
+                {srcNode: area, archive_uri: '/archive/4'});
+            this.widget.render();
+        },
+
+        simulate_cancel_click: function() {
+            // Simulate a click on the cancel link.
+            var link = Y.one("#placeholder").one('.remove-notification');
+            link.simulate('click');
+        },
+
+        mock_lp_client: function() {
+            // Mock lp client.
+            this.mockio = new Y.lp.testing.mockio.MockIo();
+            this.widget.client.io_provider = this.mockio;
+        },
+
+        test_job_id_parsed: function() {
+            Y.Assert.areEqual('3', this.widget.get('job_id'));
+        },
+
+        test_cancel_fun_wired: function() {
+            // Make sure that the cancel event is fired when the cancel button
+            // is clicked.
+
+            this.mock_lp_client();
+
+            // Setup event listener.
+            var event_fired = false;
+            var handleEvent = function(e) {
+                event_fired = true;
+            };
+            this.widget.on(
+                this.widget.name + ":cancel",
+                handleEvent, this.widget);
+
+            this.simulate_cancel_click();
+
+            Y.Assert.areSame(1, this.mockio.requests.length);
+            Y.Assert.isTrue(event_fired);
+        },
+
+        test_cancel_success_cleans_html: function() {
+            this.mock_lp_client();
+            this.simulate_cancel_click();
+            this.mockio.success({
+                responseText:'.',
+                responseHeaders: {'Content-Type': 'application/xhtml'}
+            });
+            // The HTML chunk has been deleted.
+            Y.Assert.isNull(Y.one("#placeholder").one('.pending-job'));
+        },
+
+        test_show_spinner: function() {
+            this.widget.showSpinner();
+            Y.Assert.isNotNull(Y.one("#placeholder").one('.spinner'));
+        },
+
+        test_hide_spinner: function() {
+            this.widget.showSpinner();
+            this.widget.hideSpinner();
+            Y.Assert.isNull(Y.one("#placeholder").one('.spinner'));
+        }
+
+    };
+
+    suite.add(new Y.Test.Case(TestPendingCopyJobWidget));
+
+    namespace.suite = suite;
+
+}, "0.1", {"requires": [
+               "lp.soyuz.archive_packages", "node", "lp.testing.mockio",
+               "node-event-simulate", "test", "lp.anim"]});

=== modified file 'lib/lp/soyuz/templates/archive-packages.pt'
--- lib/lp/soyuz/templates/archive-packages.pt	2012-01-06 16:35:51 +0000
+++ lib/lp/soyuz/templates/archive-packages.pt	2012-01-06 16:35:52 +0000
@@ -88,6 +88,26 @@
 }
 
 Y.on("domready", dispatchUpdate);
+
+});
+      </script>
+      <script type="text/javascript" id="repository-size-update">
+LPS.use('lp.soyuz.archive_packages',
+          'lp.app.widgets.expander.Expander', function(Y) {
+
+Y.on('domready', function() {
+    Y.all('.pending-job').each(function(node) {
+        var widget = new Y.lp.soyuz.archive_packages.PendingCopyJobWidget(
+            {srcNode: node, archive_uri: LP.cache['context'].self_link });
+        widget.render();
+
+        var expander = new Y.lp.app.widgets.expander.Expander(
+            node.one('.job-summary'), node.one('.job-details'));
+        expander.setUp();
+
+    });
+});
+
 });
       </script>
       <style type="text/css" media="screen, print">