launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #06052
[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">