Merge lp:~blake-rouse/maas/images-ajax-view into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 3188
Proposed branch: lp:~blake-rouse/maas/images-ajax-view
Merge into: lp:~maas-committers/maas/trunk
Prerequisite: lp:~blake-rouse/maas/images-ajax-response
Diff against target: 834 lines (+293/-358)
7 files modified
src/maasserver/context_processors.py (+2/-0)
src/maasserver/static/js/image_views.js (+21/-0)
src/maasserver/static/js/tests/test_image_views.js (+23/-0)
src/maasserver/templates/maasserver/images.html (+245/-246)
src/maasserver/templates/maasserver/js-conf.html (+2/-1)
src/maasserver/views/images.py (+0/-10)
src/maasserver/views/tests/test_images.py (+0/-101)
To merge this branch: bzr merge lp:~blake-rouse/maas/images-ajax-view
Reviewer Review Type Date Requested Status
Newell Jensen (community) Approve
Review via email: mp+236949@code.launchpad.net

Commit message

Use the ImagesView on the images page. Status of importing is updated every 15 seconds, new Ubuntu resources will appear and disappear along with its current status.

To post a comment you must log in.
Revision history for this message
Newell Jensen (newell-jensen) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/context_processors.py'
2--- src/maasserver/context_processors.py 2014-09-29 15:26:08 +0000
3+++ src/maasserver/context_processors.py 2014-10-02 18:55:55 +0000
4@@ -56,6 +56,8 @@
5 'css/multiselect_widget.css',
6 ],
7 'JS_LIST': [
8+ 'js/image.js',
9+ 'js/image_views.js',
10 'js/license_key.js',
11 'js/morph.js',
12 'js/user_panel.js',
13
14=== modified file 'src/maasserver/static/js/image_views.js'
15--- src/maasserver/static/js/image_views.js 2014-10-02 18:55:55 +0000
16+++ src/maasserver/static/js/image_views.js 2014-10-02 18:55:55 +0000
17@@ -254,9 +254,11 @@
18 if(ubuntuImages.length == 0) {
19 this.ubuntuMissingImages.removeClass('hidden');
20 this.ubuntuTable.addClass('hidden');
21+ this.updateUbuntuButton(false);
22 } else {
23 this.ubuntuMissingImages.addClass('hidden');
24 this.ubuntuTable.removeClass('hidden');
25+ this.updateUbuntuButton(true);
26 }
27 var self = this;
28 var innerTable = "";
29@@ -273,6 +275,25 @@
30 },
31
32 /**
33+ * Update the value of the ubuntuButton.
34+ *
35+ * The value of the button can be locked meaning it should not change, this
36+ * is done using the data attribute lock-value. data-lock-value="true"
37+ *
38+ * @method updateUbuntuButton
39+ */
40+ updateUbuntuButton: function(showApply) {
41+ if(!Y.Lang.isValue(this.ubuntuButton))
42+ return;
43+ if(this.ubuntuButton.getData('lock-value') === "true")
44+ return;
45+ if(showApply)
46+ this.ubuntuButton.set('value', 'Apply changes');
47+ else
48+ this.ubuntuButton.set('value', 'Import images');
49+ },
50+
51+ /**
52 * Return the HTML for the downloading spinner for the given model.
53 *
54 * @method getSpinner
55
56=== modified file 'src/maasserver/static/js/tests/test_image_views.js'
57--- src/maasserver/static/js/tests/test_image_views.js 2014-10-02 18:55:55 +0000
58+++ src/maasserver/static/js/tests/test_image_views.js 2014-10-02 18:55:55 +0000
59@@ -369,6 +369,29 @@
60 });
61 },
62
63+ testUpdateUbuntuButtonSetValueForApply: function() {
64+ var view = this.makeImagesView();
65+ var ubuntuButton = view.srcNode.one('#ubuntu-apply');
66+ view.updateUbuntuButton(true);
67+ Y.Assert.areSame('Apply changes', ubuntuButton.get('value'));
68+ },
69+
70+ testUpdateUbuntuButtonSetValueForImport: function() {
71+ var view = this.makeImagesView();
72+ var ubuntuButton = view.srcNode.one('#ubuntu-apply');
73+ view.updateUbuntuButton(false);
74+ Y.Assert.areSame('Import images', ubuntuButton.get('value'));
75+ },
76+
77+ testUpdateUbuntuButtonDoesNothingIfLockValueExists: function() {
78+ var view = this.makeImagesView();
79+ var ubuntuButton = view.srcNode.one('#ubuntu-apply');
80+ ubuntuButton.set('value', 'testing');
81+ ubuntuButton.setData('lock-value', 'true');
82+ view.updateUbuntuButton(true);
83+ Y.Assert.areSame('testing', ubuntuButton.get('value'));
84+ },
85+
86 testGetSpinnerReturnsEmptyForComplete: function() {
87 var view = this.makeImagesView();
88 var model = new Y.maas.image.Image({complete: true});
89
90=== modified file 'src/maasserver/templates/maasserver/images.html'
91--- src/maasserver/templates/maasserver/images.html 2014-09-30 18:59:13 +0000
92+++ src/maasserver/templates/maasserver/images.html 2014-10-02 18:55:55 +0000
93@@ -42,7 +42,11 @@
94 -webkit-border-radius: 5px;
95 background-color: rgba(221, 72, 20, 0.3);
96 }
97- .importing {
98+ #loader {
99+ width: 10px;
100+ margin: 16px auto 0 auto;
101+ }
102+ #importing {
103 margin: -20px auto -19px auto;
104 width: 230px;
105 font-weight: bold;
106@@ -85,82 +89,212 @@
107 }
108 }
109 </style>
110+ <script type="text/javascript">
111+ <!--
112+ YUI().use('maas.image_views', 'maas.shortpoll', function (Y) {
113+ Y.on('load', function() {
114+ var view = new Y.maas.image_views.ImagesView({
115+ srcNode: '#content',
116+ loader: '#loader',
117+ content: '#images-content',
118+ importer: '#importing',
119+ ubuntuOptions: '#ubuntu-options',
120+ ubuntuTable: '#ubuntu-resources',
121+ ubuntuMissingImages: '#missing-ubuntu-images',
122+ ubuntuButton: '#ubuntu-apply'});
123+
124+ var poller = new Y.maas.shortpoll.ShortPollManager({
125+ uri: MAAS_config.uris.images_handler
126+ });
127+ view.addLoader(poller.get("io"));
128+ poller.poll();
129+ });
130+ });
131+ // -->
132+ </script>
133 {% endblock %}
134
135 {% block content %}
136- {% if region_import_running or cluster_import_running %}
137- <div class="importing">
138+ <div id="loader">
139 <div class="spinner spin"></div>
140- {% if region_import_running %}
141- Step 1/2: Region importing
142- {% elif cluster_import_running %}
143- Step 2/2: Clusters importing
144+ </div>
145+ <div id="images-content" class="hidden">
146+ <div id="importing" class="hidden">
147+ <div class="spinner spin"></div>
148+ <span class="importing-text"></span>
149+ <span class="importing-dot">.</span>
150+ <span class="importing-dot" style="-webkit-animation-delay: 0.2s; animation-delay: 0.2s;">.</span>
151+ <span class="importing-dot" style="-webkit-animation-delay: 0.3s; animation-delay: 0.3s;">.</span>​
152+ </div>
153+ <div id="ubuntu-images" class="section">
154+ <h2>Ubuntu</h2>
155+ <div class="content">
156+ <form id="ubuntu_images"
157+ method="POST"
158+ action="{% url 'images' %}">
159+ {% csrf_token %}
160+ <input type="hidden" name="ubuntu_images" value="1" />
161+ {% if user.is_superuser %}
162+ <div id="ubuntu-options" class="row hidden">
163+ {% if connection_error %}
164+ <div id="connection-error" class="images-warning">
165+ Connection Error: Unable to retrieve image information from
166+ boot sources.
167+ </div>
168+ {% else %}
169+ {% if ubuntu_streams_count == 0 %}
170+ <div id="no-ubuntu-sources" class="images-warning">
171+ Error: No boot sources provide Ubuntu images.
172+ </div>
173+ {% elif ubuntu_streams_count == 1 %}
174+ <div class="col2">
175+ <div class="space-bottom-small">Release:</div>
176+ <ul id="ubuntu-releases" class="data-list">
177+ {% for release in ubuntu_releases %}
178+ <li><input type="checkbox" name="release"
179+ value="{{release.name}}"
180+ {% if release.checked %}checked="checked"{% endif %}>
181+ {{release.title}}</li>
182+ {% endfor %}
183+ </ul>
184+ </div>
185+ <div class="col10 last">
186+ <div class="space-bottom-small">Architecture:</div>
187+ <ul id="ubuntu-arches" class="data-list">
188+ {% for arch in ubuntu_arches %}
189+ <li><input type="checkbox" name="arch"
190+ value="{{arch.name}}"
191+ {% if arch.checked %}checked="checked"{% endif %}>
192+ {{arch.title}}</li>
193+ {% endfor %}
194+ </ul>
195+ </div>
196+ {% else %}
197+ <div id="too-many-ubuntu-sources" class="images-warning">
198+ More than one boot source is providing Ubuntu images. Image
199+ selection cannot be performed using the WebUI.
200+ </div>
201+ {% endif %}
202+ {% endif %}
203+ </div>
204+ <div class="clear"></div>
205+ {% endif %}
206+ <div class="row space-top">
207+ <table id="ubuntu-resources" class="space-top list hidden">
208+ <thead>
209+ <tr>
210+ <th class="spinner-col"></th>
211+ <th>Release</th>
212+ <th>Architecture</th>
213+ <th>Size</th>
214+ <th>Nodes deployed</th>
215+ <th>Last update</th>
216+ </tr>
217+ </thead>
218+ <tbody>
219+ {# maas.image_view.ImageView will render this part #}
220+ </tbody>
221+ </table>
222+ <div id="missing-ubuntu-images" class="images-warning hidden">
223+ No Ubuntu images have been imported. Ubuntu images are required
224+ to allow nodes to enlist, commission, and install.</div>
225+ </div>
226+ <div class="clear"></div>
227+ <div class="row space-top end-row">
228+ {% if user.is_superuser %}
229+ <div class="col12 last align-right">
230+ {% if ubuntu_streams_count == 1 %}
231+ <input id="ubuntu-apply" type="submit" class="button hidden" value="Import images">
232+ {% elif ubuntu_streams_count > 1 %}
233+ <input id="ubuntu-apply" type="submit" class="button hidden" data-lock-value="true" value="Import images">
234+ {% endif %}
235+ </div>
236+ {% endif %}
237+ </div>
238+ <div class="clear"></div>
239+ </form>
240+ </div>
241+ </div>
242+ {% if other_resources %}
243+ <div id="other-sync-images" class="section">
244+ <h2>Other Images</h2>
245+ <div class="content">
246+ <form id="other_images"
247+ method="POST"
248+ action="{% url 'images' %}">
249+ {% csrf_token %}
250+ <input type="hidden" name="other_images" value="1" />
251+ <div class="row space-top">
252+ <table id="other-resources" class="space-top list">
253+ <thead>
254+ <tr>
255+ <th class="spinner-col"></th>
256+ <th>Name</th>
257+ <th>Architecture</th>
258+ <th>Size</th>
259+ <th>Nodes deployed</th>
260+ <th>Last update</th>
261+ </tr>
262+ </thead>
263+ <tbody>
264+ {% for resource in other_resources %}
265+ <tr
266+ class="{% cycle 'even' 'odd' %}"
267+ data-id="{% if resource.id %}{{ resource.id }}{% endif %}">
268+ <td>
269+ {% if region_import_running and resource.exists %}
270+ {% if not resource.complete %}
271+ <div
272+ title="{{ resource.status }}"
273+ class="
274+ spinner
275+ {% if resource.downloading %}spin{% endif %}">
276+ </div>
277+ {% endif %}
278+ {% elif not region_import_running and user.is_superuser %}
279+ <input
280+ type="checkbox"
281+ name="image"
282+ value="{{ resource.os }}/{{ resource.arch }}/{{ resource.subarch }}/{{ resource.release }}"
283+ {% if resource.exists %}
284+ checked="checked"
285+ {% endif %}
286+ >
287+ {% endif %}
288+ </td>
289+ <td>{{ resource.title }}</td>
290+ <td>{{ resource.arch }}</td>
291+ <td>{{ resource.size }}</td>
292+ <td>{{ resource.number_of_nodes }}</td>
293+ <td>{{ resource.last_update }}</td>
294+ </tr>
295+ {% endfor %}
296+ </tbody>
297+ </table>
298+ </div>
299+ <div class="clear"></div>
300+ <div class="row space-top end-row">
301+ {% if user.is_superuser and not region_import_running %}
302+ <div class="col12 last align-right">
303+ <input type="submit" class="button" value="Apply changes">
304+ </div>
305+ {% endif %}
306+ </div>
307+ <div class="clear"></div>
308+ </form>
309+ </div>
310+ </div>
311 {% endif %}
312- <span class="importing-dot">.</span>
313- <span class="importing-dot" style="-webkit-animation-delay: 0.2s; animation-delay: 0.2s;">.</span>
314- <span class="importing-dot" style="-webkit-animation-delay: 0.3s; animation-delay: 0.3s;">.</span>​
315- </div>
316- {% endif %}
317- <div id="ubuntu-images" class="section">
318- <h2>Ubuntu</h2>
319- <div class="content">
320- <form id="ubuntu_images"
321- method="POST"
322- action="{% url 'images' %}">
323- {% csrf_token %}
324- <input type="hidden" name="ubuntu_images" value="1" />
325- {% if user.is_superuser and not region_import_running %}
326- <div class="row">
327- {% if connection_error %}
328- <div id="connection-error" class="images-warning">
329- Connection Error: Unable to retrieve image information from
330- boot sources.
331- </div>
332- {% else %}
333- {% if ubuntu_streams_count == 0 %}
334- <div id="no-ubuntu-sources" class="images-warning">
335- Error: No boot sources provide Ubuntu images.
336- </div>
337- {% elif ubuntu_streams_count == 1 %}
338- <div class="col2">
339- <div class="space-bottom-small">Release:</div>
340- <ul id="ubuntu-releases" class="data-list">
341- {% for release in ubuntu_releases %}
342- <li><input type="checkbox" name="release"
343- value="{{release.name}}"
344- {% if release.checked %}checked="checked"{% endif %}>
345- {{release.title}}</li>
346- {% endfor %}
347- </ul>
348- </div>
349- <div class="col10 last">
350- <div class="space-bottom-small">Architecture:</div>
351- <ul id="ubuntu-arches" class="data-list">
352- {% for arch in ubuntu_arches %}
353- <li><input type="checkbox" name="arch"
354- value="{{arch.name}}"
355- {% if arch.checked %}checked="checked"{% endif %}>
356- {{arch.title}}</li>
357- {% endfor %}
358- </ul>
359- </div>
360- {% else %}
361- <div id="too-many-ubuntu-sources" class="images-warning">
362- More than one boot source is providing Ubuntu images. Image
363- selection cannot be performed using the WebUI.
364- </div>
365- {% endif %}
366- {% endif %}
367- </div>
368- <div class="clear"></div>
369- {% endif %}
370+ {% if generated_resources %}
371+ <div id="generated-images" class="section">
372+ <h2>Generated Images</h2>
373+ <div class="content">
374 <div class="row space-top">
375- {% if ubuntu_resources|length %}
376- <table id="ubuntu-resources" class="space-top list">
377+ <table id="generated-resources" class="space-top list">
378 <thead>
379 <tr>
380 <th class="spinner-col"></th>
381- <th>Release</th>
382+ <th>Name</th>
383 <th>Architecture</th>
384 <th>Size</th>
385 <th>Nodes deployed</th>
386@@ -168,7 +302,7 @@
387 </tr>
388 </thead>
389 <tbody>
390- {% for resource in ubuntu_resources %}
391+ {% for resource in generated_resources %}
392 <tr
393 class="{% cycle 'even' 'odd' %}"
394 data-id="{{ resource.id }}">
395@@ -182,7 +316,18 @@
396 </div>
397 {% endif %}
398 </td>
399- <td>{{ resource.title }}</td>
400+ <td>{{ resource.title }}
401+ {% if user.is_superuser %}
402+ <a
403+ title="Delete image"
404+ href="{% url 'image-delete' resource.id %}">
405+ <img
406+ class="small-icon"
407+ src="{{ STATIC_URL }}img/delete.png"
408+ alt="delete" />
409+ </a>
410+ {% endif %}
411+ </td>
412 <td>{{ resource.arch }}</td>
413 <td>{{ resource.size }}</td>
414 <td>{{ resource.number_of_nodes }}</td>
415@@ -191,46 +336,22 @@
416 {% endfor %}
417 </tbody>
418 </table>
419- {% else %}
420- <div id="missing-ubuntu-images" class="images-warning">
421- No Ubuntu images have been imported. Ubuntu images are required
422- to allow nodes to enlist, commission, and install.</div>
423- {% endif %}
424- </div>
425- <div class="clear"></div>
426- <div class="row space-top end-row">
427- {% if user.is_superuser and not region_import_running %}
428- <div class="col12 last align-right">
429- {% if ubuntu_streams_count == 1 %}
430- {% if ubuntu_resources|length %}
431- <input type="submit" class="button" value="Apply changes">
432- {% else %}
433- <input type="submit" class="button" value="Import images">
434- {% endif %}
435- {% elif ubuntu_streams_count > 1 %}
436- <input type="submit" class="button" value="Import images">
437- {% endif %}
438- </div>
439- {% endif %}
440- </div>
441- <div class="clear"></div>
442- </form>
443+ </div>
444+ <div class="clear"></div>
445+ <div class="row space-top end-row"></div>
446+ <div class="clear"></div>
447+ </div>
448 </div>
449- </div>
450- {% if other_resources %}
451- <div id="other-sync-images" class="section">
452- <h2>Other Images</h2>
453- <div class="content">
454- <form id="other_images"
455- method="POST"
456- action="{% url 'images' %}">
457- {% csrf_token %}
458- <input type="hidden" name="other_images" value="1" />
459+ {% endif %}
460+ <div id="custom-images" class="section">
461+ <h2>Custom Images</h2>
462+ <div class="content">
463 <div class="row space-top">
464- <table id="other-resources" class="space-top list">
465+ {% if uploaded_resources|length %}
466+ <table id="uploaded-resources" class="space-top list">
467 <thead>
468 <tr>
469- <th class="spinner-col"></th>
470+ <th></th>
471 <th>Name</th>
472 <th>Architecture</th>
473 <th>Size</th>
474@@ -239,12 +360,9 @@
475 </tr>
476 </thead>
477 <tbody>
478- {% for resource in other_resources %}
479- <tr
480- class="{% cycle 'even' 'odd' %}"
481- data-id="{% if resource.id %}{{ resource.id }}{% endif %}">
482+ {% for resource in uploaded_resources %}
483+ <tr class="{% cycle 'even' 'odd' %}">
484 <td>
485- {% if region_import_running and resource.exists %}
486 {% if not resource.complete %}
487 <div
488 title="{{ resource.status }}"
489@@ -253,154 +371,35 @@
490 {% if resource.downloading %}spin{% endif %}">
491 </div>
492 {% endif %}
493- {% elif not region_import_running and user.is_superuser %}
494- <input
495- type="checkbox"
496- name="image"
497- value="{{ resource.os }}/{{ resource.arch }}/{{ resource.subarch }}/{{ resource.release }}"
498- {% if resource.exists %}
499- checked="checked"
500- {% endif %}
501- >
502+ </td>
503+ <td>{{ resource.title }}
504+ {% if user.is_superuser %}
505+ <a
506+ title="Delete image"
507+ href="{% url 'image-delete' resource.id %}">
508+ <img
509+ class="small-icon"
510+ src="{{ STATIC_URL }}img/delete.png"
511+ alt="delete" />
512+ </a>
513 {% endif %}
514 </td>
515- <td>{{ resource.title }}</td>
516 <td>{{ resource.arch }}</td>
517 <td>{{ resource.size }}</td>
518 <td>{{ resource.number_of_nodes }}</td>
519 <td>{{ resource.last_update }}</td>
520 </tr>
521- {% endfor %}
522+ {% endfor %}
523 </tbody>
524 </table>
525- </div>
526- <div class="clear"></div>
527- <div class="row space-top end-row">
528- {% if user.is_superuser and not region_import_running %}
529- <div class="col12 last align-right">
530- <input type="submit" class="button" value="Apply changes">
531+ {% else %}
532+ <div id="no-custom-images" class="images-info">
533+ No custom images have been uploaded.
534 </div>
535 {% endif %}
536 </div>
537 <div class="clear"></div>
538- </form>
539- </div>
540- </div>
541- {% endif %}
542- {% if generated_resources %}
543- <div id="generated-images" class="section">
544- <h2>Generated Images</h2>
545- <div class="content">
546- <div class="row space-top">
547- <table id="generated-resources" class="space-top list">
548- <thead>
549- <tr>
550- <th class="spinner-col"></th>
551- <th>Name</th>
552- <th>Architecture</th>
553- <th>Size</th>
554- <th>Nodes deployed</th>
555- <th>Last update</th>
556- </tr>
557- </thead>
558- <tbody>
559- {% for resource in generated_resources %}
560- <tr
561- class="{% cycle 'even' 'odd' %}"
562- data-id="{{ resource.id }}">
563- <td>
564- {% if not resource.complete %}
565- <div
566- title="{{ resource.status }}"
567- class="
568- spinner
569- {% if resource.downloading %}spin{% endif %}">
570- </div>
571- {% endif %}
572- </td>
573- <td>{{ resource.title }}
574- {% if user.is_superuser %}
575- <a
576- title="Delete image"
577- href="{% url 'image-delete' resource.id %}">
578- <img
579- class="small-icon"
580- src="{{ STATIC_URL }}img/delete.png"
581- alt="delete" />
582- </a>
583- {% endif %}
584- </td>
585- <td>{{ resource.arch }}</td>
586- <td>{{ resource.size }}</td>
587- <td>{{ resource.number_of_nodes }}</td>
588- <td>{{ resource.last_update }}</td>
589- </tr>
590- {% endfor %}
591- </tbody>
592- </table>
593- </div>
594- <div class="clear"></div>
595- <div class="row space-top end-row"></div>
596- <div class="clear"></div>
597- </div>
598- </div>
599- {% endif %}
600- <div id="custom-images" class="section">
601- <h2>Custom Images</h2>
602- <div class="content">
603- <div class="row space-top">
604- {% if uploaded_resources|length %}
605- <table id="uploaded-resources" class="space-top list">
606- <thead>
607- <tr>
608- <th></th>
609- <th>Name</th>
610- <th>Architecture</th>
611- <th>Size</th>
612- <th>Nodes deployed</th>
613- <th>Last update</th>
614- </tr>
615- </thead>
616- <tbody>
617- {% for resource in uploaded_resources %}
618- <tr class="{% cycle 'even' 'odd' %}">
619- <td>
620- {% if not resource.complete %}
621- <div
622- title="{{ resource.status }}"
623- class="
624- spinner
625- {% if resource.downloading %}spin{% endif %}">
626- </div>
627- {% endif %}
628- </td>
629- <td>{{ resource.title }}
630- {% if user.is_superuser %}
631- <a
632- title="Delete image"
633- href="{% url 'image-delete' resource.id %}">
634- <img
635- class="small-icon"
636- src="{{ STATIC_URL }}img/delete.png"
637- alt="delete" />
638- </a>
639- {% endif %}
640- </td>
641- <td>{{ resource.arch }}</td>
642- <td>{{ resource.size }}</td>
643- <td>{{ resource.number_of_nodes }}</td>
644- <td>{{ resource.last_update }}</td>
645- </tr>
646- {% endfor %}
647- </tbody>
648- </table>
649- {% else %}
650- <div id="no-custom-images" class="images-info">
651- No custom images have been uploaded.
652- </div>
653- {% endif %}
654- </div>
655- <div class="clear"></div>
656+ </div>
657 </div>
658 </div>
659 {% endblock %}
660
661=== modified file 'src/maasserver/templates/maasserver/js-conf.html'
662--- src/maasserver/templates/maasserver/js-conf.html 2012-06-26 09:47:31 +0000
663+++ src/maasserver/templates/maasserver/js-conf.html 2014-10-02 18:55:55 +0000
664@@ -14,7 +14,8 @@
665 statics: '{{ STATIC_URL }}',
666 maas_handler: '{% url "maas_handler" %}',
667 nodes_handler: '{% url "nodes_handler" %}',
668- account_handler: '{% url "account_handler" %}'
669+ account_handler: '{% url "account_handler" %}',
670+ images_handler: '{% url "images" %}'
671 },
672 debug: {% if YUI_DEBUG %}true{% else %}false{% endif %}
673 };
674
675=== modified file 'src/maasserver/views/images.py'
676--- src/maasserver/views/images.py 2014-10-02 18:55:55 +0000
677+++ src/maasserver/views/images.py 2014-10-02 18:55:55 +0000
678@@ -140,7 +140,6 @@
679 context['ubuntu_streams_count'] = len(self.ubuntu_sources)
680 context['ubuntu_releases'] = self.format_ubuntu_releases()
681 context['ubuntu_arches'] = self.format_ubuntu_arches()
682- context['ubuntu_resources'] = self.get_ubuntu_resources()
683 context['other_resources'] = self.get_other_resources()
684 context['generated_resources'] = self.get_generated_resources()
685 context['uploaded_resources'] = self.get_uploaded_resources()
686@@ -247,15 +246,6 @@
687 else:
688 return resource.name
689
690- def get_ubuntu_resources(self):
691- """Return all Ubuntu resources, for usage in the template."""
692- resources = list(BootResource.objects.filter(
693- rtype=BOOT_RESOURCE_TYPE.SYNCED,
694- name__startswith='ubuntu/').order_by('-name', 'architecture'))
695- for resource in resources:
696- self.add_resource_template_attributes(resource)
697- return resources
698-
699 def add_resource_template_attributes(self, resource):
700 """Adds helper attributes to the resource."""
701 resource.title = self.get_resource_title(resource)
702
703=== modified file 'src/maasserver/views/tests/test_images.py'
704--- src/maasserver/views/tests/test_images.py 2014-10-02 18:55:55 +0000
705+++ src/maasserver/views/tests/test_images.py 2014-10-02 18:55:55 +0000
706@@ -43,7 +43,6 @@
707 )
708 from requests import ConnectionError
709 from testtools.matchers import (
710- Contains,
711 ContainsAll,
712 HasLength,
713 )
714@@ -62,17 +61,6 @@
715 mock_get_os_info.return_value = (sources, releases, arches)
716 return mock_get_os_info
717
718- def make_ubuntu_resource(self, release=None):
719- if release is None:
720- release = factory.make_name('release')
721- name = 'ubuntu/%s' % release
722- arch = factory.make_name('arch')
723- subarch = factory.make_name('subarch')
724- architecture = '%s/%s' % (arch, subarch)
725- return factory.make_usable_boot_resource(
726- rtype=BOOT_RESOURCE_TYPE.SYNCED,
727- name=name, architecture=architecture)
728-
729 def test_shows_connection_error(self):
730 self.client_log_in(as_admin=True)
731 mock_get_os_info = self.patch(
732@@ -128,83 +116,6 @@
733 warnings = doc.cssselect('div#missing-ubuntu-images')
734 self.assertEqual(1, len(warnings))
735
736- def test_shows_ubuntu_resources(self):
737- self.client_log_in()
738- releases = [factory.make_name('release') for _ in range(3)]
739- [self.make_ubuntu_resource(release) for release in releases]
740- response = self.client.get(reverse('images'))
741- doc = fromstring(response.content)
742- table_content = doc.cssselect(
743- 'table#ubuntu-resources')[0].text_content()
744- self.assertThat(table_content, ContainsAll(releases))
745-
746- def test_shows_ubuntu_release_version_name(self):
747- self.client_log_in()
748- # Use trusty as known to map to "14.04 LTS"
749- release = 'trusty'
750- version = '14.04 LTS'
751- self.make_ubuntu_resource(release)
752- response = self.client.get(reverse('images'))
753- doc = fromstring(response.content)
754- table_content = doc.cssselect(
755- 'table#ubuntu-resources')[0].text_content()
756- self.assertThat(table_content, Contains(version))
757-
758- def test_shows_number_of_nodes_deployed_for_ubuntu_resource(self):
759- self.client_log_in()
760- resource = self.make_ubuntu_resource()
761- os_name, series = resource.name.split('/')
762- number_of_nodes = random.randint(1, 4)
763- for _ in range(number_of_nodes):
764- factory.make_Node(
765- status=NODE_STATUS.DEPLOYED,
766- osystem=os_name, distro_series=series,
767- architecture=resource.architecture)
768- response = self.client.get(reverse('images'))
769- doc = fromstring(response.content)
770- count = int(doc.cssselect(
771- 'table#ubuntu-resources > tbody > tr > td')[4].text_content())
772- self.assertEqual(number_of_nodes, count)
773-
774- def test_shows_number_of_default_nodes_deployed_for_ubuntu_resource(self):
775- self.client_log_in()
776- resource = self.make_ubuntu_resource()
777- os_name, series = resource.name.split('/')
778- Config.objects.set_config('default_osystem', os_name)
779- Config.objects.set_config('default_distro_series', series)
780- number_of_nodes = random.randint(1, 4)
781- for _ in range(number_of_nodes):
782- factory.make_Node(
783- status=NODE_STATUS.DEPLOYED,
784- architecture=resource.architecture)
785- response = self.client.get(reverse('images'))
786- doc = fromstring(response.content)
787- count = int(doc.cssselect(
788- 'table#ubuntu-resources > tbody > tr > td')[4].text_content())
789- self.assertEqual(number_of_nodes, count)
790-
791- def test_shows_number_of_nodes_deployed_for_ubuntu_subarch_resource(self):
792- self.client_log_in()
793- resource = self.make_ubuntu_resource()
794- arch, subarch = resource.split_arch()
795- extra_subarch = factory.make_name('subarch')
796- resource.extra['subarches'] = ','.join([subarch, extra_subarch])
797- resource.save()
798-
799- os_name, series = resource.name.split('/')
800- node_architecture = '%s/%s' % (arch, extra_subarch)
801- number_of_nodes = random.randint(1, 4)
802- for _ in range(number_of_nodes):
803- factory.make_Node(
804- status=NODE_STATUS.DEPLOYED,
805- osystem=os_name, distro_series=series,
806- architecture=node_architecture)
807- response = self.client.get(reverse('images'))
808- doc = fromstring(response.content)
809- count = int(doc.cssselect(
810- 'table#ubuntu-resources > tbody > tr > td')[4].text_content())
811- self.assertEqual(number_of_nodes, count)
812-
813 def test_hides_import_button_if_not_admin(self):
814 self.client_log_in()
815 sources = [factory.make_BootSource()]
816@@ -225,18 +136,6 @@
817 '#ubuntu-images')[0].cssselect('input[type="submit"]')
818 self.assertEqual(1, len(import_button))
819
820- def test_hides_import_button_if_import_running(self):
821- self.client_log_in()
822- sources = [factory.make_BootSource()]
823- self.patch_get_os_info_from_boot_sources(sources)
824- self.patch(
825- images_view, 'is_import_resources_running').return_value = True
826- response = self.client.get(reverse('images'))
827- doc = fromstring(response.content)
828- import_button = doc.cssselect(
829- '#ubuntu-images')[0].cssselect('input[type="submit"]')
830- self.assertEqual(0, len(import_button))
831-
832 def test_post_returns_forbidden_if_not_admin(self):
833 self.client_log_in()
834 response = self.client.post(