Merge lp:~huwshimi/launchpad/private-objects-298152 into lp:launchpad

Proposed by Huw Wilkins
Status: Merged
Approved by: Huw Wilkins
Approved revision: no longer in the source branch.
Merged at revision: 12697
Proposed branch: lp:~huwshimi/launchpad/private-objects-298152
Merge into: lp:launchpad
Diff against target: 407 lines (+257/-3)
7 files modified
lib/canonical/launchpad/icing/icon-sprites.positioning (+8/-0)
lib/canonical/launchpad/icing/sprite.css.in (+8/-0)
lib/canonical/launchpad/icing/style-3-0.css (+81/-3)
lib/lp/bugs/browser/bugtask.py (+7/-0)
lib/lp/bugs/javascript/bugtask_index.js (+119/-0)
lib/lp/bugs/templates/bugtask-index.pt (+30/-0)
lib/lp/services/features/flags.py (+4/-0)
To merge this branch: bzr merge lp:~huwshimi/launchpad/private-objects-298152
Reviewer Review Type Date Requested Status
Graham Binns (community) code Approve
Review via email: mp+53195@code.launchpad.net

Commit message

[r=gmb][bug=298152] Changed private bug notifications to be more obvious. This is only available under a feature flag.

Description of the change

The current style for notifying private bugs is not obvious enough. After some discussion I created a new style that overlays a banner at the top of the page that scrolls with it.

The banner can be closed, and when closed the privacy portlet should fade to red.

To test the notification you'll need a bug that has been marked private and you'll need to set the flag with 'bugs.private_notification.enabled default 1 on' on https://launchpad.dev/+feature-rules

Here is a screenshot of this change: http://launchpadlibrarian.net/66331334/privacy_red.png

To post a comment you must log in.
Revision history for this message
Martin Pool (mbp) wrote :

I don't want to bikeshed so make of these what you will:

1- stackoverflow etc show the ribbon above (y-axis) the page content,
rather than overlaid on it (z-axis), so it does not obscure any
content.

2- The current hashmarks have the advantage that you can still see the
bug is private when you have scrolled down the page, and it's very
common for bugs to be more than one screen long.

Martin

Revision history for this message
Huw Wilkins (huwshimi) wrote :

> 1- stackoverflow etc show the ribbon above (y-axis) the page content,
> rather than overlaid on it (z-axis), so it does not obscure any
> content.

That screenshot was probably not the best. This banner works exactly like the banner on Stackoverflow. That screenshot shows the page scrolled down a bit but it does push the content down when you're at the top of the page.

>
> 2- The current hashmarks have the advantage that you can still see the
> bug is private when you have scrolled down the page, and it's very
> common for bugs to be more than one screen long.

Again, like Stackoverflow the banner stays at the top of the visible area.

Revision history for this message
Martin Pool (mbp) wrote :

Thanks for clarifying.

There is a bit of a difference which is that the stackoverflow
notifications are point-in-time and once they are dismissed the user
will never see that particular notification again. Privacy on the
other hand is a persistent attribute of the bug state and will for
some users occur on nearly every bug they look at. In that case
needing to dismiss it for every window, or having it always overlay
the window contents might get tedious.

(But perhaps the users who complained privacy was insufficiently
prominent will be happy to have it just always hanging around.)

Revision history for this message
Graham Binns (gmb) wrote :

Hi Huw,

Thanks for this change. My only request is that we move the JS you've added to bugtask-index.pt into lib/lp/bugs/javascript/bugtask_index.js so that we can keep the JS neat(ish) and in one place.

Otherwise this is r=me.

review: Approve (code)
Revision history for this message
Huw Wilkins (huwshimi) wrote :

> Thanks for this change. My only request is that we move the JS you've added to
> bugtask-index.pt into lib/lp/bugs/javascript/bugtask_index.js so that we can
> keep the JS neat(ish) and in one place.

Thanks, that's been done.

