Merge lp:~jtv/maas/commissioning-results-ui-tweaks into lp:~maas-committers/maas/trunk
- commissioning-results-ui-tweaks
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Jeroen T. Vermeulen |
Approved revision: | no longer in the source branch. |
Merged at revision: | 1963 |
Proposed branch: | lp:~jtv/maas/commissioning-results-ui-tweaks |
Merge into: | lp:~maas-committers/maas/trunk |
Diff against target: |
358 lines (+105/-66) 6 files modified
src/maasserver/templates/metadataserver/nodecommissionresult.html (+8/-6) src/maasserver/templates/metadataserver/nodecommissionresult_list.html (+33/-22) src/maasserver/views/nodecommissionresult.py (+15/-1) src/maasserver/views/nodes.py (+1/-9) src/maasserver/views/tests/test_nodecommissionresults.py (+48/-12) src/maasserver/views/tests/test_nodes.py (+0/-16) |
To merge this branch: | bzr merge lp:~jtv/maas/commissioning-results-ui-tweaks |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Review via email: mp+206732@code.launchpad.net |
Commit message
Tweaks for the commissioning-
Description of the change
These cover the remaining review notes from the original review for this UI: https:/
We have functions similar to normalise_
Jeroen
Julian Edwards (julian-edwards) wrote : | # |
On Monday 17 Feb 2014 15:59:06 you wrote:
> <jtv> allenap: if you want to play with the new feature, edit
> src/maasserver/
> to be True.
>
> Why are we using feature flags in trunk?
Let's get rid of the flag. The feature will be useful to people, even if it's
not polished to the shine of Gavin's head. We'll also get early feedback from
users before release time.
cheers.
Jeroen T. Vermeulen (jtv) wrote : | # |
> Looks good. I have lots of comments, but they're mostly around the UI,
> and not your changes. Pick out those ones that you want to fix; the rest
> is just my commentary on the feature.
Thanks for going through it so thoroughly! I made lots of changes in response, and they brought me to the point where I'm confident enough to drop the feature flag.
> [1]
>
> From IRC:
>
> <jtv> allenap: if you want to play with the new feature, edit
> src/maasserver/
> to be True.
>
> Why are we using feature flags in trunk?
Because the change would have been much more contentious otherwise. It was a mad-dash personal initiative, not a carefully planned feature. Planned as a feature it would have taken longer, and therefore, been lower on the priority list and impossible to fit in before the sprint. As a mad dash, it was at risk of bogging down in design/review changes, and we might still have ended up getting something great later instead of something good now. The feature flag made it possible to land the initial branch and make changes later.
> [2]
>
> + {% if result_
> + <span>OK: {{ result_
> + {% else %}
>
> I know this probably comes under "systemtic UI review", but I don't
> think this needs to include the return code. Just "OK" is enough.
Exactly the sort of feedback I needed. Done.
> + <span class="warning">
> + <img src="{{ STATIC_URL }}img/warning.png" title="Failed" />
> + FAILED: {{ result_
> + </span>
> + {% endif %}
>
> Likewise, this doesn't need the return code (it ought to be on the
> details page though).
Also done.
> [3]
>
> On the details page, instead of having the 2-column thing at the top,
> which takes up a lot of space without telling us much, how about
> integrating it into the output:
>
> <breadcrumbs>
> Nodes > moon > Commissioning results > 00-maas-01-lshw.out
> </breadcrumbs>
>
> <heading>
> FAILED
> </heading>
>
> <output>
> <italics>
> Recorded 12:34 on February 17th, 2014.
> </italics>
> Error while installing lldp: Network unreachable.
> <italics>
> Exited 1
> </italics>
> </output>
>
> Maybe that's no good either. I just know that I dislike that 2-column
> layout; it's too sparse and light on useful information.
I agree, but it's what we had available... Maybe we can have a proper redesign for this sometime after the sprint. It'd be nice if it didn't look quite so much like a Node page. For now though I hope this will remain a fairly obscure page.
> [4]
>
> On http://
> be able to click on the "/!\ FAILED" bit to see the logs. If I had
> wanted to see the logs from an "OK" result I would have wanted to click
> in the same column; it is called "Script result" after all.
Ironically, that's what I had in my original branch. But Raphaël preferred the link on the left-hand column, so I changed it. And now I have a solution that I hope will ...
Preview Diff
1 | === modified file 'src/maasserver/templates/metadataserver/nodecommissionresult.html' | |||
2 | --- src/maasserver/templates/metadataserver/nodecommissionresult.html 2014-02-17 07:34:05 +0000 | |||
3 | +++ src/maasserver/templates/metadataserver/nodecommissionresult.html 2014-02-18 04:37:34 +0000 | |||
4 | @@ -19,19 +19,21 @@ | |||
5 | 19 | </span> | 19 | </span> |
6 | 20 | </li> | 20 | </li> |
7 | 21 | <li class="block size7 first" id="time"> | 21 | <li class="block size7 first" id="time"> |
10 | 22 | <h4>Time</h4> | 22 | <h4>Result registered at</h4> |
11 | 23 | <span>Result was registered at {{ object.created }}</span> | 23 | <span>{{ object.created }}</span> |
12 | 24 | </li> | 24 | </li> |
13 | 25 | <li class="block size3" id="script-result"> | 25 | <li class="block size3" id="script-result"> |
16 | 26 | <h4>Return value</h4> | 26 | <h4>Script return value</h4> |
17 | 27 | <span>Script returned {{ object.script_result }}</span> | 27 | <span>{{ object.script_result }}</span> |
18 | 28 | </li> | 28 | </li> |
19 | 29 | 29 | ||
20 | 30 | <li class="block first separate" id="output"> | 30 | <li class="block first separate" id="output"> |
21 | 31 | {% if object.data %} | ||
22 | 31 | <h2>Output</h2> | 32 | <h2>Output</h2> |
24 | 32 | <pre> | 33 | <pre> |
25 | 33 | {{ object.get_data_as_html }} | 34 | {{ object.get_data_as_html }} |
27 | 34 | </pre> | 35 | </pre> |
28 | 36 | {% endif %} | ||
29 | 35 | </li> | 37 | </li> |
30 | 36 | </ul> | 38 | </ul> |
31 | 37 | 39 | ||
32 | 38 | 40 | ||
33 | === modified file 'src/maasserver/templates/metadataserver/nodecommissionresult_list.html' | |||
34 | --- src/maasserver/templates/metadataserver/nodecommissionresult_list.html 2014-02-17 04:25:33 +0000 | |||
35 | +++ src/maasserver/templates/metadataserver/nodecommissionresult_list.html 2014-02-18 04:37:34 +0000 | |||
36 | @@ -1,6 +1,6 @@ | |||
37 | 1 | {% extends "maasserver/base.html" %} | 1 | {% extends "maasserver/base.html" %} |
38 | 2 | 2 | ||
40 | 3 | {% block nav-active-zone-list %}active{% endblock %} | 3 | {% block nav-active-result-list %}active{% endblock %} |
41 | 4 | {% block title %}Node commissioning results{% endblock %} | 4 | {% block title %}Node commissioning results{% endblock %} |
42 | 5 | {% block page-title %} | 5 | {% block page-title %} |
43 | 6 | {{ paginator.count }} result{{ paginator.count|pluralize }} | 6 | {{ paginator.count }} result{{ paginator.count|pluralize }} |
44 | @@ -12,41 +12,52 @@ | |||
45 | 12 | 12 | ||
46 | 13 | {% block content %} | 13 | {% block content %} |
47 | 14 | <div id="results"> | 14 | <div id="results"> |
49 | 15 | <h2>Commissioning results</h2> | 15 | <h2 id="header"> |
50 | 16 | Commissioning results | ||
51 | 17 | {% if nodes_filter %} | ||
52 | 18 | for {{ nodes_filter }} | ||
53 | 19 | {% endif %} | ||
54 | 20 | </h2> | ||
55 | 16 | {% if paginator.count == 0 %} | 21 | {% if paginator.count == 0 %} |
56 | 17 | <p>No matching commissioning results.</p> | 22 | <p>No matching commissioning results.</p> |
57 | 18 | {% else %} | 23 | {% else %} |
58 | 19 | <table class="list"> | 24 | <table class="list"> |
59 | 20 | <thead> | 25 | <thead> |
60 | 21 | <tr> | 26 | <tr> |
62 | 22 | <th>Time</th> | 27 | <th>Script result</th> |
63 | 28 | <th>Output file</th> | ||
64 | 29 | <th>Registered at</th> | ||
65 | 23 | <th>Node</th> | 30 | <th>Node</th> |
66 | 24 | <th>Output file</th> | ||
67 | 25 | <th>Script result<th> | ||
68 | 26 | </tr> | 31 | </tr> |
69 | 27 | </thead> | 32 | </thead> |
70 | 28 | <tbody> | 33 | <tbody> |
71 | 29 | {% for result_item in results_list %} | 34 | {% for result_item in results_list %} |
72 | 30 | <tr class="result {% cycle 'even' 'odd' %}"> | 35 | <tr class="result {% cycle 'even' 'odd' %}"> |
74 | 31 | <td>{{ result_item.created }}</td> | 36 | <!-- Script result --> |
75 | 37 | <td> | ||
76 | 38 | <a href="{% url 'nodecommissionresult-view' result_item.id %}"> | ||
77 | 39 | {% if result_item.script_result == 0 %} | ||
78 | 40 | <span>OK</span> | ||
79 | 41 | {% else %} | ||
80 | 42 | <span class="warning"> | ||
81 | 43 | <img src="{{ STATIC_URL }}img/warning.png" title="Failed" /> | ||
82 | 44 | FAILED | ||
83 | 45 | </span> | ||
84 | 46 | {% endif %} | ||
85 | 47 | </a> | ||
86 | 48 | </td> | ||
87 | 49 | <!-- Output file --> | ||
88 | 50 | <td> | ||
89 | 51 | {{ result_item.name }} | ||
90 | 52 | </td> | ||
91 | 53 | <!-- Registered at --> | ||
92 | 54 | <td> | ||
93 | 55 | {{ result_item.created }} | ||
94 | 56 | </td> | ||
95 | 57 | <!-- Node --> | ||
96 | 32 | <td> | 58 | <td> |
97 | 33 | <a href="{% url 'node-view' result_item.node.system_id %}"> | 59 | <a href="{% url 'node-view' result_item.node.system_id %}"> |
114 | 34 | {{ result_item.node.system_id }} | 60 | {{ result_item.node.hostname }} |
99 | 35 | </a> | ||
100 | 36 | </td> | ||
101 | 37 | <td> | ||
102 | 38 | {{ result_item.name }} | ||
103 | 39 | </td> | ||
104 | 40 | <td> | ||
105 | 41 | <a href="{% url 'nodecommissionresult-view' result_item.id %}"> | ||
106 | 42 | {% if result_item.script_result == 0 %} | ||
107 | 43 | OK: {{ result_item.script_result }} | ||
108 | 44 | {% else %} | ||
109 | 45 | <span class="warning"> | ||
110 | 46 | <img src="{{ STATIC_URL }}img/warning.png" title="Failed" /> | ||
111 | 47 | FAILED: {{ result_item.script_result }} | ||
112 | 48 | </span> | ||
113 | 49 | {% endif %} | ||
115 | 50 | </a> | 61 | </a> |
116 | 51 | </td> | 62 | </td> |
117 | 52 | </tr> | 63 | </tr> |
118 | 53 | 64 | ||
119 | === modified file 'src/maasserver/views/nodecommissionresult.py' | |||
120 | --- src/maasserver/views/nodecommissionresult.py 2014-02-17 12:28:55 +0000 | |||
121 | +++ src/maasserver/views/nodecommissionresult.py 2014-02-18 04:37:34 +0000 | |||
122 | @@ -18,6 +18,7 @@ | |||
123 | 18 | 18 | ||
124 | 19 | from django.shortcuts import get_object_or_404 | 19 | from django.shortcuts import get_object_or_404 |
125 | 20 | from django.views.generic import DetailView | 20 | from django.views.generic import DetailView |
126 | 21 | from maasserver.models import Node | ||
127 | 21 | from maasserver.views import PaginatedListView | 22 | from maasserver.views import PaginatedListView |
128 | 22 | from metadataserver.models import NodeCommissionResult | 23 | from metadataserver.models import NodeCommissionResult |
129 | 23 | 24 | ||
130 | @@ -27,9 +28,22 @@ | |||
131 | 27 | template_name = 'maasserver/nodecommissionresult-list.html' | 28 | template_name = 'maasserver/nodecommissionresult-list.html' |
132 | 28 | context_object_name = 'results_list' | 29 | context_object_name = 'results_list' |
133 | 29 | 30 | ||
134 | 31 | def get_filter_system_ids(self): | ||
135 | 32 | """Return the list of nodes that were selected for filtering.""" | ||
136 | 33 | return self.request.GET.getlist('node') | ||
137 | 34 | |||
138 | 35 | def get_context_data(self, **kwargs): | ||
139 | 36 | context = super(NodeCommissionResultListView, self).get_context_data() | ||
140 | 37 | system_ids = self.get_filter_system_ids() | ||
141 | 38 | if system_ids is not None and len(system_ids) > 0: | ||
142 | 39 | nodes = Node.objects.filter(system_id__in=system_ids) | ||
143 | 40 | context['nodes_filter'] = ', '.join( | ||
144 | 41 | sorted(node.hostname for node in nodes)) | ||
145 | 42 | return context | ||
146 | 43 | |||
147 | 30 | def get_queryset(self): | 44 | def get_queryset(self): |
148 | 31 | results = NodeCommissionResult.objects.all() | 45 | results = NodeCommissionResult.objects.all() |
150 | 32 | system_ids = self.request.GET.getlist('node') | 46 | system_ids = self.get_filter_system_ids() |
151 | 33 | if system_ids is not None and len(system_ids) > 0: | 47 | if system_ids is not None and len(system_ids) > 0: |
152 | 34 | results = results.filter(node__system_id__in=system_ids) | 48 | results = results.filter(node__system_id__in=system_ids) |
153 | 35 | return results.order_by('node', '-created', 'name') | 49 | return results.order_by('node', '-created', 'name') |
154 | 36 | 50 | ||
155 | === modified file 'src/maasserver/views/nodes.py' | |||
156 | --- src/maasserver/views/nodes.py 2014-02-13 10:29:27 +0000 | |||
157 | +++ src/maasserver/views/nodes.py 2014-02-18 04:37:34 +0000 | |||
158 | @@ -400,11 +400,6 @@ | |||
159 | 400 | """) | 400 | """) |
160 | 401 | 401 | ||
161 | 402 | 402 | ||
162 | 403 | # Feature flag: link to node commissioning results? | ||
163 | 404 | # XXX jtv 2014-02-13: Remove this when this UI feature is good enough. | ||
164 | 405 | ENABLE_NODECOMMISSIONRESULTS = False | ||
165 | 406 | |||
166 | 407 | |||
167 | 408 | class NodeView(NodeViewMixin, UpdateView): | 403 | class NodeView(NodeViewMixin, UpdateView): |
168 | 409 | """View class to display a node's information and buttons for the actions | 404 | """View class to display a node's information and buttons for the actions |
169 | 410 | which can be performed on this node. | 405 | which can be performed on this node. |
170 | @@ -447,10 +442,7 @@ | |||
171 | 447 | context["probed_details"] = etree.tostring( | 442 | context["probed_details"] = etree.tostring( |
172 | 448 | probed_details, encoding=unicode, pretty_print=True) | 443 | probed_details, encoding=unicode, pretty_print=True) |
173 | 449 | 444 | ||
178 | 450 | if ENABLE_NODECOMMISSIONRESULTS: | 445 | results = NodeCommissionResult.objects.filter(node=node).count() |
175 | 451 | results = NodeCommissionResult.objects.filter(node=node).count() | ||
176 | 452 | else: | ||
177 | 453 | results = 0 | ||
179 | 454 | context['nodecommissionresults'] = results | 446 | context['nodecommissionresults'] = results |
180 | 455 | 447 | ||
181 | 456 | return context | 448 | return context |
182 | 457 | 449 | ||
183 | === modified file 'src/maasserver/views/tests/test_nodecommissionresults.py' | |||
184 | --- src/maasserver/views/tests/test_nodecommissionresults.py 2014-02-17 12:28:55 +0000 | |||
185 | +++ src/maasserver/views/tests/test_nodecommissionresults.py 2014-02-18 04:37:34 +0000 | |||
186 | @@ -30,6 +30,11 @@ | |||
187 | 30 | from testtools.matchers import HasLength | 30 | from testtools.matchers import HasLength |
188 | 31 | 31 | ||
189 | 32 | 32 | ||
190 | 33 | def normalise_whitespace(text): | ||
191 | 34 | """Replace any whitespace sequence with just a single space.""" | ||
192 | 35 | return ' '.join(text.split()) | ||
193 | 36 | |||
194 | 37 | |||
195 | 33 | class TestNodeCommissionResultView(MAASServerTestCase): | 38 | class TestNodeCommissionResultView(MAASServerTestCase): |
196 | 34 | 39 | ||
197 | 35 | def request_page(self, result): | 40 | def request_page(self, result): |
198 | @@ -72,7 +77,7 @@ | |||
199 | 72 | result.node.hostname, | 77 | result.node.hostname, |
200 | 73 | self.extract_field(doc, 'node')) | 78 | self.extract_field(doc, 'node')) |
201 | 74 | self.assertEqual( | 79 | self.assertEqual( |
203 | 75 | "Script returned %d" % result.script_result, | 80 | "%d" % result.script_result, |
204 | 76 | self.extract_field(doc, 'script-result')) | 81 | self.extract_field(doc, 'script-result')) |
205 | 77 | self.assertEqual(result.data, self.extract_field(doc, 'output', 'pre')) | 82 | self.assertEqual(result.data, self.extract_field(doc, 'output', 'pre')) |
206 | 78 | 83 | ||
207 | @@ -92,6 +97,13 @@ | |||
208 | 92 | doc = self.request_page(result) | 97 | doc = self.request_page(result) |
209 | 93 | self.assertEqual('A\ufffdB', self.extract_field(doc, 'output', 'pre')) | 98 | self.assertEqual('A\ufffdB', self.extract_field(doc, 'output', 'pre')) |
210 | 94 | 99 | ||
211 | 100 | def test_hides_output_if_empty(self): | ||
212 | 101 | self.client_log_in(as_admin=True) | ||
213 | 102 | result = factory.make_node_commission_result(data=b'') | ||
214 | 103 | doc = self.request_page(result) | ||
215 | 104 | field = get_one(doc.cssselect('#output')) | ||
216 | 105 | self.assertEqual('', field.text_content().strip()) | ||
217 | 106 | |||
218 | 95 | 107 | ||
219 | 96 | class TestNodeCommissionResultListView(MAASServerTestCase): | 108 | class TestNodeCommissionResultListView(MAASServerTestCase): |
220 | 97 | 109 | ||
221 | @@ -143,26 +155,23 @@ | |||
222 | 143 | result_row = get_one(content.cssselect('.result')) | 155 | result_row = get_one(content.cssselect('.result')) |
223 | 144 | fields = result_row.cssselect('td') | 156 | fields = result_row.cssselect('td') |
224 | 145 | 157 | ||
226 | 146 | [time, node, output_file, script_result] = fields | 158 | [script_result, output_file, time, node] = fields |
227 | 159 | self.assertEqual('OK', script_result.text_content().strip()) | ||
228 | 147 | self.assertIn('%d' % result.created.year, time.text_content()) | 160 | self.assertIn('%d' % result.created.year, time.text_content()) |
230 | 148 | self.assertEqual(result.node.system_id, node.text_content().strip()) | 161 | self.assertEqual(result.node.hostname, node.text_content().strip()) |
231 | 149 | self.assertEqual( | 162 | self.assertEqual( |
232 | 150 | reverse('node-view', args=[result.node.system_id]), | 163 | reverse('node-view', args=[result.node.system_id]), |
233 | 151 | get_one(node.cssselect('a')).get('href')) | 164 | get_one(node.cssselect('a')).get('href')) |
234 | 152 | self.assertEqual(result.name, output_file.text_content().strip()) | 165 | self.assertEqual(result.name, output_file.text_content().strip()) |
235 | 153 | self.assertEqual('OK: 0', script_result.text_content().strip()) | ||
236 | 154 | 166 | ||
237 | 155 | def test_shows_failure(self): | 167 | def test_shows_failure(self): |
238 | 156 | self.client_log_in(as_admin=True) | 168 | self.client_log_in(as_admin=True) |
241 | 157 | result = factory.make_node_commission_result( | 169 | factory.make_node_commission_result(script_result=randint(1, 100)) |
240 | 158 | script_result=randint(1, 100)) | ||
242 | 159 | content = self.request_page() | 170 | content = self.request_page() |
243 | 160 | result_row = get_one(content.cssselect('.result')) | 171 | result_row = get_one(content.cssselect('.result')) |
244 | 161 | fields = result_row.cssselect('td') | 172 | fields = result_row.cssselect('td') |
249 | 162 | [_, _, _, script_result] = fields | 173 | [script_result, _, _, _] = fields |
250 | 163 | self.assertEqual( | 174 | self.assertEqual("FAILED", script_result.text_content().strip()) |
247 | 164 | "FAILED: %d" % result.script_result, | ||
248 | 165 | script_result.text_content().strip()) | ||
251 | 166 | self.assertNotEqual([], script_result.find_class('warning')) | 175 | self.assertNotEqual([], script_result.find_class('warning')) |
252 | 167 | 176 | ||
253 | 168 | def test_links_to_result(self): | 177 | def test_links_to_result(self): |
254 | @@ -172,7 +181,7 @@ | |||
255 | 172 | content = self.request_page() | 181 | content = self.request_page() |
256 | 173 | result_row = get_one(content.cssselect('.result')) | 182 | result_row = get_one(content.cssselect('.result')) |
257 | 174 | fields = result_row.cssselect('td') | 183 | fields = result_row.cssselect('td') |
259 | 175 | [_, _, _, script_result] = fields | 184 | [script_result, _, _, _] = fields |
260 | 176 | link = get_one(script_result.cssselect('a')) | 185 | link = get_one(script_result.cssselect('a')) |
261 | 177 | self.assertEqual( | 186 | self.assertEqual( |
262 | 178 | reverse('nodecommissionresult-view', args=[result.id]), | 187 | reverse('nodecommissionresult-view', args=[result.id]), |
263 | @@ -241,8 +250,35 @@ | |||
264 | 241 | self.assertThat(rows, HasLength(len(matching_results))) | 250 | self.assertThat(rows, HasLength(len(matching_results))) |
265 | 242 | matching_names = set() | 251 | matching_names = set() |
266 | 243 | for row in rows: | 252 | for row in rows: |
268 | 244 | [_, _, name, _] = row.cssselect('td') | 253 | [_, name, _, _] = row.cssselect('td') |
269 | 245 | matching_names.add(name.text_content().strip()) | 254 | matching_names.add(name.text_content().strip()) |
270 | 246 | self.assertEqual( | 255 | self.assertEqual( |
271 | 247 | {result.name for result in matching_results}, | 256 | {result.name for result in matching_results}, |
272 | 248 | matching_names) | 257 | matching_names) |
273 | 258 | |||
274 | 259 | def test_does_not_show_node_if_not_filtering_by_node(self): | ||
275 | 260 | self.client_log_in(as_admin=True) | ||
276 | 261 | doc = self.request_page() | ||
277 | 262 | header = get_one(doc.cssselect('#header')) | ||
278 | 263 | self.assertEqual( | ||
279 | 264 | "Commissioning results", | ||
280 | 265 | normalise_whitespace(header.text_content())) | ||
281 | 266 | |||
282 | 267 | def test_shows_node_if_filtering_by_node(self): | ||
283 | 268 | self.client_log_in(as_admin=True) | ||
284 | 269 | node = factory.make_node() | ||
285 | 270 | doc = self.request_page(nodes=[node]) | ||
286 | 271 | header = get_one(doc.cssselect('#header')) | ||
287 | 272 | self.assertEqual( | ||
288 | 273 | "Commissioning results for %s" % node.hostname, | ||
289 | 274 | normalise_whitespace(header.text_content())) | ||
290 | 275 | |||
291 | 276 | def test_shows_nodes_if_filtering_by_multiple_nodes(self): | ||
292 | 277 | self.client_log_in(as_admin=True) | ||
293 | 278 | names = [factory.make_name('node').lower() for _ in range(2)] | ||
294 | 279 | nodes = [factory.make_node(hostname=name) for name in names] | ||
295 | 280 | doc = self.request_page(nodes=nodes) | ||
296 | 281 | header = get_one(doc.cssselect('#header')) | ||
297 | 282 | self.assertEqual( | ||
298 | 283 | "Commissioning results for %s" % ', '.join(sorted(names)), | ||
299 | 284 | normalise_whitespace(header.text_content())) | ||
300 | 249 | 285 | ||
301 | === modified file 'src/maasserver/views/tests/test_nodes.py' | |||
302 | --- src/maasserver/views/tests/test_nodes.py 2014-02-13 10:53:27 +0000 | |||
303 | +++ src/maasserver/views/tests/test_nodes.py 2014-02-18 04:37:34 +0000 | |||
304 | @@ -951,11 +951,6 @@ | |||
305 | 951 | class NodeCommissionResultsDisplayTest(MAASServerTestCase): | 951 | class NodeCommissionResultsDisplayTest(MAASServerTestCase): |
306 | 952 | """Tests for the link to node commissioning results on the Node page.""" | 952 | """Tests for the link to node commissioning results on the Node page.""" |
307 | 953 | 953 | ||
308 | 954 | def enable_display(self): | ||
309 | 955 | """Enable the feature flag behind which this display is hidden.""" | ||
310 | 956 | # XXX jtv 2014-02-13: Remove this once feature is good enough. | ||
311 | 957 | self.patch(nodes_views, 'ENABLE_NODECOMMISSIONRESULTS', True) | ||
312 | 958 | |||
313 | 959 | def request_results_display(self, node): | 954 | def request_results_display(self, node): |
314 | 960 | """Request the page for `node`, and extract the results display. | 955 | """Request the page for `node`, and extract the results display. |
315 | 961 | 956 | ||
316 | @@ -1000,7 +995,6 @@ | |||
317 | 1000 | return ' '.join(text.split()) | 995 | return ' '.join(text.split()) |
318 | 1001 | 996 | ||
319 | 1002 | def test_view_node_links_to_commissioning_results_if_appropriate(self): | 997 | def test_view_node_links_to_commissioning_results_if_appropriate(self): |
320 | 1003 | self.enable_display() | ||
321 | 1004 | self.client_log_in(as_admin=True) | 998 | self.client_log_in(as_admin=True) |
322 | 1005 | result = factory.make_node_commission_result() | 999 | result = factory.make_node_commission_result() |
323 | 1006 | section = self.request_results_display(result.node) | 1000 | section = self.request_results_display(result.node) |
324 | @@ -1010,26 +1004,17 @@ | |||
325 | 1010 | results_list + '?node=%s' % result.node.system_id, | 1004 | results_list + '?node=%s' % result.node.system_id, |
326 | 1011 | link.get('href')) | 1005 | link.get('href')) |
327 | 1012 | 1006 | ||
328 | 1013 | def test_view_node_hides_commissioning_results_by_default(self): | ||
329 | 1014 | # XXX jtv 2014-02-13: Remove this test once we get rid of feature flag. | ||
330 | 1015 | self.client_log_in(as_admin=True) | ||
331 | 1016 | result = factory.make_node_commission_result() | ||
332 | 1017 | self.assertIsNone(self.request_results_display(result.node)) | ||
333 | 1018 | |||
334 | 1019 | def test_view_node_shows_commissioning_results_only_if_present(self): | 1007 | def test_view_node_shows_commissioning_results_only_if_present(self): |
335 | 1020 | self.enable_display() | ||
336 | 1021 | self.client_log_in(as_admin=True) | 1008 | self.client_log_in(as_admin=True) |
337 | 1022 | node = factory.make_node() | 1009 | node = factory.make_node() |
338 | 1023 | self.assertIsNone(self.request_results_display(node)) | 1010 | self.assertIsNone(self.request_results_display(node)) |
339 | 1024 | 1011 | ||
340 | 1025 | def test_view_node_shows_commissioning_results_only_to_superuser(self): | 1012 | def test_view_node_shows_commissioning_results_only_to_superuser(self): |
341 | 1026 | self.enable_display() | ||
342 | 1027 | self.client_log_in(as_admin=False) | 1013 | self.client_log_in(as_admin=False) |
343 | 1028 | result = factory.make_node_commission_result() | 1014 | result = factory.make_node_commission_result() |
344 | 1029 | self.assertIsNone(self.request_results_display(result.node)) | 1015 | self.assertIsNone(self.request_results_display(result.node)) |
345 | 1030 | 1016 | ||
346 | 1031 | def test_view_node_shows_single_commissioning_result(self): | 1017 | def test_view_node_shows_single_commissioning_result(self): |
347 | 1032 | self.enable_display() | ||
348 | 1033 | self.client_log_in(as_admin=True) | 1018 | self.client_log_in(as_admin=True) |
349 | 1034 | result = factory.make_node_commission_result() | 1019 | result = factory.make_node_commission_result() |
350 | 1035 | section = self.request_results_display(result.node) | 1020 | section = self.request_results_display(result.node) |
351 | @@ -1039,7 +1024,6 @@ | |||
352 | 1039 | self.normalise_whitespace(link.text_content())) | 1024 | self.normalise_whitespace(link.text_content())) |
353 | 1040 | 1025 | ||
354 | 1041 | def test_view_node_shows_multiple_commissioning_results(self): | 1026 | def test_view_node_shows_multiple_commissioning_results(self): |
355 | 1042 | self.enable_display() | ||
356 | 1043 | self.client_log_in(as_admin=True) | 1027 | self.client_log_in(as_admin=True) |
357 | 1044 | node = factory.make_node() | 1028 | node = factory.make_node() |
358 | 1045 | num_results = randint(2, 5) | 1029 | num_results = randint(2, 5) |
Looks good. I have lots of comments, but they're mostly around the UI,
and not your changes. Pick out those ones that you want to fix; the rest
is just my commentary on the feature.
[1]
From IRC:
<jtv> allenap: if you want to play with the new feature, edit r/views/ nodes.py and change ENABLE_ NODECOMMISSIONR ESULTS
src/maasserve
to be True.
Why are we using feature flags in trunk?
[2]
+ {% if result_ item.script_ result == 0 %} item.script_ result }}</span>
+ <span>OK: {{ result_
+ {% else %}
I know this probably comes under "systemtic UI review", but I don't
think this needs to include the return code. Just "OK" is enough.
+ <span class="warning"> item.script_ result }}
+ <img src="{{ STATIC_URL }}img/warning.png" title="Failed" />
+ FAILED: {{ result_
+ </span>
+ {% endif %}
Likewise, this doesn't need the return code (it ought to be on the
details page though).
[3]
On the details page, instead of having the 2-column thing at the top,
which takes up a lot of space without telling us much, how about
integrating it into the output:
<breadcrumbs>
Nodes > moon > Commissioning results > 00-maas-01-lshw.out
</breadcrumbs>
<heading>
FAILED
</heading>
<output>
<italics>
Recorded 12:34 on February 17th, 2014.
</italics>
Error while installing lldp: Network unreachable.
<italics>
Exited 1
</italics>
</output>
Maybe that's no good either. I just know that I dislike that 2-column
layout; it's too sparse and light on useful information.
[4]
On http:// localhost: 5240/commission ing-results/ ?node=... I expected to
be able to click on the "/!\ FAILED" bit to see the logs. If I had
wanted to see the logs from an "OK" result I would have wanted to click
in the same column; it is called "Script result" after all.
[4.1]
Same goes for http:// localhost: 5240/nodes/; I want to be able to click
the "Failed tests" status line or the warning triangle to see what's
wrong.
[4.2]
The URL http:// localhost: 5240/commission ing-results/ ?node=... is
slightly disorientating. It would be good to have a view under
/nodes/$id/ to show a page with that node's own results.
[5]
I'm also not sure I care what file it wrote to: 02-virtuality. out means little to me, and I know the
00-maas-
implementation.
[6]
I'm also not sure the Node column is useful on that page. I see that 4671-11e1- 93b8-00225f89f2 11 is
it's a general commissioning results page, narrowed to that particular
node, but I got there by finding "moon" then clicking "3 output files".
To be told that it's for node-29d7ad70-
confusing. Once I understood, it was superfluous.
I guess it needs to be there when showing more than just a single node's
results, but it should then show the node's given name, rather than its
system-generated name.
[7]
On http:// localhost: 5240/nodes/ .../view/ the "Commissioning output" cell
should probably show if commissioning failed too, but perhaps that's
coming later.
[8]
It's not a change you made, but the <pre> block for the output has
excess whitespace within it. <pre> is so anal that it's necessary to
foreg...