Merge lp:~adeuring/launchpad/bug-903359 into lp:launchpad

Proposed by Abel Deuring
Status: Merged
Approved by: Abel Deuring
Approved revision: no longer in the source branch.
Merged at revision: 14549
Proposed branch: lp:~adeuring/launchpad/bug-903359
Merge into: lp:launchpad
Diff against target: 309 lines (+112/-65)
5 files modified
lib/lp/app/javascript/ordering/ordering.js (+33/-28)
lib/lp/app/javascript/ordering/tests/test_orderby_widget.js (+43/-15)
lib/lp/bugs/browser/bugtask.py (+21/-21)
lib/lp/bugs/browser/tests/test_bugtask.py (+15/-0)
lib/lp/bugs/javascript/buglisting_utils.js (+0/-1)
To merge this branch: bzr merge lp:~adeuring/launchpad/bug-903359
Reviewer Review Type Date Requested Status
Deryck Hodge (community) Approve
Review via email: mp+86244@code.launchpad.net

Commit message

[r=deryck][bug=903359] configure ascending or descending default sort order for each OrderByBar sort option separately.

Description of the change

fault sort direction for each of the
sort options of a OrderByBar separately (bug 903359).

The implementation is simple: The constructor of the sort widget
has the parameter sort_keys, which was a sequences uf tuples
(name, title); I extended this to the tuple (name, title, direction).

The new field "direction" must have either the value "asc" or the value
"desc". (I considered to use a bool flag instead, but this would have
required more changes to the current implementation of OrderByBar,
which already uses these string -- and I wanted to finish this branch
today...)

I added the method OrderByWidget._setSortOrder() to remove duplicated
code in OrderByWidget.updateSortArrows() and OrderByWidget.updateSortArrows().

And I updated the constant SORT_KEYS in lp.bugs.browser.bugtask, which
the sort buttons to include the sort order.

Some choices of "asc" or "desc" in SORT_KEYS are candidates for
bikeshedding, especially: Should the default status sor direction
really be "asc", i.e. should the status "new" come first?

I don't want to discuss this here -- changing the default order for
each sort option requires only a one line change...

tests:

./bin/test app -vvt test_orderby_widget
./bin/test bugs -vvt lp.bugs.browser.tests.test_bugtask

no lint