I also found a bug when changing the bug between private to public where it would not show/hide the banner. This has been fixed, but required some big changes to the code.

Revision history for this message
Graham Binns (gmb) wrote :

Hi Huw,

I've taken a look at your changes and they look fine. r=me.

review: Approve (code)
Revision history for this message
Brad Crittenden (bac) wrote :

Huw this branch deleted the file icon-sprites which seems to have been a mistake. I am in the process of restoring the file and landing it. If you meant for that file to really go away please provide an explanation. Thanks.

Revision history for this message
Brad Crittenden (bac) wrote :

Huw, never mind. I see that the file is generated and therefore should not be in our tree. Unfortunately we didn't have rules in our makefile to generate it automatically. I've just landed a fix to do just that.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'lib/canonical/launchpad/icing/icon-sprites'
2Binary files lib/canonical/launchpad/icing/icon-sprites 2011-02-16 04:32:34 +0000 and lib/canonical/launchpad/icing/icon-sprites 1970-01-01 00:00:00 +0000 differ
3=== modified file 'lib/canonical/launchpad/icing/icon-sprites.positioning'
4--- lib/canonical/launchpad/icing/icon-sprites.positioning 2011-02-16 04:32:34 +0000
5+++ lib/canonical/launchpad/icing/icon-sprites.positioning 2011-03-23 01:08:27 +0000
6@@ -441,6 +441,10 @@
7 0,
8 -4096
9 ],
10+ "../images/notification-close.png": [
11+ 0,
12+ -20725
13+ ],
14 "../images/merge-proposal-large.png": [
15 0,
16 -17868
17@@ -453,6 +457,10 @@
18 0,
19 -1968
20 ],
21+ "../images/notification-private.png": [
22+ 0,
23+ -20554
24+ ],
25 "../images/bug.png": [
26 0,
27 -4260
28
29=== modified file 'lib/canonical/launchpad/icing/sprite.css.in'
30--- lib/canonical/launchpad/icing/sprite.css.in 2011-03-18 22:47:24 +0000
31+++ lib/canonical/launchpad/icing/sprite.css.in 2011-03-23 01:08:27 +0000
32@@ -492,3 +492,11 @@
33 background-image: url(/@@/trash-logo.png); /* sprite-ref: icon-sprites */
34 background-repeat: no-repeat;
35 }
36+.notification-private {
37+ background-image: url(/@@/notification-private.png); /* sprite-ref: icon-sprites */
38+ background-repeat: no-repeat;
39+ }
40+.notification-close {
41+ background-image: url(/@@/notification-close.png); /* sprite-ref: icon-sprites */
42+ background-repeat: no-repeat;
43+ }
44
45=== modified file 'lib/canonical/launchpad/icing/style-3-0.css'
46--- lib/canonical/launchpad/icing/style-3-0.css 2011-03-21 21:30:07 +0000
47+++ lib/canonical/launchpad/icing/style-3-0.css 2011-03-23 01:08:27 +0000
48@@ -24,6 +24,7 @@
49 * Header, footer, side, help
50 * Colors
51 * Sprites
52+ * Global notifications
53 * Application or page specifc styles that do not belong in this file.
54 */
55
56@@ -132,6 +133,10 @@
57 /* It must be obvious to the user that the context is private */
58 background: url("/@@/private-y-bg") top left repeat-y;
59 }
60+/* Override for when the feature flag is active */
61+body.feature-flag-bugs-private-notification-enabled.private {
62+ background-image: none;
63+ }
64 * html body {
65 /* stops floats dropping in IE 5.5/6 */
66 word-wrap: break-word;
67@@ -1102,7 +1107,7 @@
68 font-size: 12px;
69 text-decoration: underline;
70 }
71-.unseen {
72+.unseen, .hidden {
73 display: none;
74 }
75 .invisible-link {
76@@ -1112,6 +1117,11 @@
77 left:-9999em;
78 display:block;
79 }
80+.transparent {
81+ opacity: 0;
82+ filter: alpha(opacity=0);
83+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
84+}
85 .rss-right {
86 background: url(/@@/rss.png) right center no-repeat;
87 }
88@@ -1314,8 +1324,14 @@
89 background: #fbfbfb;
90 }
91 #privacy.private {
92- background: url(/@@/private-bg) top left repeat-x; /* 8px high */
93- padding-top: 12px; /* = 8px + the usual 4px top padding */
94+ background: url(/@@/private-bg) top left repeat-x; /* 8px high */
95+ padding-top: 12px; /* = 8px + the usual 4px top padding */
96+ }
97+/* Override for when the feature flag is active */
98+.feature-flag-bugs-private-notification-enabled #privacy.private {
99+ background-image: none;
100+ background-color: #FBFBFB;
101+ padding-top: 0.5em;
102 }
103 .downloads li {
104 margin: 0;
105@@ -1876,6 +1892,68 @@
106 padding:2px 0 0 18px;
107 }
108
109+
110+/* ====================
111+ Global notifications
112+*/
113+/* Move the content down so the notification banner doesn't hide any content. */
114+body.global-notification-visible {
115+ padding-top: 40px;
116+ }
117+body.global-notification-visible .login-logout {
118+ top: 45px;
119+ }
120+.global-notification {
121+ position: fixed;
122+ z-index: 10;
123+ top: 0;
124+ left: 0;
125+ right: 0;
126+ padding: 8px 20px;
127+ /* Define colour for browsers that don't support transparency */
128+ background-color: #8d1f1f;
129+ /* Set transparent background for browsers that support it */
130+ background-color: rgba(125,0,0,0.9);
131+ color: #fff;
132+ text-shadow: 0 -1px 0 #631616;
133+ font-size: 14px;
134+ line-height: 21px;
135+ font-weight: bold;
136+ -moz-box-shadow: 0 0 5px #333;
137+ -webkit-box-shadow: 0 0 5px #333;
138+ box-shadow: 0 0 5px #333;
139+ }
140+.global-notification .sprite.notification-private {
141+ float: left;
142+ display: inline-block;
143+ height: 21px;
144+ width: 20px;
145+ margin-right: 10px;
146+ padding: 0;
147+ }
148+.global-notification-close, .global-notification-close:active,
149+.global-notification-close:visited {
150+ color: #e47a7a;
151+ }
152+.global-notification-close {
153+ display: block;
154+ position: absolute;
155+ top: 11px;
156+ right: 20px;
157+ font-size: 12px;
158+ font-weight: normal;
159+ line-height: 14px;
160+ }
161+.global-notification-close .sprite.notification-close {
162+ float: right;
163+ display: block;
164+ height: 9px;
165+ width: 8px;
166+ margin: 3px 0 0 7px;
167+ padding: 0;
168+ }
169+
170+
171 /*
172 * YOU HAVE REACHED THE END OF THIS FILE. IF YOU SEE ANYTHING BELOW SPRITES
173 * YOU SHOULD WORK TO GET IT OUT OF THIS GLOBAL STYLE SHEET.
174
175=== added file 'lib/canonical/launchpad/images/notification-close.png'
176Binary files lib/canonical/launchpad/images/notification-close.png 1970-01-01 00:00:00 +0000 and lib/canonical/launchpad/images/notification-close.png 2011-03-23 01:08:27 +0000 differ
177=== added file 'lib/canonical/launchpad/images/notification-private.png'
178Binary files lib/canonical/launchpad/images/notification-private.png 1970-01-01 00:00:00 +0000 and lib/canonical/launchpad/images/notification-private.png 2011-03-23 01:08:27 +0000 differ
179=== modified file 'lib/lp/bugs/browser/bugtask.py'
180--- lib/lp/bugs/browser/bugtask.py 2011-03-21 21:36:55 +0000
181+++ lib/lp/bugs/browser/bugtask.py 2011-03-23 01:08:27 +0000
182@@ -974,6 +974,13 @@
183 else:
184 return bugtask_heat_html(self.context)
185
186+ @property
187+ def privacy_notice_classes(self):
188+ if not self.context.bug.private:
189+ return 'hidden'
190+ else:
191+ return ''
192+
193
194 def calculate_heat_display(heat, max_bug_heat):
195 """Calculate the number of heat 'flames' to display."""
196
197=== modified file 'lib/lp/bugs/javascript/bugtask_index.js'
198--- lib/lp/bugs/javascript/bugtask_index.js 2011-02-24 00:23:04 +0000
199+++ lib/lp/bugs/javascript/bugtask_index.js 2011-03-23 01:08:27 +0000
200@@ -43,6 +43,15 @@
201 Y.lp.bugs.bugtask_index.portlets.setup_portlet_handlers();
202
203 /*
204+ * Display the privacy notification if the bug is private
205+ */
206+ if (bug_private) {
207+ Y.on("domready", function () {
208+ display_privacy_notification();
209+ });
210+ }
211+
212+ /*
213 * Check the page for links related to overlay forms and request the HTML
214 * for these forms.
215 */
216@@ -372,11 +381,19 @@
217 privacy_text.set(
218 'innerHTML',
219 'This report is <strong>private</strong> ');
220+ display_privacy_notification();
221 } else {
222+ if (bugs_private_notification_enabled) {
223+ if (Y.one('.global-notification').hasClass('hidden')) {
224+ Y.one('.portlet.private').setStyle('color', '#333');
225+ Y.one('.portlet.private').setStyle('background-color', '#fbfbfb');
226+ }
227+ }
228 Y.one('body').replaceClass('private', 'public');
229 privacy_div.replaceClass('private', 'public');
230 privacy_text.set(
231 'innerHTML', 'This report is public ');
232+ hide_privacy_notification();
233 }
234 privacy_text.appendChild(privacy_link);
235 privacy_text.appendChild(privacy_spinner);
236@@ -411,6 +428,108 @@
237 };
238
239
240+/*
241+ * Display privacy notifications
242+ *
243+ * This should be called after the page has loaded e.g. on 'domready'.
244+ */
245+function display_privacy_notification() {
246+ /* Check if the feature flag is set for this notification. */
247+ if (bugs_private_notification_enabled) {
248+ /* Set a temporary class on the body for the feature flag,
249+ this is because we have no way to use feature flags in
250+ css directly. This should be remove if the feature
251+ is accepted. */
252+ Y.one('body').addClass('feature-flag-bugs-private-notification-enabled');
253+ /* Set the visible flag so that the content moves down. */
254+ Y.one('body').addClass('global-notification-visible');
255+
256+ if (Y.one('.global-notification').hasClass('hidden')) {
257+ Y.one('.global-notification').addClass('transparent');
258+ Y.one('.global-notification').removeClass('hidden');
259+ var fade_in = new Y.Anim({
260+ node: '.global-notification',
261+ to: {opacity: 1},
262+ duration: 0.3
263+ });
264+ var body_space = new Y.Anim({
265+ node: 'body',
266+ to: {'padding-top': '40px'},
267+ duration: 0.2,
268+ easing: Y.Easing.easeOut
269+ });
270+ var login_space = new Y.Anim({
271+ node: '.login-logout',
272+ to: {'top': '45px'},
273+ duration: 0.2,
274+ easing: Y.Easing.easeOut
275+ });
276+
277+ fade_in.run();
278+ body_space.run();
279+ login_space.run();
280+ }
281+
282+ Y.on('click', function(e) {
283+ hide_privacy_notification(true);
284+ e.halt();
285+ }, '.global-notification-close');
286+ }
287+}
288+
289+
290+/*
291+ * Hide privacy notifications
292+ *
293+ * This should be called after the page has loaded e.g. on 'domready'.
294+ */
295+function hide_privacy_notification(highlight_portlet) {
296+ if (bugs_private_notification_enabled) {
297+ if (!Y.one('.global-notification').hasClass('hidden')) {
298+ var fade_out = new Y.Anim({
299+ node: '.global-notification',
300+ to: {opacity: 0},
301+ duration: 0.3
302+ });
303+ var body_space = new Y.Anim({
304+ node: 'body',
305+ to: {'padding-top': 0},
306+ duration: 0.2,
307+ easing: Y.Easing.easeOut
308+ });
309+ var login_space = new Y.Anim({
310+ node: '.login-logout',
311+ to: {'top': '6px'},
312+ duration: 0.2,
313+ easing: Y.Easing.easeOut
314+ });
315+ fade_out.on('end', function() {
316+ fade_out.get('node').addClass('hidden');
317+ });
318+ body_space.on('end', function() {
319+ Y.one('body').removeClass('global-notification-visible');
320+ });
321+
322+ fade_out.run();
323+ body_space.run();
324+ login_space.run();
325+
326+ if (highlight_portlet) {
327+ var portlet_colour = new Y.Anim({
328+ node: '.portlet.private',
329+ to: {
330+ color: '#fff',
331+ backgroundColor:'#8d1f1f'
332+ },
333+ duration: 0.4,
334+ });
335+ portlet_colour.run();
336+ }
337+ }
338+ }
339+}
340+
341+
342 /**
343 * Set up the link-a-related-branch picker.
344 */
345
346=== modified file 'lib/lp/bugs/templates/bugtask-index.pt'
347--- lib/lp/bugs/templates/bugtask-index.pt 2011-03-15 01:40:18 +0000
348+++ lib/lp/bugs/templates/bugtask-index.pt 2011-03-23 01:08:27 +0000
349@@ -21,6 +21,26 @@
350 use_advanced_subscriptions = false;
351 </script>
352 </tal:subscriptions-js>
353+ <tal:if condition="context/bug/private">
354+ <script type="text/javascript">
355+ var bug_private = true;
356+ </script>
357+ </tal:if>
358+ <tal:if condition="not:context/bug/private">
359+ <script type="text/javascript">
360+ var bug_private = false;
361+ </script>
362+ </tal:if>
363+ <tal:if condition="request/features/bugs.private_notification.enabled">
364+ <script type="text/javascript">
365+ var bugs_private_notification_enabled = true;
366+ </script>
367+ </tal:if>
368+ <tal:if condition="not:request/features/bugs.private_notification.enabled">
369+ <script type="text/javascript">
370+ var bugs_private_notification_enabled = false;
371+ </script>
372+ </tal:if>
373 <script type="text/javascript">
374 LPS.use('base', 'node', 'oop', 'event', 'lp.bugs.bugtask_index',
375 'lp.bugs.bugtask_index.portlets',
376@@ -69,6 +89,16 @@
377 </metal:heading>
378
379 <div metal:fill-slot="main" tal:define="context_menu context/menu:context">
380+ <tal:if condition="request/features/bugs.private_notification.enabled">
381+ <div tal:attributes="class string: global-notification ${view/privacy_notice_classes}">
382+ <span class="sprite notification-private"></span>
383+ This bug is private
384+ <a href="#" class="global-notification-close">
385+ <span class="sprite notification-close"></span>
386+ Hide
387+ </a>
388+ </div>
389+ </tal:if>
390 <div id="tags-autocomplete">
391 <div id="tags-autocomplete-content"></div>
392 </div>
393
394=== modified file 'lib/lp/services/features/flags.py'
395--- lib/lp/services/features/flags.py 2011-03-11 12:27:31 +0000
396+++ lib/lp/services/features/flags.py 2011-03-23 01:08:27 +0000
397@@ -85,6 +85,10 @@
398 'boolean',
399 'Shows the server-side page render time in the login widget.',
400 ''),
401+ ('bugs.private_notification.enabled',
402+ 'boolean',
403+ 'Changes the appearance of notifications on private bugs.',
404+ ''),
405 ])
406
407 # The set of all flag names that are documented.