allura
Revision | b6e24976941f65d0d3586a9bbb588d9811de996c (tree) |
---|---|
Time | 2012-03-23 17:34:07 |
Author | Yaroslav Luzin <jardev@gmai...> |
Commiter | Yaroslav Luzin |
Merge branch 'dev' of ssh://git.code.sf.net/p/allura/git
@@ -4,42 +4,53 @@ | ||
4 | 4 | <div class="first-line">{{g.markdown.convert(h.really_unicode(value.message.split('\n')[0]))}}</div> |
5 | 5 | {{g.markdown.convert(h.really_unicode('\n'.join(value.message.split('\n')[1:])))}} |
6 | 6 | </div> |
7 | - <h2 class="commit-details"> | |
8 | - <ul class="commit-links"> | |
9 | - <li><a class="commit-tree-link" href="{{value.url()}}tree/">Tree</a></li> | |
10 | - {% if prev %} | |
11 | - <li class="commit-parents"> | |
12 | - Parent(s): | |
13 | - {% for ci in prev %}<a href="{{ci.url()}}">{{ci.shorthand_id()}}</a>{% endfor %} | |
14 | - </li> | |
15 | - {% endif %} | |
16 | - {% if next %} | |
17 | - <li class="commit-children"> | |
18 | - Child(ren): | |
19 | - {% for ci in next %}<a href="{{ci.url()}}">{{ci.shorthand_id()}}</a>{% endfor %} | |
20 | - </li> | |
21 | - {% endif %} | |
22 | - </ul> | |
7 | + <div class="commit-details"> | |
23 | 8 | |
24 | - Authored by | |
25 | - {% if value.author_url %} | |
26 | - <a href="{{value.author_url}}">{{email_gravatar(value.authored.email, title=h.really_unicode(value.authored.name), size=16)}}</a> | |
27 | - <a href="{{value.author_url}}">{{h.really_unicode(value.authored.name)}}</a> | |
28 | - {% else %} | |
29 | - {{email_gravatar(value.authored.email, title=h.really_unicode(value.authored.name), size=16)}} {{h.really_unicode(value.authored.name)}} | |
30 | - {% endif %} | |
9 | + <div class="commit-authorship"> | |
10 | + <p> | |
11 | + <label>Authored by:</label> | |
12 | + {% if value.author_url %} | |
13 | + <a href="{{value.author_url}}">{{email_gravatar(value.authored.email, title=h.really_unicode(value.authored.name), size=16)}}</a> | |
14 | + <a href="{{value.author_url}}">{{h.really_unicode(value.authored.name)}}</a> | |
15 | + {% else %} | |
16 | + {{email_gravatar(value.authored.email, title=h.really_unicode(value.authored.name), size=16)}} {{h.really_unicode(value.authored.name)}} | |
17 | + {% endif %} | |
31 | 18 | |
32 | - {% if value.authored.date %}{{abbr_date(value.authored.date)}}{% endif %} | |
19 | + {% if value.authored.date %}{{abbr_date(value.authored.date)}}{% endif %} | |
20 | + </p> | |
33 | 21 | |
34 | - {% if value.committed.email != value.authored.email %} | |
35 | - Committed by | |
36 | - {% if value.committer_url %} | |
37 | - <a href="{{value.committer_url}}">{{email_gravatar(value.committed.email, title=h.really_unicode(value.committed.name), size=16)}}</a> | |
38 | - <a href="{{value.committer_url}}">{{h.really_unicode(value.committed.name)}}</a> | |
39 | - {% else %} | |
40 | - {{email_gravatar(value.committed.email, title=h.really_unicode(value.committed.name), size=16)}} {{h.really_unicode(value.committed.name)}} | |
22 | + {% if value.committed.email != value.authored.email %} | |
23 | + <p> | |
24 | + <label>Committed by:</label> | |
25 | + {% if value.committer_url %} | |
26 | + <a href="{{value.committer_url}}">{{email_gravatar(value.committed.email, title=h.really_unicode(value.committed.name), size=16)}}</a> | |
27 | + <a href="{{value.committer_url}}">{{h.really_unicode(value.committed.name)}}</a> | |
28 | + {% else %} | |
29 | + {{email_gravatar(value.committed.email, title=h.really_unicode(value.committed.name), size=16)}} {{h.really_unicode(value.committed.name)}} | |
30 | + {% endif %} | |
31 | + {% if value.committed.date %}{{abbr_date(value.committed.date)}}{% endif %} | |
32 | + </p> | |
41 | 33 | {% endif %} |
42 | - {% if value.committed.date %}{{abbr_date(value.committed.date)}}{% endif %} | |
43 | - {% endif %} | |
44 | - </h2> | |
34 | + </div> | |
35 | + | |
36 | + <div class="commit-links"> | |
37 | + <a class="commit-tree-link" href="{{value.url()}}tree/">Tree</a> | |
38 | + <div class="commit-ancestry"> | |
39 | + {% if prev %} | |
40 | + <p class="commit-parents"> | |
41 | + Parent(s): | |
42 | + {% for ci in prev %}<a href="{{ci.url()}}">{{ci.shorthand_id()}}</a>{% endfor %} | |
43 | + </p> | |
44 | + {% endif %} | |
45 | + {% if next %} | |
46 | + <p class="commit-children"> | |
47 | + Child(ren): | |
48 | + {% for ci in next %}<a href="{{ci.url()}}">{{ci.shorthand_id()}}</a>{% endfor %} | |
49 | + </p> | |
50 | + {% endif %} | |
51 | + </div> | |
52 | + </div> | |
53 | + | |
54 | + <div class="clearfix"></div> | |
55 | + </div> | |
45 | 56 | </div> |
@@ -85,7 +85,7 @@ class Globals(MappedClass): | ||
85 | 85 | @property |
86 | 86 | def not_closed_mongo_query(self): |
87 | 87 | return dict( |
88 | - status={'$in': list(self.set_of_open_status_names)}) | |
88 | + status={'$nin': list(self.set_of_closed_status_names)}) | |
89 | 89 | |
90 | 90 | @property |
91 | 91 | def closed_query(self): |
@@ -16,7 +16,7 @@ | ||
16 | 16 | {{c.subscribe_form.display(value=subscribed, action='subscribe', style='icon')}} |
17 | 17 | {% endif %} |
18 | 18 | {% if allow_edit %} |
19 | - <a href="{{tg.url(c.app.url+'edit/', dict(q=url_q, limit=limit, sort=sort, page=page))}}" title="Bulk Edit"><b data-icon="{{g.icons['pencil'].char}}" class="ico {{g.icons['pencil'].css}}"></b></a> | |
19 | + <a href="{{tg.url(c.app.url+'edit/', dict(q=url_q, limit=limit, sort=url_sort, page=page))}}" title="Bulk Edit"><b data-icon="{{g.icons['pencil'].char}}" class="ico {{g.icons['pencil'].css}}"></b></a> | |
20 | 20 | {% endif %} |
21 | 21 | {% endblock %} |
22 | 22 |
@@ -8,7 +8,7 @@ | ||
8 | 8 | |
9 | 9 | {% block actions %} |
10 | 10 | {% if allow_edit %} |
11 | - <a href="{{tg.url(c.app.url+'edit/', dict(q=q, limit=limit, sort=sort, page=page))}}" title="Bulk Edit"><b data-icon="{{g.icons['pencil'].char}}" class="ico {{g.icons['pencil'].css}}"></b></a> | |
11 | + <a href="{{tg.url(c.app.url+'edit/', dict(q=q, limit=limit, sort=url_sort, page=page))}}" title="Bulk Edit"><b data-icon="{{g.icons['pencil'].char}}" class="ico {{g.icons['pencil'].css}}"></b></a> | |
12 | 12 | {% endif %} |
13 | 13 | {% endblock %} |
14 | 14 |
@@ -3,7 +3,7 @@ | ||
3 | 3 | {% if field.name == '_milestone' %} |
4 | 4 | <div class="grid-6">{{milestones}} |
5 | 5 | <label for="{{field.name}}" class="cr">{{field.label}}:</label> |
6 | - <select name="{{field.name}}" class="wide"> | |
6 | + <select name="{{field.name}}" id="{{field.name}}" class="wide"> | |
7 | 7 | <option value="" selected="selected">no change</option> |
8 | 8 | {% for m in field.milestones %} |
9 | 9 | {% if not m.complete %} |
@@ -16,7 +16,7 @@ | ||
16 | 16 | {% endfor %} |
17 | 17 | <div class="grid-6"> |
18 | 18 | <label for="status" class="cr">Status:</label> |
19 | - <select name="status" class="wide"> | |
19 | + <select name="status" id="status" class="wide"> | |
20 | 20 | <option value="" selected="selected">no change</option> |
21 | 21 | {% for option in globals.all_status_names.split() %} |
22 | 22 | <option value="{{option}}">{{option}}</option> |
@@ -25,7 +25,7 @@ | ||
25 | 25 | </div> |
26 | 26 | <div class="grid-6"> |
27 | 27 | <label for="assigned_to" class="cr">Owner:</label> |
28 | - {{c.user_select.display(name='assigned_to', value='', className='wide')}} | |
28 | + {{c.user_select.display(name='assigned_to', id='assigned_to', value='', className='wide')}} | |
29 | 29 | </div> |
30 | 30 | {% set cf_count = 0 %} |
31 | 31 | {% for field in globals.custom_fields %} |
@@ -36,7 +36,7 @@ | ||
36 | 36 | <div class="grid-6"> |
37 | 37 | <label for="{{field.id}}" class="cr">{{field.label}}:</label> |
38 | 38 | {% if field.type == 'boolean' %} |
39 | - <input name="{{field.name}}" type="checkbox" value="True"/> | |
39 | + <input name="{{field.name}}" id="{{field.name}}" type="checkbox" value="True"/> | |
40 | 40 | {% elif field.type == 'select' %} |
41 | 41 | <select name="{{field.name}}" class="wide"> |
42 | 42 | <option value="" selected="selected">no change</option> |
@@ -4,7 +4,7 @@ import Image, StringIO | ||
4 | 4 | import allura |
5 | 5 | |
6 | 6 | from mock import patch |
7 | -from nose.tools import assert_true, assert_false, assert_equal | |
7 | +from nose.tools import assert_true, assert_false, assert_equal, assert_in | |
8 | 8 | from formencode.variabledecode import variable_encode |
9 | 9 | |
10 | 10 | from alluratest.controller import TestController |
@@ -692,6 +692,67 @@ class TestFunctionalController(TrackerTestController): | ||
692 | 692 | r = self.app.get('/bugs/1/', dict(page=1, limit=2)) |
693 | 693 | assert_true('Page 2 of 2' in r) |
694 | 694 | |
695 | + def test_bulk_edit_index(self): | |
696 | + self.new_ticket(summary='test first ticket', status='open') | |
697 | + self.new_ticket(summary='test second ticket', status='accepted') | |
698 | + self.new_ticket(summary='test third ticket', status='closed') | |
699 | + ThreadLocalORMSession.flush_all() | |
700 | + M.MonQTask.run_ready() | |
701 | + ThreadLocalORMSession.flush_all() | |
702 | + response = self.app.get('/p/test/bugs/?sort=summary+asc') | |
703 | + ticket_rows = response.html.find('table', {'class':'ticket-list'}).find('tbody') | |
704 | + assert_in('test first ticket', str(ticket_rows)) | |
705 | + assert_in('test second ticket', str(ticket_rows)) | |
706 | + edit_link = response.html.find('a',{'title':'Bulk Edit'}) | |
707 | + expected_link = "/p/test/bugs/edit/?q=%21status%3Awont-fix+%26%26+%21status%3Aclosed&sort=snippet_s+asc&limit=25&page=0" | |
708 | + assert_equal(expected_link, edit_link['href']) | |
709 | + response = self.app.get(edit_link['href']) | |
710 | + ticket_rows = response.html.find('tbody', {'class':'ticket-list'}) | |
711 | + assert_in('test first ticket', str(ticket_rows)) | |
712 | + assert_in('test second ticket', str(ticket_rows)) | |
713 | + | |
714 | + def test_bulk_edit_milestone(self): | |
715 | + self.new_ticket(summary='test first ticket', status='open', _milestone='1.0') | |
716 | + self.new_ticket(summary='test second ticket', status='accepted', _milestone='1.0') | |
717 | + self.new_ticket(summary='test third ticket', status='closed', _milestone='1.0') | |
718 | + ThreadLocalORMSession.flush_all() | |
719 | + M.MonQTask.run_ready() | |
720 | + ThreadLocalORMSession.flush_all() | |
721 | + response = self.app.get('/p/test/bugs/milestone/1.0/?sort=ticket_num+asc') | |
722 | + ticket_rows = response.html.find('table', {'class':'ticket-list'}).find('tbody') | |
723 | + assert_in('test first ticket', str(ticket_rows)) | |
724 | + assert_in('test second ticket', str(ticket_rows)) | |
725 | + assert_in('test third ticket', str(ticket_rows)) | |
726 | + edit_link = response.html.find('a',{'title':'Bulk Edit'}) | |
727 | + expected_link = "/p/test/bugs/edit/?q=_milestone%3A1.0&sort=ticket_num_i+asc&limit=25&page=0" | |
728 | + assert_equal(expected_link, edit_link['href']) | |
729 | + response = self.app.get(edit_link['href']) | |
730 | + ticket_rows = response.html.find('tbody', {'class':'ticket-list'}) | |
731 | + assert_in('test first ticket', str(ticket_rows)) | |
732 | + assert_in('test second ticket', str(ticket_rows)) | |
733 | + assert_in('test third ticket', str(ticket_rows)) | |
734 | + | |
735 | + def test_bulk_edit_search(self): | |
736 | + self.new_ticket(summary='test first ticket', status='open') | |
737 | + self.new_ticket(summary='test second ticket', status='open') | |
738 | + self.new_ticket(summary='test third ticket', status='closed', _milestone='1.0') | |
739 | + ThreadLocalORMSession.flush_all() | |
740 | + M.MonQTask.run_ready() | |
741 | + ThreadLocalORMSession.flush_all() | |
742 | + response = self.app.get('/p/test/bugs/search/?q=status%3Aopen') | |
743 | + ticket_rows = response.html.find('table', {'class':'ticket-list'}).find('tbody') | |
744 | + assert_in('test first ticket', str(ticket_rows)) | |
745 | + assert_in('test second ticket', str(ticket_rows)) | |
746 | + assert_false('test third ticket' in str(ticket_rows)) | |
747 | + edit_link = response.html.find('a',{'title':'Bulk Edit'}) | |
748 | + expected_link = "/p/test/bugs/edit/?q=status%3Aopen&limit=25&page=0" | |
749 | + assert_equal(expected_link, edit_link['href']) | |
750 | + response = self.app.get(edit_link['href']) | |
751 | + ticket_rows = response.html.find('tbody', {'class':'ticket-list'}) | |
752 | + assert_in('test first ticket', str(ticket_rows)) | |
753 | + assert_in('test second ticket', str(ticket_rows)) | |
754 | + assert_false('test third ticket' in str(ticket_rows)) | |
755 | + | |
695 | 756 | class TestMilestoneAdmin(TrackerTestController): |
696 | 757 | def _post(self, params, **kw): |
697 | 758 | params['open_status_names'] = 'aa bb' |
@@ -57,6 +57,22 @@ search_validators = dict( | ||
57 | 57 | page=validators.Int(if_empty=0), |
58 | 58 | sort=validators.UnicodeString(if_empty=None)) |
59 | 59 | |
60 | +def _mongo_col_to_solr_col(name): | |
61 | + if name == 'ticket_num': | |
62 | + return 'ticket_num_i' | |
63 | + elif name == 'summary': | |
64 | + return 'snippet_s' | |
65 | + elif name == '_milestone': | |
66 | + return 'milestone_s' | |
67 | + elif name == 'status': | |
68 | + return 'status_s' | |
69 | + elif name == 'assigned_to': | |
70 | + return 'assigned_to_s' | |
71 | + else: | |
72 | + for field in c.app.globals.sortable_custom_fields_shown_in_search(): | |
73 | + if name == field['name']: | |
74 | + return field['sortable_name'] | |
75 | + | |
60 | 76 | class W: |
61 | 77 | thread=w.Thread( |
62 | 78 | page=None, limit=None, page_size=None, count=None, |
@@ -382,7 +398,7 @@ class RootController(BaseController): | ||
382 | 398 | @with_trailing_slash |
383 | 399 | @h.vardec |
384 | 400 | @expose('jinja:forgetracker:templates/tracker/index.html') |
385 | - def index(self, limit=25, columns=None, page=0, sort='ticket_num_i asc', **kw): | |
401 | + def index(self, limit=25, columns=None, page=0, sort='ticket_num desc', **kw): | |
386 | 402 | kw.pop('q', None) # it's just our original query mangled and sent back to us |
387 | 403 | result = TM.Ticket.paged_query(c.app.globals.not_closed_mongo_query, |
388 | 404 | sort=sort, limit=int(limit), |
@@ -392,6 +408,11 @@ class RootController(BaseController): | ||
392 | 408 | result['allow_edit'] = has_access(c.app, 'write')() |
393 | 409 | result['help_msg'] = c.app.config.options.get('TicketHelpSearch') |
394 | 410 | result['url_q'] = c.app.globals.not_closed_query |
411 | + result['url_sort'] = '' | |
412 | + if sort: | |
413 | + sort_split = sort.split(' ') | |
414 | + solr_col = _mongo_col_to_solr_col(sort_split[0]) | |
415 | + result['url_sort'] = '%s %s' % (solr_col, sort_split[1]) | |
395 | 416 | c.ticket_search_results = W.ticket_search_results |
396 | 417 | return result |
397 | 418 |
@@ -1413,7 +1434,13 @@ class MilestoneController(BaseController): | ||
1413 | 1434 | field=self.field, |
1414 | 1435 | milestone=self.milestone, |
1415 | 1436 | total=progress['hits'], |
1416 | - closed=progress['closed']) | |
1437 | + closed=progress['closed'], | |
1438 | + q=self.progress_key) | |
1439 | + result['url_sort'] = '' | |
1440 | + if sort: | |
1441 | + sort_split = sort.split(' ') | |
1442 | + solr_col = _mongo_col_to_solr_col(sort_split[0]) | |
1443 | + result['url_sort'] = '%s %s' % (solr_col, sort_split[1]) | |
1417 | 1444 | c.ticket_search_results = W.ticket_search_results |
1418 | 1445 | c.auto_resize_textarea = W.auto_resize_textarea |
1419 | 1446 | return result |