~ubuntu-branches/ubuntu/utopic/maas/utopic-security

1.3.1 by Andres Rodriguez
Import upstream version 1.7.0~beta7+bzr3266
1
/* Copyright 2014 Canonical Ltd.  This software is licensed under the
2
 * GNU Affero General Public License version 3 (see the file LICENSE).
3
 *
4
 * Image views.
5
 *
6
 * @module Y.maas.image_views
7
 */
8
9
YUI.add('maas.image_views', function(Y) {
10
11
Y.log('loading maas.image_views');
12
var module = Y.namespace('maas.image_views');
13
14
var BOOT_RESOURCE_TYPE = Y.maas.enums.BOOT_RESOURCE_TYPE;
15
16
17
/**
18
 * A base view class to display a set of Images (Y.maas.image.Image).
19
 *
20
 * It will load the list of images (in this.modelList) when rendered
21
 * for the first time and changes to this.modelList will trigger
22
 * re-rendering.
23
 *
24
 * You can provide your custom rendering method by defining a 'render'
25
 * method (also, you can provide methods named 'loadImagesStarted' and
26
 * 'loadImagesEnded' to customize the display during the initial loading of the
27
 * visible images and a method named 'displayGlobalError' to display a message
28
 * when errors occur during loading).
29
 *
30
 */
31
module.ImageListLoader = Y.Base.create('imageListLoader', Y.View, [], {
32
33
    initializer: function(config) {
34
        this.modelList = new Y.maas.image.ImageList();
35
        this.loaded = false;
36
    },
37
38
    render: function () {
39
    },
40
41
    /**
42
     * Add a loader, a Y.IO object. Events fired by this IO object will
43
     * be followed, and will drive updates to this object's model.
44
     *
45
     * It may be wiser to remodel this to consume a YUI DataSource. That
46
     * would make testing easier, for one, but it would also mean we can
47
     * eliminate our polling code: DataSource has support for polling
48
     * via the datasource-polling module.
49
     *
50
     * @method addLoader
51
     */
52
    addLoader: function(loader) {
53
        loader.on("io:start", this.loadImagesStarted, this);
54
        loader.on("io:end", this.loadImagesEnded, this);
55
        loader.on("io:failure", this.loadImagesFailed, this);
56
        loader.on("io:success", function(id, request) {
57
            this.loadImages(request.responseText);
58
        }, this);
59
    },
60
61
    /**
62
     * Load the images from the given data.
63
     *
64
     * @method loadImages
65
     */
66
    loadImages: function(data) {
67
        try {
68
            var parsed = JSON.parse(data);
69
            this.regionImportRunning = parsed.region_import_running;
70
            this.clusterImportRunning = parsed.cluster_import_running;
71
            this.mergeImages(parsed.resources);
72
        }
73
        catch(e) {
74
            this.loadImagesFailed();
75
        }
76
        this.loaded = true;
77
        this.render();
78
    },
79
80
    /**
81
     * Process an array of images, merging them into modelList with the
82
     * fewest modifications possible.
83
     *
84
     * @method mergeImages
85
     */
86
    mergeImages: function(images) {
87
        var self = this;
88
        var imagesByID = {};
89
        Y.Array.each(images, function(image) {
90
            imagesByID[image.id] = image;
91
        });
92
        var modelsByID = {};
93
        this.modelList.each(function(model) {
94
            modelsByID[model.get("id")] = model;
95
        });
96
97
        Y.each(imagesByID, function(image, id) {
98
            var model = modelsByID[id];
99
            if (Y.Lang.isValue(model)) {
100
                // Compare the image and the model.
101
                var modelAttrs = model.getAttrs();
102
                var modelChanges = {};
103
                Y.each(modelAttrs, function(value, key) {
104
                    if (image[key] !== value) {
105
                        modelChanges[key] = image[key];
106
                    }
107
                });
108
                // Update the image.
109
                model.setAttrs(modelChanges);
110
            }
111
            else {
112
                // Add the image.
113
                self.modelList.add(image);
114
            }
115
        });
116
117
        Y.each(modelsByID, function(model, id) {
118
            // Remove models that don't correspond to a image.
119
            if (!Y.Object.owns(imagesByID, id)) {
120
                self.modelList.remove(model);
121
            }
122
        });
123
    },
124
125
   /**
126
    * Function called if an error occurs during the initial loading.
127
    *
128
    * @method displayGlobalError
129
    */
130
    displayGlobalError: function (error_message) {
131
    },
132
133
   /**
134
    * Function called when the Image list starts loading.
135
    *
136
    * @method loadImagesStarted
137
    */
138
    loadImagesStarted: function() {
139
    },
140
141
   /**
142
    * Function called when the Image list has loaded.
143
    *
144
    * @method loadImagesEnded
145
    */
146
    loadImagesEnded: function() {
147
    },
148
149
    /**
150
     * Function called when the Image list failed to load.
151
     *
152
     * @method loadImagesFailed
153
     */
154
    loadImagesFailed: function() {
155
        this.displayGlobalError('Unable to load boot images.');
156
    }
157
158
});
159
160
/**
161
 * A customized view based on ImageListLoader that will display the
162
 * images view.
163
 */
164
module.ImagesView = Y.Base.create(
165
    'imagesView', module.ImageListLoader, [], {
166
167
    regionImportingText: 'Step 1/2: Region importing',
168
    clusterImportingText: 'Step 2/2: Clusters importing',
169
170
171
    initializer: function(config) {
172
        this.srcNode = Y.one(config.srcNode);
173
        this.loader = this.srcNode.one(config.loader);
174
        this.content = this.srcNode.one(config.content);
175
        this.importer = this.srcNode.one(config.importer);
176
        this.ubuntuOptions = this.srcNode.one(config.ubuntuOptions);
177
        this.ubuntuSpinner = this.srcNode.one(config.ubuntuSpinner);
178
        this.ubuntuTable = this.srcNode.one(config.ubuntuTable);
179
        this.ubuntuMissingImages = this.srcNode.one(config.ubuntuMissingImages);
180
        this.ubuntuButton = this.srcNode.one(config.ubuntuButton);
181
    },
182
183
   /**
184
    * Return all Ubuntu images.
185
    *
186
    * @ method getUbuntuImages
187
    */
188
    getUbuntuImages: function() {
189
        images = this.modelList.filter(function(model) {
190
            return model.get('rtype') === BOOT_RESOURCE_TYPE.SYNCED &&
191
                model.get('name').indexOf('ubuntu/') === 0;
192
        });
193
        // Sort the images decending, so newest Ubuntu version is on top.
194
        images.sort(function(a, b) {
195
            return -(a.get('title').localeCompare(b.get('title')));
196
        });
197
        return images;
198
    },
199
200
   /**
201
    * Display images page.
202
    *
203
    * @method render
204
    */
205
    render: function () {
206
        if(!this.loaded) {
207
            this.loader.removeClass('hidden');
208
            this.content.addClass('hidden');
209
        } else {
210
            this.loader.addClass('hidden');
211
            this.content.removeClass('hidden');
212
        }
213
        this.renderImporting();
214
        this.renderUbuntuView();
215
    },
216
217
   /**
218
    * Render the importing header.
219
    *
220
    * @method renderUbuntuView
221
    */
222
    renderImporting: function() {
223
        var importingText = this.importer.one('.importing-text');
224
        if(!this.regionImportRunning && !this.clusterImportRunning) {
225
            this.importer.addClass('hidden');
226
            importingText.setContent('');
227
        } else if (this.regionImportRunning) {
228
            this.importer.removeClass('hidden');
229
            importingText.setContent(this.regionImportingText);
230
        } else if (this.clusterImportRunning) {
231
            this.importer.removeClass('hidden');
232
            importingText.setContent(this.clusterImportingText);
233
        }
234
    },
235
236
   /**
237
    * Render the Ubuntu section of the view.
238
    *
239
    * @method renderUbuntuView
240
    */
241
    renderUbuntuView: function() {
242
        if(this.regionImportRunning) {
243
            if(Y.Lang.isValue(this.ubuntuOptions)) {
244
                this.ubuntuOptions.addClass('hidden');
245
            }
246
            if(Y.Lang.isValue(this.ubuntuButton)) {
247
                this.ubuntuButton.addClass('hidden');
248
            }
249
        } else {
250
            if(Y.Lang.isValue(this.ubuntuOptions)) {
251
                this.ubuntuOptions.removeClass('hidden');
252
            }
253
            if(Y.Lang.isValue(this.ubuntuButton)) {
254
                this.ubuntuButton.removeClass('hidden');
255
            }
256
        }
257
        var ubuntuImages = this.getUbuntuImages();
258
        if(ubuntuImages.length === 0) {
259
            this.ubuntuMissingImages.removeClass('hidden');
260
            this.ubuntuTable.addClass('hidden');
261
            this.updateUbuntuButton(false);
262
        } else {
263
            this.ubuntuMissingImages.addClass('hidden');
264
            this.ubuntuTable.removeClass('hidden');
265
            this.updateUbuntuButton(true);
266
        }
267
        var self = this;
268
        var innerTable = "";
269
        Y.each(ubuntuImages, function(model) {
270
            innerTable += "<tr><td>" + self.getSpinner(model) + "</td>";
271
            innerTable += "<td>" + model.get('title') + "</td>";
272
            innerTable += "<td>" + model.get('arch') + "</td>";
273
            innerTable += "<td>" + model.get('size') + "</td>";
274
            innerTable += "<td>" + model.get('numberOfNodes') + "</td>";
275
            innerTable += "<td>" + model.get('lastUpdate') + "</td>";
276
            innerTable += "</tr>";
277
        });
278
        this.ubuntuTable.one('tbody').setHTML(innerTable);
279
    },
280
281
   /**
282
    * Update the value of the ubuntuButton.
283
    *
284
    * The value of the button can be locked meaning it should not change, this
285
    * is done using the data attribute lock-value. data-lock-value="true"
286
    *
287
    * @method updateUbuntuButton
288
    */
289
    updateUbuntuButton: function(showApply) {
290
        if(!Y.Lang.isValue(this.ubuntuButton)) {
291
            return;
292
        }
293
        if(this.ubuntuButton.getData('lock-value') === "true") {
294
            return;
295
        }
296
        if(showApply) {
297
            this.ubuntuButton.set('value', 'Apply changes');
298
        }
299
        else {
300
            this.ubuntuButton.set('value', 'Import images');
301
        }
302
    },
303
304
   /**
305
    * Return the HTML for the downloading spinner for the given model.
306
    *
307
    * @method getSpinner
308
    */
309
    getSpinner: function(model) {
310
        // Spinner is not rendered when the model is complete.
311
        if(model.get('complete')) {
312
            return '';
313
        }
314
        html = '<div title="' + model.get('status') + '" class="spinner';
315
        if(model.get('downloading')) {
316
            html += ' spin';
317
        }
318
        html += '"></div>';
319
        return html;
320
    }
321
});
322
323
}, '0.1', {'requires': [
324
    'view', 'io', 'maas.enums', 'maas.image']}
325
);