launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #05474
[Merge] lp:~adeuring/launchpad/banner-for-beta-features-2 into lp:launchpad
Abel Deuring has proposed merging lp:~adeuring/launchpad/banner-for-beta-features-2 into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~adeuring/launchpad/banner-for-beta-features-2/+merge/81833
This branch adds a banner pages having features in beta status.
The core idea: LP.cache has an entry "beta_features", which
contains copies of the tuples from lp.services.features.flags.flag_info
for features matching these conditions:
- the feature name appears in view.beta_features
- when a page is rendered, the value of the feature flag is not the
default value. (see
lp:~adeuring/launchpad/banner-for-beta-features for details)
The function beta_notification() in beta-notification.js checks if
LP.cache.beta_features is not emtpy, and if so, it adds a banner to
the page showing the title of the beta feature flags and optionally
a link to a page with more information about the feature.
The banner can be hidden by a click on the "hide" link.
The new property BugTaskSearchListingView.beta_features (which
overrides LaunchpadView.beta_features) activates the banner for bug
listings.
test: /bin/test -vvt test_beta_notification
Demo/QA:
- enable the feature flag bugs.dynamic_bug_listings.enabled
- visit any bug listing, for example https://bugs.launchpad.dev/firefox
lint:
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/canonical/launchpad/icing/style-3-0.css
lib/lp/app/javascript/beta-notification.js
lib/lp/app/javascript/tests/test_beta_notification.html
lib/lp/app/javascript/tests/test_beta_notification.js
lib/lp/app/templates/base-layout-macros.pt
lib/lp/bugs/browser/bugtask.py
./lib/canonical/launchpad/icing/style-3-0.css
58: Unknown Property name.: -moz-border-radius
59: Unknown Property name.: -webkit-border-radius
60: Unknown Property name.: -khtml-border-radius
61: Unknown Property name.: border-radius
[ca 700 lines deleted]
2331: I003: To few newlines before selectors.
2334: I003: To few newlines before selectors.
2349: I003: To few newlines before selectors.
2352: I003: To few newlines before selectors.
--
https://code.launchpad.net/~adeuring/launchpad/banner-for-beta-features-2/+merge/81833
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~adeuring/launchpad/banner-for-beta-features-2 into lp:launchpad.
=== modified file 'lib/canonical/launchpad/icing/style-3-0.css'
--- lib/canonical/launchpad/icing/style-3-0.css 2011-11-02 21:19:13 +0000
+++ lib/canonical/launchpad/icing/style-3-0.css 2011-11-10 11:33:48 +0000
@@ -2101,6 +2101,37 @@
padding: 0;
}
+/* ===========
+ Beta banner
+*/
+.beta-banner {
+ position: fixed;
+ z-index: 9;
+ top: 0;
+ left: 0;
+ right: 0;
+ padding: 8px 20px;
+ /* Define colour for browsers that don't support transparency */
+ background-color: #606060;
+ /* Set transparent background for browsers that support it */
+ background-color: rgba(64, 64, 64,0.9);
+ color: #fff;
+ font-size: 14px;
+ line-height: 21px;
+ }
+.beta-banner .info-link {
+ color: #4884ef;
+}
+.beta-warning {
+ padding: 4px;
+ margin-right: 8px;
+ background-color: #be0000;
+ font-weight: bold;
+ }
+.beta-feature {
+ font-weight: bold;
+ }
+
/*
* YOU HAVE REACHED THE END OF THIS FILE. IF YOU SEE ANYTHING BELOW SPRITES
=== added file 'lib/lp/app/javascript/beta-notification.js'
--- lib/lp/app/javascript/beta-notification.js 1970-01-01 00:00:00 +0000
+++ lib/lp/app/javascript/beta-notification.js 2011-11-10 11:33:48 +0000
@@ -0,0 +1,132 @@
+YUI.add('lp.app.beta_features', function(Y) {
+
+var namespace = Y.namespace('lp.app.beta_features');
+
+var beta_notification_node = null;
+
+/**
+ * For unit tests - we need to reset the notification setup to run more than
+ one test.
+ */
+namespace._reset_beta_notification = function () {
+ notification_node = null;
+};
+
+/*
+ * Display beta feature notifications.
+ *
+ * This should be called after the page has loaded e.g. on 'domready'.
+ */
+function display_beta_notification() {
+ if (LP.cache.beta_features.length === 0) {
+ return;
+ }
+
+ var beta_features = LP.cache.beta_features;
+ var body = Y.one('body');
+ body.addClass('global-notification-visible');
+ var target_id = "maincontent";
+ var id_selector = "#" + target_id;
+ var main = Y.one(id_selector);
+ beta_notification_node = Y.Node.create('<div></div>')
+ .addClass('beta-banner');
+ main.appendChild(beta_notification_node);
+ var beta_warning = Y.Node.create(
+ '<span class="beta-warning">BETA</span>');
+ beta_notification_node.appendChild(beta_warning);
+ var close_box = Y.Node.create(
+ '<a href="#" class="global-notification-close">Hide' +
+ '<span class="notification-close sprite" /></a>');
+ beta_notification_node.appendChild(close_box);
+ beta_notification_node.append('Some parts of this page are in beta: ');
+ var index;
+ for (index = 0; index < beta_features.length; index++) {
+ var feature_name = beta_features[index][4];
+ var info_link = beta_features[index][5];
+ if (info_link.length > 0) {
+ info_link =
+ ' (<a href="' + info_link + '" class="info-link">' +
+ 'read more</a>)';
+ }
+ beta_notification_node.appendChild(Y.Node.create(
+ '<span class="beta-feature"> ' + feature_name + info_link +
+ '</span>'));
+ }
+ close_box.on('click', function(e) {
+ e.halt();
+ var fade_out = new Y.Anim({
+ node: '.beta-banner',
+ to: {opacity: 0},
+ duration: 0.3
+ });
+ var body_space = new Y.Anim({
+ node: 'body',
+ to: {'paddingTop': 0},
+ duration: 0.2,
+ easing: Y.Easing.easeOut
+ });
+ var login_space = new Y.Anim({
+ node: '.login-logout',
+ to: {'top': '6px'},
+ duration: 0.2,
+ easing: Y.Easing.easeOut
+ });
+ fade_out.on('end', function() {
+ fade_out.get('node').addClass('hidden');
+ });
+ body_space.on('end', function() {
+ Y.one('body').removeClass('global-notification-visible');
+ });
+
+ fade_out.run();
+ body_space.run();
+ login_space.run();
+ });
+}
+namespace.display_beta_notification = display_beta_notification;
+
+/*
+ * Hide beta notifications
+ */
+function hide_beta_notification() {
+ setup_beta_notification();
+ if (!Y.one('.global-notification').hasClass('hidden')) {
+ var fade_out = new Y.Anim({
+ node: '.global-notification',
+ to: {opacity: 0},
+ duration: 0.3
+ });
+ var body_space = new Y.Anim({
+ node: 'body',
+ to: {'paddingTop': 0},
+ duration: 0.2,
+ easing: Y.Easing.easeOut
+ });
+ var login_space = new Y.Anim({
+ node: '.login-logout',
+ to: {'top': '6px'},
+ duration: 0.2,
+ easing: Y.Easing.easeOut
+ });
+ fade_out.on('end', function() {
+ fade_out.get('node').addClass('hidden');
+ });
+ body_space.on('end', function() {
+ Y.one('body').removeClass('global-notification-visible');
+ });
+
+ fade_out.run();
+ body_space.run();
+ login_space.run();
+
+ }
+}
+namespace.hide_beta_notification = hide_beta_notification;
+
+/* A helper for unit tests. */
+namespace._reset_beta_notification = function() {
+ beta_notification_node = null;
+};
+
+
+}, "0.1", {"requires": ["base", "node", "anim"]});
=== added file 'lib/lp/app/javascript/tests/test_beta_notification.html'
--- lib/lp/app/javascript/tests/test_beta_notification.html 1970-01-01 00:00:00 +0000
+++ lib/lp/app/javascript/tests/test_beta_notification.html 2011-11-10 11:33:48 +0000
@@ -0,0 +1,23 @@
+<html>
+ <head>
+ <title>Launchpad Beta Feature Notifications</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>
+
+ <!-- The module under test. -->
+ <script type="text/javascript" src="../beta-notification.js"></script>
+
+ <!-- The test suite. -->
+ <script type="text/javascript" src="test_beta_notification.js"></script>
+ </head>
+ <body class="yui3-skin-sam">
+ <!-- The example markup required by the script to run. -->
+ <div id="maincontent"> </div>
+ </body>
+</html>
=== added file 'lib/lp/app/javascript/tests/test_beta_notification.js'
--- lib/lp/app/javascript/tests/test_beta_notification.js 1970-01-01 00:00:00 +0000
+++ lib/lp/app/javascript/tests/test_beta_notification.js 2011-11-10 11:33:48 +0000
@@ -0,0 +1,125 @@
+/* Copyright 2011 Canonical Ltd. This software is licensed under the
+ * GNU Affero General Public License version 3 (see the file LICENSE).
+ */
+
+// Set the "enabled" variable, normally set by base-layout-macros.
+// This must be a global variable for the code being tested to work.
+var privacy_notification_enabled = true;
+
+YUI().use('lp.testing.runner', 'test', 'console', 'node',
+ 'lp.app.beta_features', 'node-event-simulate', function(Y) {
+
+ var suite = new Y.Test.Suite("lp.app.beta_notification Tests");
+
+ suite.add(new Y.Test.Case({
+ name: 'beta-notification',
+
+ _reset_container: function () {
+ Y.lp.app.beta_features._reset_beta_notification();
+ var body = Y.one(document.body);
+
+ // Replace the container.
+ var container = Y.one('#maincontent');
+ container.remove(true);
+ container = Y.Node.create('<div></div>')
+ .set('id', 'maincontent');
+ body.appendChild(container);
+ body.removeClass('global-notification-visible');
+ return container;
+ },
+
+ setUp: function () {
+ // Create the global notification html.
+ var container = this._reset_container();
+ var login_logout = Y.Node.create('<div></div>')
+ .addClass('login-logout');
+ container.appendChild(login_logout);
+ window.LP = {
+ cache: {}
+ };
+ },
+
+ test_beta_banner_one_beta_feature: function() {
+ LP.cache.beta_features = [
+ ['', '', '', '', 'A beta feature', 'http://lp.dev/LEP/one']];
+ Y.lp.app.beta_features.display_beta_notification();
+
+ var body = Y.one('body');
+ // The <body> node has the class global-notification-visible,
+ // so that the element has enough padding for the beta banner.
+ Y.Assert.isTrue(body.hasClass('global-notification-visible'));
+
+ var banner = Y.one('.beta-banner');
+ var sub_nodes = banner.get('children');
+
+ // The message about a beta feature consists of the feature
+ // title and a link to a page with more information about
+ // the feature.
+ feature_info = sub_nodes.filter('.beta-feature').item(0);
+ Y.Assert.areEqual(
+ ' A beta feature (read more)', feature_info.get('text'));
+ info_link = feature_info.get('children').item(0);
+ Y.Assert.areEqual('http://lp.dev/LEP/one', info_link.get('href'));
+ },
+
+ test_beta_banner_two_beta_features: function() {
+ LP.cache.beta_features = [
+ ['', '', '', '', 'Beta feature 1', 'http://lp.dev/LEP/one'],
+ ['', '', '', '', 'Beta feature 2', '']];
+ Y.lp.app.beta_features.display_beta_notification();
+
+ var body = Y.one('body');
+ Y.Assert.isTrue(body.hasClass('global-notification-visible'));
+
+ var banner = Y.one('.beta-banner');
+ var sub_nodes = banner.get('children');
+
+ // Notifications about several features can be displayed.
+ feature_info = sub_nodes.filter('.beta-feature').item(0);
+ Y.Assert.areEqual(
+ ' Beta feature 1 (read more)', feature_info.get('text'));
+ info_link = feature_info.get('children').item(0);
+ Y.Assert.areEqual('http://lp.dev/LEP/one', info_link.get('href'));
+
+ // If an entry in LP.cache.beta_features does not provide a
+ // "read more" link, the corrsponding node is not added.
+ feature_info = sub_nodes.filter('.beta-feature').item(1);
+ Y.Assert.areEqual(
+ ' Beta feature 2', feature_info.get('text'));
+ Y.Assert.isNull(feature_info.get('children').item(0));
+ },
+
+ test_beta_banner_no_beta_features_defined: function() {
+ LP.cache.beta_features = [];
+ Y.lp.app.beta_features.display_beta_notification();
+
+ var body = Y.one('body');
+ Y.Assert.isFalse(body.hasClass('global-notification-visible'));
+
+ Y.Assert.isNull(Y.one('.beta-banner'));
+ },
+
+ test_hide_beta_banner: function() {
+ LP.cache.beta_features = [
+ ['', '', '', '', 'A beta feature', 'http://lp.dev/LEP/one']];
+ Y.lp.app.beta_features.display_beta_notification();
+ var body = Y.one('body');
+ var banner = Y.one('.beta-banner');
+ Y.Assert.isFalse(banner.hasClass('hidden'));
+
+ close_link = Y.one('.global-notification-close');
+ close_link.simulate('click');
+ // We must wait until the fade out animation finishes.
+ this.wait(
+ function() {
+ Y.Assert.isTrue(banner.hasClass('hidden'));
+ Y.Assert.isFalse(
+ body.hasClass('global-notification-visible'));
+ },
+ 400);
+ }
+ }));
+
+ Y.lp.testing.Runner.run(suite);
+});
+
=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
--- lib/lp/app/templates/base-layout-macros.pt 2011-10-25 23:41:57 +0000
+++ lib/lp/app/templates/base-layout-macros.pt 2011-11-10 11:33:48 +0000
@@ -107,8 +107,8 @@
<metal:load-lavascript use-macro="context/@@+base-layout-macros/load-javascript" />
<script type="text/javascript">
- LPS.use('base', 'node', 'oop', 'event', 'lp.bugs.bugtask_index',
- 'lp.bugs.subscribers',
+ LPS.use('base', 'node', 'oop', 'event', 'lp.app.beta_features',
+ 'lp.bugs.bugtask_index', 'lp.bugs.subscribers',
'lp.code.branchmergeproposal.diff', 'lp.comments.hide',
function(Y) {
Y.on("domready", function () {
@@ -116,6 +116,7 @@
Y.lp.app.privacy.setup_privacy_notification();
Y.lp.app.privacy.display_privacy_notification();
}
+ Y.lp.app.beta_features.display_beta_notification();
});
});
</script>
@@ -266,11 +267,6 @@
•
<a href="http://blog.launchpad.net/"
>Blog</a>
- <tal:careers_link condition="not: features/baselayout.careers_link.disabled">
- •
- <a href="http://www.canonical.com/about-canonical/careers"
- >Careers</a>
- </tal:careers_link>
•
<a href="http://identi.ca/launchpadstatus"
>System status</a>
=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py 2011-11-08 14:08:46 +0000
+++ lib/lp/bugs/browser/bugtask.py 2011-11-10 11:33:48 +0000
@@ -2445,6 +2445,8 @@
implements(IBugTaskSearchListingMenu)
+ beta_features = ['bugs.dynamic_bug_listings.enabled']
+
# Only include <link> tags for bug feeds when using this view.
feed_types = (
BugTargetLatestBugsFeedLink,
Follow ups