Merge lp:~julian-edwards/maas/backport-r1294-1299 into lp:maas/1.2
- backport-r1294-1299
- Merge into 1.2
Proposed by
Julian Edwards
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Julian Edwards | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 1324 | ||||
Proposed branch: | lp:~julian-edwards/maas/backport-r1294-1299 | ||||
Merge into: | lp:maas/1.2 | ||||
Diff against target: |
328 lines (+189/-9) 6 files modified
src/maasserver/static/css/components/table_list.css (+13/-0) src/maasserver/templates/maasserver/node_list.html (+1/-1) src/maasserver/templates/maasserver/nodes_listing.html (+16/-0) src/maasserver/templates/maasserver/tag_view.html (+1/-1) src/maasserver/tests/test_views_nodes.py (+115/-5) src/maasserver/views/nodes.py (+43/-2) |
||||
To merge this branch: | bzr merge lp:~julian-edwards/maas/backport-r1294-1299 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Julian Edwards (community) | Approve | ||
Review via email:
|
Commit message
Fix bug #994887: Nodes list view now supports sorting by hostname(mac) or status columns. (backport r1294 and r1299 from trunk)
Description of the change
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Julian Edwards (julian-edwards) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/maasserver/static/css/components/table_list.css' | |||
2 | --- src/maasserver/static/css/components/table_list.css 2012-04-05 06:23:59 +0000 | |||
3 | +++ src/maasserver/static/css/components/table_list.css 2012-12-03 07:15:29 +0000 | |||
4 | @@ -30,6 +30,19 @@ | |||
5 | 30 | border-color: #dd4814; | 30 | border-color: #dd4814; |
6 | 31 | cursor: pointer; | 31 | cursor: pointer; |
7 | 32 | } | 32 | } |
8 | 33 | .sort-none, | ||
9 | 34 | .sort-asc, | ||
10 | 35 | .sort-desc { | ||
11 | 36 | background-repeat: no-repeat; | ||
12 | 37 | background-position: right center; | ||
13 | 38 | padding-right: 16px; | ||
14 | 39 | } | ||
15 | 40 | .sort-asc { | ||
16 | 41 | background-image: url('../?img/sort_ascending.png'); | ||
17 | 42 | } | ||
18 | 43 | .sort-desc { | ||
19 | 44 | background-image: url('../?img/sort_descending.png'); | ||
20 | 45 | } | ||
21 | 33 | /* ul list */ | 46 | /* ul list */ |
22 | 34 | ul.list { | 47 | ul.list { |
23 | 35 | list-style: none; | 48 | list-style: none; |
24 | 36 | 49 | ||
25 | === added file 'src/maasserver/static/img/sort_ascending.png' | |||
26 | 37 | Binary files src/maasserver/static/img/sort_ascending.png 1970-01-01 00:00:00 +0000 and src/maasserver/static/img/sort_ascending.png 2012-12-03 07:15:29 +0000 differ | 50 | Binary files src/maasserver/static/img/sort_ascending.png 1970-01-01 00:00:00 +0000 and src/maasserver/static/img/sort_ascending.png 2012-12-03 07:15:29 +0000 differ |
27 | === added file 'src/maasserver/static/img/sort_descending.png' | |||
28 | 38 | Binary files src/maasserver/static/img/sort_descending.png 1970-01-01 00:00:00 +0000 and src/maasserver/static/img/sort_descending.png 2012-12-03 07:15:29 +0000 differ | 51 | Binary files src/maasserver/static/img/sort_descending.png 1970-01-01 00:00:00 +0000 and src/maasserver/static/img/sort_descending.png 2012-12-03 07:15:29 +0000 differ |
29 | === modified file 'src/maasserver/templates/maasserver/node_list.html' | |||
30 | --- src/maasserver/templates/maasserver/node_list.html 2012-10-17 05:20:13 +0000 | |||
31 | +++ src/maasserver/templates/maasserver/node_list.html 2012-12-03 07:15:29 +0000 | |||
32 | @@ -38,7 +38,7 @@ | |||
33 | 38 | {% if input_query_error %} | 38 | {% if input_query_error %} |
34 | 39 | <p class="form-errors">{{input_query_error}}</p> | 39 | <p class="form-errors">{{input_query_error}}</p> |
35 | 40 | {% endif %} | 40 | {% endif %} |
37 | 41 | {% include "maasserver/nodes_listing.html" %} | 41 | {% include "maasserver/nodes_listing.html" with sorting="true" %} |
38 | 42 | {% include "maasserver/pagination.html" %} | 42 | {% include "maasserver/pagination.html" %} |
39 | 43 | <a id="addnode" href="#" class="button right space-top">+ Add node</a> | 43 | <a id="addnode" href="#" class="button right space-top">+ Add node</a> |
40 | 44 | <div class="clear"></div> | 44 | <div class="clear"></div> |
41 | 45 | 45 | ||
42 | === modified file 'src/maasserver/templates/maasserver/nodes_listing.html' | |||
43 | --- src/maasserver/templates/maasserver/nodes_listing.html 2012-11-16 13:30:09 +0000 | |||
44 | +++ src/maasserver/templates/maasserver/nodes_listing.html 2012-12-03 07:15:29 +0000 | |||
45 | @@ -2,9 +2,25 @@ | |||
46 | 2 | <table class="list"> | 2 | <table class="list"> |
47 | 3 | <thead> | 3 | <thead> |
48 | 4 | <tr> | 4 | <tr> |
49 | 5 | {% if sorting == "true" %} | ||
50 | 6 | <th><a href="{{ sort_links.hostname }}" | ||
51 | 7 | class="{{ sort_classes.hostname }}"> | ||
52 | 8 | <acronym title="Fully Qualified Domain Name">FQDN</acronym> | ||
53 | 9 | </a></th> | ||
54 | 10 | <th> | ||
55 | 11 | <acronym | ||
56 | 12 | title="Media Access Control addresses">MAC</acronym> | ||
57 | 13 | </th> | ||
58 | 14 | <th> | ||
59 | 15 | <a href="{{ sort_links.status }}" | ||
60 | 16 | class="{{ sort_classes.status }}">Status</a> | ||
61 | 17 | </th> | ||
62 | 18 | {% else %} | ||
63 | 5 | <th><acronym title="Fully Qualified Domain Name">FQDN</acronym></th> | 19 | <th><acronym title="Fully Qualified Domain Name">FQDN</acronym></th> |
64 | 6 | <th><acronym | 20 | <th><acronym |
65 | 7 | title="Media Access Control addresses">MAC</acronym></th> | 21 | title="Media Access Control addresses">MAC</acronym></th> |
66 | 22 | <th>Status</th> | ||
67 | 23 | {% endif %} | ||
68 | 8 | </tr> | 24 | </tr> |
69 | 9 | </thead> | 25 | </thead> |
70 | 10 | {% for node in node_list %} | 26 | {% for node in node_list %} |
71 | 11 | 27 | ||
72 | === modified file 'src/maasserver/templates/maasserver/tag_view.html' | |||
73 | --- src/maasserver/templates/maasserver/tag_view.html 2012-11-07 11:32:16 +0000 | |||
74 | +++ src/maasserver/templates/maasserver/tag_view.html 2012-12-03 07:15:29 +0000 | |||
75 | @@ -34,7 +34,7 @@ | |||
76 | 34 | </ul> | 34 | </ul> |
77 | 35 | <div id="nodes" class="block first pad-top"> | 35 | <div id="nodes" class="block first pad-top"> |
78 | 36 | <h2 class="block first line-top pad-top">{{ paginator.count }} Node{{ paginator.count|pluralize }}</h2> | 36 | <h2 class="block first line-top pad-top">{{ paginator.count }} Node{{ paginator.count|pluralize }}</h2> |
80 | 37 | {% include "maasserver/nodes_listing.html" %} | 37 | {% include "maasserver/nodes_listing.html" with sorting="false" %} |
81 | 38 | {% include "maasserver/pagination.html" %} | 38 | {% include "maasserver/pagination.html" %} |
82 | 39 | </div> | 39 | </div> |
83 | 40 | {% endblock %} | 40 | {% endblock %} |
84 | 41 | 41 | ||
85 | === modified file 'src/maasserver/tests/test_views_nodes.py' | |||
86 | --- src/maasserver/tests/test_views_nodes.py 2012-11-29 13:22:20 +0000 | |||
87 | +++ src/maasserver/tests/test_views_nodes.py 2012-12-03 07:15:29 +0000 | |||
88 | @@ -13,7 +13,12 @@ | |||
89 | 13 | __all__ = [] | 13 | __all__ = [] |
90 | 14 | 14 | ||
91 | 15 | import httplib | 15 | import httplib |
92 | 16 | from operator import attrgetter | ||
93 | 16 | from unittest import skip | 17 | from unittest import skip |
94 | 18 | from urlparse import ( | ||
95 | 19 | parse_qsl, | ||
96 | 20 | urlparse, | ||
97 | 21 | ) | ||
98 | 17 | 22 | ||
99 | 18 | from django.conf import settings | 23 | from django.conf import settings |
100 | 19 | from django.core.urlresolvers import reverse | 24 | from django.core.urlresolvers import reverse |
101 | @@ -81,6 +86,15 @@ | |||
102 | 81 | enlist_preseed_link = reverse('enlist-preseed-view') | 86 | enlist_preseed_link = reverse('enlist-preseed-view') |
103 | 82 | self.assertIn(enlist_preseed_link, get_content_links(response)) | 87 | self.assertIn(enlist_preseed_link, get_content_links(response)) |
104 | 83 | 88 | ||
105 | 89 | def test_node_list_contains_column_sort_links(self): | ||
106 | 90 | # Just create a node to have something in the list | ||
107 | 91 | factory.make_node() | ||
108 | 92 | response = self.client.get(reverse('node-list')) | ||
109 | 93 | sort_hostname = '?sort=hostname&dir=asc' | ||
110 | 94 | sort_status = '?sort=status&dir=asc' | ||
111 | 95 | self.assertIn(sort_hostname, get_content_links(response)) | ||
112 | 96 | self.assertIn(sort_status, get_content_links(response)) | ||
113 | 97 | |||
114 | 84 | def test_node_list_lists_nodes_from_different_nodegroups(self): | 98 | def test_node_list_lists_nodes_from_different_nodegroups(self): |
115 | 85 | # Bug 1084443. | 99 | # Bug 1084443. |
116 | 86 | nodegroup1 = factory.make_node_group() | 100 | nodegroup1 = factory.make_node_group() |
117 | @@ -91,6 +105,99 @@ | |||
118 | 91 | response = self.client.get(reverse('node-list')) | 105 | response = self.client.get(reverse('node-list')) |
119 | 92 | self.assertEqual(httplib.OK, response.status_code) | 106 | self.assertEqual(httplib.OK, response.status_code) |
120 | 93 | 107 | ||
121 | 108 | def test_node_list_sorts_by_hostname(self): | ||
122 | 109 | names = ['zero', 'one', 'five'] | ||
123 | 110 | nodes = [factory.make_node(hostname=n) for n in names] | ||
124 | 111 | |||
125 | 112 | # First check the ascending sort order | ||
126 | 113 | sorted_nodes = sorted(nodes, key=attrgetter('hostname')) | ||
127 | 114 | response = self.client.get( | ||
128 | 115 | reverse('node-list'), { | ||
129 | 116 | 'sort': 'hostname', | ||
130 | 117 | 'dir': 'asc'}) | ||
131 | 118 | node_links = [ | ||
132 | 119 | reverse('node-view', args=[node.system_id]) | ||
133 | 120 | for node in sorted_nodes] | ||
134 | 121 | self.assertEqual( | ||
135 | 122 | node_links, | ||
136 | 123 | [link for link in get_content_links(response) | ||
137 | 124 | if link.startswith('/nodes/node')]) | ||
138 | 125 | |||
139 | 126 | # Now check the reverse order | ||
140 | 127 | node_links = list(reversed(node_links)) | ||
141 | 128 | response = self.client.get( | ||
142 | 129 | reverse('node-list'), { | ||
143 | 130 | 'sort': 'hostname', | ||
144 | 131 | 'dir': 'desc'}) | ||
145 | 132 | self.assertEqual( | ||
146 | 133 | node_links, | ||
147 | 134 | [link for link in get_content_links(response) | ||
148 | 135 | if link.startswith('/nodes/node')]) | ||
149 | 136 | |||
150 | 137 | def test_node_list_sorts_by_status(self): | ||
151 | 138 | statuses = { | ||
152 | 139 | NODE_STATUS.READY, | ||
153 | 140 | NODE_STATUS.DECLARED, | ||
154 | 141 | NODE_STATUS.FAILED_TESTS, | ||
155 | 142 | } | ||
156 | 143 | nodes = [factory.make_node(status=s) for s in statuses] | ||
157 | 144 | |||
158 | 145 | # First check the ascending sort order | ||
159 | 146 | sorted_nodes = sorted(nodes, key=attrgetter('status')) | ||
160 | 147 | response = self.client.get( | ||
161 | 148 | reverse('node-list'), { | ||
162 | 149 | 'sort': 'status', | ||
163 | 150 | 'dir': 'asc'}) | ||
164 | 151 | node_links = [ | ||
165 | 152 | reverse('node-view', args=[node.system_id]) | ||
166 | 153 | for node in sorted_nodes] | ||
167 | 154 | self.assertEqual( | ||
168 | 155 | node_links, | ||
169 | 156 | [link for link in get_content_links(response) | ||
170 | 157 | if link.startswith('/nodes/node')]) | ||
171 | 158 | |||
172 | 159 | # Now check the reverse order | ||
173 | 160 | node_links = list(reversed(node_links)) | ||
174 | 161 | response = self.client.get( | ||
175 | 162 | reverse('node-list'), { | ||
176 | 163 | 'sort': 'status', | ||
177 | 164 | 'dir': 'desc'}) | ||
178 | 165 | self.assertEqual( | ||
179 | 166 | node_links, | ||
180 | 167 | [link for link in get_content_links(response) | ||
181 | 168 | if link.startswith('/nodes/node')]) | ||
182 | 169 | |||
183 | 170 | def test_node_list_sort_preserves_other_params(self): | ||
184 | 171 | # Set a very small page size to save creating lots of nodes | ||
185 | 172 | page_size = 2 | ||
186 | 173 | self.patch(nodes_views.NodeListView, 'paginate_by', page_size) | ||
187 | 174 | |||
188 | 175 | nodes = [] | ||
189 | 176 | tag = factory.make_tag('shiny') | ||
190 | 177 | for name in ('bbb', 'ccc', 'ddd', 'aaa'): | ||
191 | 178 | node = factory.make_node(hostname=name) | ||
192 | 179 | node.tags = [tag] | ||
193 | 180 | nodes.append(node) | ||
194 | 181 | |||
195 | 182 | params = { | ||
196 | 183 | 'sort': 'hostname', | ||
197 | 184 | 'dir': 'asc', | ||
198 | 185 | 'page': '1', | ||
199 | 186 | 'query': 'maas-tags=shiny'} | ||
200 | 187 | response = self.client.get(reverse('node-list'), params) | ||
201 | 188 | document = fromstring(response.content) | ||
202 | 189 | header_links = document.xpath("//div[@id='nodes']/table//th/a/@href") | ||
203 | 190 | fields = iter(('hostname', 'status')) | ||
204 | 191 | field_dirs = iter(('desc', 'asc')) | ||
205 | 192 | for link in header_links: | ||
206 | 193 | self.assertThat( | ||
207 | 194 | parse_qsl(urlparse(link).query), | ||
208 | 195 | ContainsAll([ | ||
209 | 196 | ('page', '1'), | ||
210 | 197 | ('query', 'maas-tags=shiny'), | ||
211 | 198 | ('sort', next(fields)), | ||
212 | 199 | ('dir', next(field_dirs))])) | ||
213 | 200 | |||
214 | 94 | def test_node_list_displays_fqdn_dns_not_managed(self): | 201 | def test_node_list_displays_fqdn_dns_not_managed(self): |
215 | 95 | nodes = [factory.make_node() for i in range(3)] | 202 | nodes = [factory.make_node() for i in range(3)] |
216 | 96 | response = self.client.get(reverse('node-list')) | 203 | response = self.client.get(reverse('node-list')) |
217 | @@ -448,7 +555,8 @@ | |||
218 | 448 | {"query": "maas-tags=shiny cpu=2"}) | 555 | {"query": "maas-tags=shiny cpu=2"}) |
219 | 449 | node2_link = reverse('node-view', args=[node2.system_id]) | 556 | node2_link = reverse('node-view', args=[node2.system_id]) |
220 | 450 | document = fromstring(response.content) | 557 | document = fromstring(response.content) |
222 | 451 | node_links = document.xpath("//div[@id='nodes']/table//a/@href") | 558 | node_links = document.xpath( |
223 | 559 | "//div[@id='nodes']/table//td/a/@href") | ||
224 | 452 | self.assertEqual([node2_link], node_links) | 560 | self.assertEqual([node2_link], node_links) |
225 | 453 | 561 | ||
226 | 454 | def test_node_list_paginates(self): | 562 | def test_node_list_paginates(self): |
227 | @@ -461,7 +569,7 @@ | |||
228 | 461 | # Order node links with newest first as the view is expected to | 569 | # Order node links with newest first as the view is expected to |
229 | 462 | node_links = [reverse('node-view', args=[node.system_id]) | 570 | node_links = [reverse('node-view', args=[node.system_id]) |
230 | 463 | for node in reversed(nodes)] | 571 | for node in reversed(nodes)] |
232 | 464 | expr_node_links = XPath("//div[@id='nodes']/table//a/@href") | 572 | expr_node_links = XPath("//div[@id='nodes']/table//td/a/@href") |
233 | 465 | expr_page_anchors = XPath("//div[@class='pagination']//a") | 573 | expr_page_anchors = XPath("//div[@class='pagination']//a") |
234 | 466 | # Fetch first page, should link newest two nodes and page 2 | 574 | # Fetch first page, should link newest two nodes and page 2 |
235 | 467 | response = self.client.get(reverse('node-list')) | 575 | response = self.client.get(reverse('node-list')) |
236 | @@ -473,7 +581,8 @@ | |||
237 | 473 | # Fetch second page, should link next nodes and adjacent pages | 581 | # Fetch second page, should link next nodes and adjacent pages |
238 | 474 | response = self.client.get(reverse('node-list'), {"page": 2}) | 582 | response = self.client.get(reverse('node-list'), {"page": 2}) |
239 | 475 | page2 = fromstring(response.content) | 583 | page2 = fromstring(response.content) |
241 | 476 | self.assertEqual(node_links[page_size:page_size * 2], | 584 | self.assertEqual( |
242 | 585 | node_links[page_size:page_size * 2], | ||
243 | 477 | expr_node_links(page2)) | 586 | expr_node_links(page2)) |
244 | 478 | self.assertEqual([("first", "."), ("previous", "."), | 587 | self.assertEqual([("first", "."), ("previous", "."), |
245 | 479 | ("next", "?page=3"), ("last", "?page=3")], | 588 | ("next", "?page=3"), ("last", "?page=3")], |
246 | @@ -501,8 +610,9 @@ | |||
247 | 501 | {"query": "maas-tags=odd", "page": 3}) | 610 | {"query": "maas-tags=odd", "page": 3}) |
248 | 502 | document = fromstring(response.content) | 611 | document = fromstring(response.content) |
249 | 503 | self.assertIn("5 matching nodes", document.xpath("string(//h1)")) | 612 | self.assertIn("5 matching nodes", document.xpath("string(//h1)")) |
252 | 504 | self.assertEqual([last_node_link], | 613 | self.assertEqual( |
253 | 505 | document.xpath("//div[@id='nodes']/table//a/@href")) | 614 | [last_node_link], |
254 | 615 | document.xpath("//div[@id='nodes']/table//td/a/@href")) | ||
255 | 506 | self.assertEqual([("first", "?query=maas-tags%3Dodd"), | 616 | self.assertEqual([("first", "?query=maas-tags%3Dodd"), |
256 | 507 | ("previous", "?query=maas-tags%3Dodd&page=2")], | 617 | ("previous", "?query=maas-tags%3Dodd&page=2")], |
257 | 508 | [(a.text.lower(), a.get("href")) | 618 | [(a.text.lower(), a.get("href")) |
258 | 509 | 619 | ||
259 | === modified file 'src/maasserver/views/nodes.py' | |||
260 | --- src/maasserver/views/nodes.py 2012-11-29 13:22:20 +0000 | |||
261 | +++ src/maasserver/views/nodes.py 2012-12-03 07:15:29 +0000 | |||
262 | @@ -110,13 +110,26 @@ | |||
263 | 110 | def get(self, request, *args, **kwargs): | 110 | def get(self, request, *args, **kwargs): |
264 | 111 | self.query = request.GET.get("query") | 111 | self.query = request.GET.get("query") |
265 | 112 | self.query_error = None | 112 | self.query_error = None |
266 | 113 | self.sort_by = request.GET.get("sort") | ||
267 | 114 | self.sort_dir = request.GET.get("dir") | ||
268 | 115 | |||
269 | 113 | return super(NodeListView, self).get(request, *args, **kwargs) | 116 | return super(NodeListView, self).get(request, *args, **kwargs) |
270 | 114 | 117 | ||
271 | 115 | def get_queryset(self): | 118 | def get_queryset(self): |
273 | 116 | # Return node list sorted, newest first. | 119 | # Default sort - newest first, unless sorting params are |
274 | 120 | # present. In addition, to ensure order consistency, when | ||
275 | 121 | # sorting by non-unique fields (like status), we always | ||
276 | 122 | # sort by the unique creation date as well | ||
277 | 123 | if self.sort_by is not None: | ||
278 | 124 | prefix = '-' if self.sort_dir == 'desc' else '' | ||
279 | 125 | order_by = (prefix + self.sort_by, '-created') | ||
280 | 126 | else: | ||
281 | 127 | order_by = ('-created', ) | ||
282 | 128 | |||
283 | 129 | # Return the sorted node list | ||
284 | 117 | nodes = Node.objects.get_nodes( | 130 | nodes = Node.objects.get_nodes( |
285 | 118 | user=self.request.user, prefetch_mac=True, | 131 | user=self.request.user, prefetch_mac=True, |
287 | 119 | perm=NODE_PERMISSION.VIEW,).order_by('-created') | 132 | perm=NODE_PERMISSION.VIEW,).order_by(*order_by) |
288 | 120 | if self.query: | 133 | if self.query: |
289 | 121 | try: | 134 | try: |
290 | 122 | return constrain_nodes(nodes, _parse_constraints(self.query)) | 135 | return constrain_nodes(nodes, _parse_constraints(self.query)) |
291 | @@ -127,11 +140,39 @@ | |||
292 | 127 | nodes = nodes.prefetch_related('nodegroup__nodegroupinterface_set') | 140 | nodes = nodes.prefetch_related('nodegroup__nodegroupinterface_set') |
293 | 128 | return nodes | 141 | return nodes |
294 | 129 | 142 | ||
295 | 143 | def _prepare_sort_links(self): | ||
296 | 144 | """Returns 2 dicts, with sort fields as keys and | ||
297 | 145 | links and CSS classes for the that field. | ||
298 | 146 | """ | ||
299 | 147 | |||
300 | 148 | fields = ('hostname', 'status') | ||
301 | 149 | # Build relative URLs for the links, just with the params | ||
302 | 150 | links = {field: '?' for field in fields} | ||
303 | 151 | classes = {field: 'sort-none' for field in fields} | ||
304 | 152 | |||
305 | 153 | params = self.request.GET.copy() | ||
306 | 154 | reverse_dir = 'asc' if self.sort_dir == 'desc' else 'desc' | ||
307 | 155 | |||
308 | 156 | for field in fields: | ||
309 | 157 | params['sort'] = field | ||
310 | 158 | if field == self.sort_by: | ||
311 | 159 | params['dir'] = reverse_dir | ||
312 | 160 | classes[field] = 'sort-%s' % self.sort_dir | ||
313 | 161 | else: | ||
314 | 162 | params['dir'] = 'asc' | ||
315 | 163 | |||
316 | 164 | links[field] += params.urlencode() | ||
317 | 165 | |||
318 | 166 | return links, classes | ||
319 | 167 | |||
320 | 130 | def get_context_data(self, **kwargs): | 168 | def get_context_data(self, **kwargs): |
321 | 131 | context = super(NodeListView, self).get_context_data(**kwargs) | 169 | context = super(NodeListView, self).get_context_data(**kwargs) |
322 | 132 | context.update(get_longpoll_context()) | 170 | context.update(get_longpoll_context()) |
323 | 133 | context["input_query"] = self.query | 171 | context["input_query"] = self.query |
324 | 134 | context["input_query_error"] = self.query_error | 172 | context["input_query_error"] = self.query_error |
325 | 173 | links, classes = self._prepare_sort_links() | ||
326 | 174 | context["sort_links"] = links | ||
327 | 175 | context["sort_classes"] = classes | ||
328 | 135 | return context | 176 | return context |
329 | 136 | 177 | ||
330 | 137 | 178 |