To post a comment you must log in.
Revision history for this message
Deryck Hodge (deryck) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/app/javascript/ordering/ordering.js'
--- lib/lp/app/javascript/ordering/ordering.js 2011-12-16 03:40:04 +0000
+++ lib/lp/app/javascript/ordering/ordering.js 2011-12-19 14:16:28 +0000
@@ -38,15 +38,15 @@
38 */38 */
39 sort_keys: {39 sort_keys: {
40 value: [40 value: [
41 ['bugnumber', 'Bug number'],41 ['bugnumber', 'Bug number', 'asc'],
42 ['bugtitle', 'Bug title'],42 ['bugtitle', 'Bug title', 'asc'],
43 ['status', 'Status'],43 ['status', 'Status', 'asc'],
44 ['importance', 'Importance'],44 ['importance', 'Importance', 'desc'],
45 ['bug-heat-icons', 'Bug heat'],45 ['bug-heat-icons', 'Bug heat', 'desc'],
46 ['package', 'Package name'],46 ['package', 'Package name', 'asc'],
47 ['milestone', 'Milestone'],47 ['milestone', 'Milestone', 'asc'],
48 ['assignee', 'Assignee'],48 ['assignee', 'Assignee', 'asc'],
49 ['bug-age', 'Bug age']49 ['bug-age', 'Bug age', 'desc']
50 ]50 ]
51 },51 },
5252
@@ -209,6 +209,20 @@
209 }209 }
210 },210 },
211211
212 _setSortOrder: function(value, arrow_span) {
213 if (value === 'asc') {
214 arrow_span.setContent(this.constructor.ASCENDING_ARROW);
215 arrow_span.addClass('asc');
216 arrow_span.removeClass('desc');
217 this.set('sort_order', 'asc');
218 } else {
219 arrow_span.setContent(this.constructor.DESCENDING_ARROW);
220 arrow_span.addClass('desc');
221 arrow_span.removeClass('asc');
222 this.set('sort_order', 'desc');
223 }
224 },
225
212 /**226 /**
213 * Method used to update the arrows used in the display.227 * Method used to update the arrows used in the display.
214 * This will also update the widget's attributes to match228 * This will also update the widget's attributes to match
@@ -229,15 +243,9 @@
229 // Handle the case where the button clicked is the current243 // Handle the case where the button clicked is the current
230 // active sort order. We change sort directions for it.244 // active sort order. We change sort directions for it.
231 if (arrow_span.hasClass('desc')) {245 if (arrow_span.hasClass('desc')) {
232 arrow_span.setContent(this.constructor.ASCENDING_ARROW);246 this._setSortOrder('asc', arrow_span);
233 arrow_span.addClass('asc');
234 arrow_span.removeClass('desc');
235 this.set('sort_order', 'asc');
236 } else {247 } else {
237 arrow_span.setContent(this.constructor.DESCENDING_ARROW);248 this._setSortOrder('desc', arrow_span);
238 arrow_span.addClass('desc');
239 arrow_span.removeClass('asc');
240 this.set('sort_order', 'desc');
241 }249 }
242 } else {250 } else {
243 // We have a different sort order clicked and need to251 // We have a different sort order clicked and need to
@@ -251,9 +259,13 @@
251 var pre_click_sort_order = this.get('sort_order');259 var pre_click_sort_order = this.get('sort_order');
252 old_arrow_span.removeClass(pre_click_sort_order);260 old_arrow_span.removeClass(pre_click_sort_order);
253 // Update current li span arrow and set new sort order.261 // Update current li span arrow and set new sort order.
254 arrow_span.addClass('asc');262 var sort_order;
255 this.set('sort_order', 'asc');263 Y.each(this.get('sort_keys'), function(key_data) {
256 arrow_span.setContent(this.constructor.ASCENDING_ARROW);264 if (key_data[0] === clicked_node_sort_key) {
265 sort_order = key_data[2];
266 }
267 });
268 this._setSortOrder(sort_order, arrow_span);
257 }269 }
258 },270 },
259271
@@ -335,15 +347,8 @@
335 li_node = Y.Node.create(li_html);347 li_node = Y.Node.create(li_html);
336 if (this.get('active') === id) {348 if (this.get('active') === id) {
337 li_node.addClass('active-sort');349 li_node.addClass('active-sort');
338 li_node.one('span').addClass(this.get('sort_order'));
339 sort_order = this.get('sort_order');350 sort_order = this.get('sort_order');
340 if (sort_order === 'asc') {351 this._setSortOrder(sort_order, li_node.one('span'));
341 li_node.one('span').setContent(
342 this.constructor.ASCENDING_ARROW);
343 } else if (sort_order === 'desc') {
344 li_node.one('span').setContent(
345 this.constructor.DESCENDING_ARROW);
346 }
347 }352 }
348 orderby_ul.appendChild(li_node);353 orderby_ul.appendChild(li_node);
349 li_nodes.push(li_node);354 li_nodes.push(li_node);
350355
=== modified file 'lib/lp/app/javascript/ordering/tests/test_orderby_widget.js'
--- lib/lp/app/javascript/ordering/tests/test_orderby_widget.js 2011-12-08 13:23:00 +0000
+++ lib/lp/app/javascript/ordering/tests/test_orderby_widget.js 2011-12-19 14:16:28 +0000
@@ -83,9 +83,9 @@
83 test_user_supplied_sort_keys: function() {83 test_user_supplied_sort_keys: function() {
84 // Call sites can supply their own sort keys to a widget.84 // Call sites can supply their own sort keys to a widget.
85 var user_supplied_sort_keys = [85 var user_supplied_sort_keys = [
86 ['foo', 'Foo item'],86 ['foo', 'Foo item', 'asc'],
87 ['bar', 'Bar item'],87 ['bar', 'Bar item', 'asc'],
88 ['baz', 'Baz item']88 ['baz', 'Baz item', 'asc']
89 ];89 ];
90 this.orderby = new Y.lp.ordering.OrderByBar({90 this.orderby = new Y.lp.ordering.OrderByBar({
91 sort_keys: user_supplied_sort_keys});91 sort_keys: user_supplied_sort_keys});
@@ -100,8 +100,8 @@
100 // created from sort keys, and the name should be used as100 // created from sort keys, and the name should be used as
101 // a button display name in HTML.101 // a button display name in HTML.
102 var test_sort_keys = [102 var test_sort_keys = [
103 ['foo', 'Foo item'],103 ['foo', 'Foo item', 'asc'],
104 ['bar', 'Bar item']104 ['bar', 'Bar item', 'asc']
105 ];105 ];
106 this.makeSrcNode('test-div');106 this.makeSrcNode('test-div');
107 this.orderby = new Y.lp.ordering.OrderByBar({107 this.orderby = new Y.lp.ordering.OrderByBar({
@@ -187,8 +187,8 @@
187 // This should fail because we do not allow187 // This should fail because we do not allow
188 // a "active" value not found in sort_keys.188 // a "active" value not found in sort_keys.
189 var test_sort_keys = [189 var test_sort_keys = [
190 ['foo', 'Foo item'],190 ['foo', 'Foo item', 'asc'],
191 ['bar', 'Bar item']191 ['bar', 'Bar item', 'asc']
192 ];192 ];
193 this.orderby = new Y.lp.ordering.OrderByBar({193 this.orderby = new Y.lp.ordering.OrderByBar({
194 sort_keys: test_sort_keys,194 sort_keys: test_sort_keys,
@@ -212,8 +212,8 @@
212 // happen.212 // happen.
213 this.makeSrcNode('test-div');213 this.makeSrcNode('test-div');
214 var test_sort_keys = [214 var test_sort_keys = [
215 ['foo', 'Foo item'],215 ['foo', 'Foo item', 'asc'],
216 ['bar', 'Bar item']216 ['bar', 'Bar item', 'asc']
217 ];217 ];
218 this.orderby = new Y.lp.ordering.OrderByBar({218 this.orderby = new Y.lp.ordering.OrderByBar({
219 srcNode: Y.one('#test-div'),219 srcNode: Y.one('#test-div'),
@@ -223,8 +223,10 @@
223 });223 });
224 this.orderby.render();224 this.orderby.render();
225 var foo_node = Y.one('#sort-foo');225 var foo_node = Y.one('#sort-foo');
226 var expected_starting_text = '<span class="sprite order-ascending"></span>';226 var expected_starting_text =
227 var expected_ending_text = '<span class="sprite order-descending"></span>';227 '<span class="sprite order-ascending"></span>';
228 var expected_ending_text =
229 '<span class="sprite order-descending"></span>';
228 Assert.areEqual(230 Assert.areEqual(
229 expected_starting_text, foo_node.one('span').get('innerHTML'));231 expected_starting_text, foo_node.one('span').get('innerHTML'));
230 Assert.isTrue(foo_node.one('span').hasClass('asc'));232 Assert.isTrue(foo_node.one('span').hasClass('asc'));
@@ -240,8 +242,8 @@
240 // change should happen.242 // change should happen.
241 this.makeSrcNode('test-div');243 this.makeSrcNode('test-div');
242 var test_sort_keys = [244 var test_sort_keys = [
243 ['foo', 'Foo item'],245 ['foo', 'Foo item', 'asc'],
244 ['bar', 'Bar item']246 ['bar', 'Bar item', 'asc']
245 ];247 ];
246 this.orderby = new Y.lp.ordering.OrderByBar({248 this.orderby = new Y.lp.ordering.OrderByBar({
247 srcNode: Y.one('#test-div'),249 srcNode: Y.one('#test-div'),
@@ -261,6 +263,32 @@
261 Assert.isFalse(Y.one('#sort-foo').one('span').hasClass('desc'));263 Assert.isFalse(Y.one('#sort-foo').one('span').hasClass('desc'));
262 },264 },
263265
266 test_click_different_sort_arrows_change_default_order: function() {
267 // A newly active sort button has the order as specified by
268 // the constructor parameter sort_keys.
269 this.makeSrcNode('test-div');
270 var test_sort_keys = [
271 ['foo', 'Foo item', 'asc'],
272 ['bar', 'Bar item', 'desc'],
273 ['baz', 'Baz item', 'asc']
274 ];
275 this.orderby = new Y.lp.ordering.OrderByBar({
276 srcNode: Y.one('#test-div'),
277 sort_keys: test_sort_keys,
278 active: 'foo',
279 sort_order: 'asc'
280 });
281 this.orderby.render();
282 var bar_node = Y.one('#sort-bar');
283 bar_node.simulate('click');
284 Assert.isTrue(bar_node.one('span').hasClass('desc'));
285 Assert.areEqual('desc', this.orderby.get('sort_order'));
286 var baz_node = Y.one('#sort-baz');
287 baz_node.simulate('click');
288 Assert.isTrue(baz_node.one('span').hasClass('asc'));
289 Assert.areEqual('asc', this.orderby.get('sort_order'));
290 },
291
264 test_sort_clause_default: function() {292 test_sort_clause_default: function() {
265 // sort_clause defaults to "importance".293 // sort_clause defaults to "importance".
266 this.orderby = new Y.lp.ordering.OrderByBar();294 this.orderby = new Y.lp.ordering.OrderByBar();
@@ -275,8 +303,8 @@
275 // a URL.303 // a URL.
276 this.makeSrcNode('test-div');304 this.makeSrcNode('test-div');
277 var test_sort_keys = [305 var test_sort_keys = [
278 ['foo', 'Foo item'],306 ['foo', 'Foo item', 'asc'],
279 ['bar', 'Bar item']307 ['bar', 'Bar item', 'asc']
280 ];308 ];
281 this.orderby = new Y.lp.ordering.OrderByBar({309 this.orderby = new Y.lp.ordering.OrderByBar({
282 srcNode: Y.one('#test-div'),310 srcNode: Y.one('#test-div'),
283311
=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py 2011-12-18 03:35:49 +0000
+++ lib/lp/bugs/browser/bugtask.py 2011-12-19 14:16:28 +0000
@@ -2494,27 +2494,27 @@
2494# All sort orders supported by BugTaskSet.search() and a title for2494# All sort orders supported by BugTaskSet.search() and a title for
2495# them.2495# them.
2496SORT_KEYS = [2496SORT_KEYS = [
2497 ('importance', 'Importance'),2497 ('importance', 'Importance', 'desc'),
2498 ('status', 'Status'),2498 ('status', 'Status', 'asc'),
2499 ('id', 'Bug number'),2499 ('id', 'Bug number', 'desc'),
2500 ('title', 'Bug title'),2500 ('title', 'Bug title', 'asc'),
2501 ('targetname', 'Package/Project/Series name'),2501 ('targetname', 'Package/Project/Series name', 'asc'),
2502 ('milestone_name', 'Milestone'),2502 ('milestone_name', 'Milestone', 'asc'),
2503 ('date_last_updated', 'Date bug last updated'),2503 ('date_last_updated', 'Date bug last updated', 'desc'),
2504 ('assignee', 'Assignee'),2504 ('assignee', 'Assignee', 'asc'),
2505 ('reporter', 'Reporter'),2505 ('reporter', 'Reporter', 'asc'),
2506 ('datecreated', 'Bug age'),2506 ('datecreated', 'Bug age', 'desc'),
2507 ('tag', 'Bug Tags'),2507 ('tag', 'Bug Tags', 'asc'),
2508 ('heat', 'Bug heat'),2508 ('heat', 'Bug heat', 'desc'),
2509 ('date_closed', 'Date bug closed'),2509 ('date_closed', 'Date bug closed', 'desc'),
2510 ('dateassigned', 'Date when the bug task was assigned'),2510 ('dateassigned', 'Date when the bug task was assigned', 'desc'),
2511 ('number_of_duplicates', 'Number of duplicates'),2511 ('number_of_duplicates', 'Number of duplicates', 'desc'),
2512 ('latest_patch_uploaded', 'Date latest patch uploaded'),2512 ('latest_patch_uploaded', 'Date latest patch uploaded', 'desc'),
2513 ('message_count', 'Number of comments'),2513 ('message_count', 'Number of comments', 'desc'),
2514 ('milestone', 'Milestone ID'),2514 ('milestone', 'Milestone ID', 'desc'),
2515 ('specification', 'Linked blueprint'),2515 ('specification', 'Linked blueprint', 'asc'),
2516 ('task', 'Bug task ID'),2516 ('task', 'Bug task ID', 'desc'),
2517 ('users_affected_count', 'Number of affected users'),2517 ('users_affected_count', 'Number of affected users', 'desc'),
2518 ]2518 ]
25192519
25202520
25212521
=== modified file 'lib/lp/bugs/browser/tests/test_bugtask.py'
--- lib/lp/bugs/browser/tests/test_bugtask.py 2011-12-15 18:55:46 +0000
+++ lib/lp/bugs/browser/tests/test_bugtask.py 2011-12-19 14:16:28 +0000
@@ -2263,6 +2263,21 @@
2263 "keys present in JSON cache but not defined: %r"2263 "keys present in JSON cache but not defined: %r"
2264 % (valid_keys - json_sort_keys, json_sort_keys - valid_keys))2264 % (valid_keys - json_sort_keys, json_sort_keys - valid_keys))
22652265
2266 def test_sort_keys_in_json_cache_data(self):
2267 # The entry 'sort_keys' in the JSON cache of a search listing
2268 # view is a sequence of 3-tuples (name, title, order), where
2269 # order is one of the string 'asc' or 'desc'.
2270 with dynamic_listings():
2271 view = self.makeView()
2272 cache = IJSONRequestCache(view.request)
2273 json_sort_keys = cache.objects['sort_keys']
2274 for key in json_sort_keys:
2275 self.assertEqual(
2276 3, len(key), 'Invalid key length: %r' % (key, ))
2277 self.assertTrue(
2278 key[2] in ('asc', 'desc'),
2279 'Invalid order value: %r' % (key, ))
2280
22662281
2267class TestBugTaskExpirableListingView(BrowserTestCase):2282class TestBugTaskExpirableListingView(BrowserTestCase):
2268 """Test BugTaskExpirableListingView."""2283 """Test BugTaskExpirableListingView."""
22692284
=== modified file 'lib/lp/bugs/javascript/buglisting_utils.js'
--- lib/lp/bugs/javascript/buglisting_utils.js 2011-12-15 15:11:50 +0000
+++ lib/lp/bugs/javascript/buglisting_utils.js 2011-12-19 14:16:28 +0000
@@ -344,7 +344,6 @@
344 Y.each(orderbybar.always_display, function(sort_key) {344 Y.each(orderbybar.always_display, function(sort_key) {
345 orderby_visibility[sort_key] = true;345 orderby_visibility[sort_key] = true;
346 });346 });
347 Y.log(data_visibility);
348 orderbybar.updateVisibility(orderby_visibility);347 orderbybar.updateVisibility(orderby_visibility);
349 }348 }
350349