Merge lp:~hatch/juju-gui/import-bundle-btn into lp:juju-gui/experimental
- import-bundle-btn
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1187 |
Proposed branch: | lp:~hatch/juju-gui/import-bundle-btn |
Merge into: | lp:juju-gui/experimental |
Diff against target: |
440 lines (+108/-204) 9 files modified
app/app.js (+20/-2) app/assets/javascripts/bundle-import-extension.js (+73/-0) app/index.html (+1/-0) app/modules-debug.js (+4/-4) app/views/topology/importexport.js (+0/-151) app/views/topology/service.js (+8/-40) app/views/topology/topology.js (+0/-1) bin/merge-files (+1/-0) lib/views/stylesheet.less (+1/-6) |
To merge this branch: | bzr merge lp:~hatch/juju-gui/import-bundle-btn |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju GUI Hackers | Pending | ||
Review via email:
|
Commit message
Description of the change
Adds support for bundle import button
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jeff Pihach (hatch) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Richard Harding (rharding) wrote : | # |
code looks ok. Looks like some movement. You said there were tests, but
it seems like it'd be a good idea to create a test file for the new
extension module created out of the code revamp. Will QA next.
https:/
File app/index.html (right):
https:/
app/index.html:143:
should we #id this since we only expect one?
https:/
File bin/merge-files (right):
https:/
bin/merge-files:91:
is it not picked up by the deps on app.js?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Richard Harding (rharding) wrote : | # |
QA:
We should have a title="" on the buttons to give hints that they're
import/export controls.
QA ok
LGTM
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jeff Pihach (hatch) wrote : | # |
Thanks for the review! Changes made
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jeff Pihach (hatch) wrote : | # |
*** Submitted:
Adds support for bundle import button
R=rharding
CC=
https:/
Preview Diff
1 | === modified file 'app/app.js' |
2 | --- app/app.js 2013-11-06 17:12:26 +0000 |
3 | +++ app/app.js 2013-11-07 16:02:07 +0000 |
4 | @@ -51,7 +51,8 @@ |
5 | Y.juju.SubAppRegistration, |
6 | Y.juju.NSRouter, |
7 | Y.juju.Cookies, |
8 | - Y.juju.GhostDeployer], { |
9 | + Y.juju.GhostDeployer, |
10 | + Y.juju.BundleImport], { |
11 | |
12 | /* |
13 | Extension properties |
14 | @@ -567,6 +568,22 @@ |
15 | }, this); |
16 | } |
17 | |
18 | + var importNode = Y.one('#import-trigger'); |
19 | + var importFileInput = Y.one('.import-export input[type=file]'); |
20 | + // Tests won't have this node. |
21 | + if (importNode && importFileInput) { |
22 | + importNode.on('click', function(e) { |
23 | + e.halt(); |
24 | + e.currentTarget.siblings('input[type=file]') |
25 | + .item(0).getDOMNode().click(); |
26 | + }); |
27 | + |
28 | + importFileInput.on('change', function(e) { |
29 | + this.sendToDeployer(this.env, this.db, |
30 | + e.currentTarget.get('files')._nodes); |
31 | + }, this); |
32 | + } |
33 | + |
34 | // Attach SubApplications. The subapps should share the same db. |
35 | cfg.db = this.db; |
36 | |
37 | @@ -1345,6 +1362,7 @@ |
38 | 'juju-inspector-widget', |
39 | 'juju-ghost-inspector', |
40 | 'juju-view-bundle', |
41 | - 'viewmode-controls' |
42 | + 'viewmode-controls', |
43 | + 'bundle-import-extension' |
44 | ] |
45 | }); |
46 | |
47 | === added file 'app/assets/javascripts/bundle-import-extension.js' |
48 | --- app/assets/javascripts/bundle-import-extension.js 1970-01-01 00:00:00 +0000 |
49 | +++ app/assets/javascripts/bundle-import-extension.js 2013-11-07 16:02:07 +0000 |
50 | @@ -0,0 +1,73 @@ |
51 | +/* |
52 | +This file is part of the Juju GUI, which lets users view and manage Juju |
53 | +environments within a graphical interface (https://launchpad.net/juju-gui). |
54 | +Copyright (C) 2012-2013 Canonical Ltd. |
55 | + |
56 | +This program is free software: you can redistribute it and/or modify it under |
57 | +the terms of the GNU Affero General Public License version 3, as published by |
58 | +the Free Software Foundation. |
59 | + |
60 | +This program is distributed in the hope that it will be useful, but WITHOUT |
61 | +ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
62 | +SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero |
63 | +General Public License for more details. |
64 | + |
65 | +You should have received a copy of the GNU Affero General Public License along |
66 | +with this program. If not, see <http://www.gnu.org/licenses/>. |
67 | +*/ |
68 | + |
69 | +'use strict'; |
70 | + |
71 | +YUI.add('bundle-import-extension', function(Y) { |
72 | + |
73 | + function BundleImport() {} |
74 | + |
75 | + BundleImport.prototype = { |
76 | + |
77 | + sendToDeployer: function(env, db, fileSources) { |
78 | + var notifications = db.notifications; |
79 | + if (!Y.Lang.isFunction(env.deployerImport)) { |
80 | + // Notify the user that their environment is too old and return. |
81 | + notifications.add({ |
82 | + title: 'Deployer Import Unsupported', |
83 | + message: 'Your environment is too old to support deployer file' + |
84 | + ' imports directly. Please consider upgrading to use' + |
85 | + ' this feature.', |
86 | + level: 'important' |
87 | + }); |
88 | + return; |
89 | + } |
90 | + // Handle dropping Deployer files on the canvas. |
91 | + Y.Array.each(fileSources, function(file) { |
92 | + var reader = new FileReader(); |
93 | + reader.onload = function(e) { |
94 | + // Import each into the environment |
95 | + env.deployerImport(e.target.result, null, function(result) { |
96 | + if (!result.err) { |
97 | + notifications.add({ |
98 | + title: 'Imported Deployer file', |
99 | + message: 'Import from "' + file.name + '" successful. This ' + |
100 | + 'can take some time to complete.', |
101 | + level: 'important' |
102 | + }); |
103 | + } else { |
104 | + console.warn('import failed', file, result); |
105 | + notifications.add({ |
106 | + title: 'Import Environment Failed', |
107 | + message: 'Import from "' + file.name + |
108 | + '" failed.<br/>' + result.err, |
109 | + level: 'error' |
110 | + }); |
111 | + } |
112 | + }); |
113 | + }; |
114 | + reader.readAsText(file); |
115 | + }); |
116 | + } |
117 | + }; |
118 | + |
119 | + Y.namespace('juju').BundleImport = BundleImport; |
120 | + |
121 | + |
122 | +}); |
123 | + |
124 | |
125 | === modified file 'app/index.html' |
126 | --- app/index.html 2013-10-31 03:28:32 +0000 |
127 | +++ app/index.html 2013-11-07 16:02:07 +0000 |
128 | @@ -140,6 +140,7 @@ |
129 | <i class="sprite icon-import-normal normal"></i> |
130 | <i class="sprite icon-import-hover hover"></i> |
131 | </a> |
132 | + <input type="file" /> |
133 | <a href="" id="export-trigger"> |
134 | <i class="sprite icon-export-normal normal"></i> |
135 | <i class="sprite icon-export-hover hover"></i> |
136 | |
137 | === modified file 'app/modules-debug.js' |
138 | --- app/modules-debug.js 2013-11-04 02:17:54 +0000 |
139 | +++ app/modules-debug.js 2013-11-07 16:02:07 +0000 |
140 | @@ -181,6 +181,10 @@ |
141 | fullpath: '/juju-ui/assets/javascripts/app-cookies-extension.js' |
142 | }, |
143 | |
144 | + 'bundle-import-extension': { |
145 | + fullpath: '/juju-ui/assets/javascripts/bundle-import-extension.js' |
146 | + }, |
147 | + |
148 | 'sub-app': { |
149 | fullpath: '/juju-ui/assets/javascripts/sub-app.js' |
150 | }, |
151 | @@ -210,10 +214,6 @@ |
152 | fullpath: '/juju-ui/views/topology/service.js' |
153 | }, |
154 | |
155 | - 'juju-topology-importexport': { |
156 | - fullpath: '/juju-ui/views/topology/importexport.js' |
157 | - }, |
158 | - |
159 | 'juju-topology-utils': { |
160 | fullpath: '/juju-ui/views/topology/utils.js' |
161 | }, |
162 | |
163 | === removed file 'app/views/topology/importexport.js' |
164 | --- app/views/topology/importexport.js 2013-08-08 22:36:30 +0000 |
165 | +++ app/views/topology/importexport.js 1970-01-01 00:00:00 +0000 |
166 | @@ -1,151 +0,0 @@ |
167 | -/* |
168 | -This file is part of the Juju GUI, which lets users view and manage Juju |
169 | -environments within a graphical interface (https://launchpad.net/juju-gui). |
170 | -Copyright (C) 2012-2013 Canonical Ltd. |
171 | - |
172 | -This program is free software: you can redistribute it and/or modify it under |
173 | -the terms of the GNU Affero General Public License version 3, as published by |
174 | -the Free Software Foundation. |
175 | - |
176 | -This program is distributed in the hope that it will be useful, but WITHOUT |
177 | -ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
178 | -SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero |
179 | -General Public License for more details. |
180 | - |
181 | -You should have received a copy of the GNU Affero General Public License along |
182 | -with this program. If not, see <http://www.gnu.org/licenses/>. |
183 | -*/ |
184 | - |
185 | -'use strict'; |
186 | - |
187 | -/** |
188 | - * Provide the ImportExportModule class. |
189 | - * |
190 | - * @module topology |
191 | - * @submodule topology.importexport |
192 | - */ |
193 | - |
194 | -YUI.add('juju-topology-importexport', function(Y) { |
195 | - var views = Y.namespace('juju.views'), |
196 | - models = Y.namespace('juju.models'), |
197 | - d3ns = Y.namespace('d3'); |
198 | - |
199 | - /** |
200 | - * Handle ImportExport from the Topology. |
201 | - * |
202 | - * @class ImportExportModule |
203 | - */ |
204 | - var ImportExportModule = Y.Base.create('ImportExportModule', |
205 | - d3ns.Module, [], { |
206 | - events: { |
207 | - scene: { |
208 | - '.zoom-plane': { |
209 | - drop: '_handleFileDrop' |
210 | - } |
211 | - } |
212 | - }, |
213 | - |
214 | - /** |
215 | - * Handle file drops with HTML5 reader api |
216 | - * |
217 | - * @method _handleFileDrop |
218 | - */ |
219 | - _handleFileDrop: function(box, self) { |
220 | - // This handler uses the HTML5 File |
221 | - // API for DnD support. This event |
222 | - // doesn't properly appear in the YUI |
223 | - // event wrrapper so we extract it directly |
224 | - // from the DOM event. |
225 | - var evt = d3.event, |
226 | - topo = self.get('component'), |
227 | - notifications = topo.get('db').notifications, |
228 | - env = topo.get('env'), |
229 | - fileSources = evt._event.dataTransfer.files; |
230 | - if (fileSources.length) { |
231 | - Y.Array.each(fileSources, function(file) { |
232 | - var reader = new FileReader(); |
233 | - reader.onload = function(e) { |
234 | - // Import each into the environment |
235 | - env.importEnvironment(e.target.result, function(result) { |
236 | - if (!result.error) { |
237 | - notifications.add({ |
238 | - title: 'Imported Environment', |
239 | - message: 'Import from "' + file.name + '" successful', |
240 | - level: 'important' |
241 | - }); |
242 | - } else { |
243 | - notifications.add({ |
244 | - title: 'Import Environment Failed', |
245 | - message: 'Import from "' + file.name + |
246 | - '" failed.<br/>' + result.error, |
247 | - level: 'error' |
248 | - }); |
249 | - } |
250 | - }); |
251 | - }; |
252 | - reader.readAsText(file); |
253 | - }); |
254 | - } else { |
255 | - // If this is not a drop event generated by the application (all |
256 | - // of which have a dataType), then it was caused by dropping |
257 | - // something external to the app, in which case it might be an |
258 | - // environment configuration, so process it as such. |
259 | - |
260 | - // dataType is an invalid argument in IE10 so in order to maintain |
261 | - // this functionality for other browsers we need to do a UA check. |
262 | - if (!Y.UA.ie) { |
263 | - var dataType = evt._event.dataTransfer.getData('dataType'); |
264 | - if (dataType === undefined) { |
265 | - env.importEnvironment(evt._event.dataTransfer.getData('Text')); |
266 | - } |
267 | - } |
268 | - } |
269 | - evt.preventDefault(); |
270 | - evt.stopPropagation(); |
271 | - }, |
272 | - |
273 | - /** |
274 | - * Update lifecycle phase |
275 | - * @method update |
276 | - */ |
277 | - update: function() { |
278 | - // Check the feature flag |
279 | - if (!this._dragHandle && window.flags.dndexport) { |
280 | - var env = this.get('component').get('env'); |
281 | - this._dragHandle = Y.one('#environment-name') |
282 | - .on('dragstart', function(evt) { |
283 | - env.exportEnvironment(function(r) { |
284 | - var ev = evt._event; |
285 | - ev.dataTransfer.dragEffect = 'copy'; |
286 | - var json = JSON.stringify(r.result); |
287 | - ev.dataTransfer.setData('Text', json); |
288 | - }); |
289 | - evt.stopPropagation(); |
290 | - }, this); |
291 | - |
292 | - this.get('component') |
293 | - .recordSubscription(this, this._dragHandle); |
294 | - |
295 | - } |
296 | - ImportExportModule.superclass.update.call(this); |
297 | - } |
298 | - }, { |
299 | - ATTRS: { |
300 | - /** |
301 | - @property {d3ns.Component} component |
302 | - */ |
303 | - component: {} |
304 | - } |
305 | - |
306 | - }); |
307 | - views.ImportExportModule = ImportExportModule; |
308 | -}, '0.1.0', { |
309 | - requires: [ |
310 | - 'node', |
311 | - 'event', |
312 | - 'd3-components', |
313 | - 'juju-models', |
314 | - 'juju-env', |
315 | - 'juju-view-utils' |
316 | - ] |
317 | -}); |
318 | |
319 | === modified file 'app/views/topology/service.js' |
320 | --- app/views/topology/service.js 2013-10-18 16:47:34 +0000 |
321 | +++ app/views/topology/service.js 2013-11-07 16:02:07 +0000 |
322 | @@ -285,7 +285,8 @@ |
323 | @class ServiceModule |
324 | */ |
325 | var ServiceModule = Y.Base.create('ServiceModule', d3ns.Module, [ |
326 | - ServiceModuleCommon], { |
327 | + ServiceModuleCommon, |
328 | + Y.juju.BundleImport], { |
329 | events: { |
330 | scene: { |
331 | '.service': { |
332 | @@ -621,7 +622,8 @@ |
333 | }, |
334 | |
335 | /** |
336 | - * Handle deploying a services by dropping a charm onto the canvas. |
337 | + * Handle deploying services by dropping a charm onto the canvas or |
338 | + * dropping a yaml bundle deployer file from your file system. |
339 | * |
340 | * @method canvasDropHandler |
341 | * @param {Y.EventFacade} e the drop event object. |
342 | @@ -639,43 +641,8 @@ |
343 | var db = topo.get('db'); |
344 | var notifications = db.notifications; |
345 | if (fileSources && fileSources.length) { |
346 | - if (!Y.Lang.isFunction(env.deployerImport)) { |
347 | - // Notify the user that their environment is too old and return. |
348 | - notifications.add({ |
349 | - title: 'Deployer Import Unsupported', |
350 | - message: 'Your environment is too old to support deployer file' + |
351 | - ' imports directly. Please consider upgrading to use' + |
352 | - ' this feature.', |
353 | - level: 'important' |
354 | - }); |
355 | - return; |
356 | - } |
357 | - // Handle dropping Deployer files on the canvas. |
358 | - Y.Array.each(fileSources, function(file) { |
359 | - var reader = new FileReader(); |
360 | - reader.onload = function(e) { |
361 | - // Import each into the environment |
362 | - env.deployerImport(e.target.result, null, function(result) { |
363 | - if (!result.err) { |
364 | - notifications.add({ |
365 | - title: 'Imported Deployer file', |
366 | - message: 'Import from "' + file.name + '" successful. This ' + |
367 | - 'can take some time to complete.', |
368 | - level: 'important' |
369 | - }); |
370 | - } else { |
371 | - console.warn('import failed', file, result); |
372 | - notifications.add({ |
373 | - title: 'Import Environment Failed', |
374 | - message: 'Import from "' + file.name + |
375 | - '" failed.<br/>' + result.err, |
376 | - level: 'error' |
377 | - }); |
378 | - } |
379 | - }); |
380 | - }; |
381 | - reader.readAsText(file); |
382 | - }); |
383 | + // provided by bundle-import-extension.js |
384 | + this.sendToDeployer(env, db, fileSources); |
385 | } else { |
386 | // Handle dropping charm/bundle tokens from the left side bar. |
387 | var dragData = JSON.parse(dataTransfer.getData('Text')); |
388 | @@ -1326,6 +1293,7 @@ |
389 | 'juju-templates', |
390 | 'juju-models', |
391 | 'juju-env', |
392 | - 'unscaled-pack-layout' |
393 | + 'unscaled-pack-layout', |
394 | + 'bundle-import-extension' |
395 | ] |
396 | }); |
397 | |
398 | === modified file 'app/views/topology/topology.js' |
399 | --- app/views/topology/topology.js 2013-10-23 19:57:12 +0000 |
400 | +++ app/views/topology/topology.js 2013-11-07 16:02:07 +0000 |
401 | @@ -302,7 +302,6 @@ |
402 | 'juju-topology-relation', |
403 | 'juju-topology-panzoom', |
404 | 'juju-topology-viewport', |
405 | - 'juju-topology-importexport', |
406 | 'juju-topology-utils' |
407 | ] |
408 | }); |
409 | |
410 | === modified file 'bin/merge-files' |
411 | --- bin/merge-files 2013-11-04 02:17:54 +0000 |
412 | +++ bin/merge-files 2013-11-07 16:02:07 +0000 |
413 | @@ -88,6 +88,7 @@ |
414 | filesToLoad.js.push.apply(filesToLoad.js, [ |
415 | 'app/assets/javascripts/app-subapp-extension.js', |
416 | 'app/assets/javascripts/app-cookies-extension.js', |
417 | + 'app/assets/javascripts/bundle-import-extension.js', |
418 | 'app/assets/javascripts/d3-components.js', |
419 | 'app/assets/javascripts/d3.min.js', |
420 | 'app/assets/javascripts/d3.status.js', |
421 | |
422 | === modified file 'lib/views/stylesheet.less' |
423 | --- lib/views/stylesheet.less 2013-10-31 03:28:32 +0000 |
424 | +++ lib/views/stylesheet.less 2013-11-07 16:02:07 +0000 |
425 | @@ -271,14 +271,9 @@ |
426 | } |
427 | } |
428 | } |
429 | - #import-trigger { |
430 | - /* XXX bac: remove the hiding when import is implemented. */ |
431 | + input[type=file] { |
432 | display: none; |
433 | } |
434 | - #export-trigger { |
435 | - /* XXX huwshimi: remove the following line when import is implemented. */ |
436 | - border: none; |
437 | - } |
438 | } |
439 | &.notifications-nav { |
440 | position: relative; |
Reviewers: mp+194371_ code.launchpad. net,
Message:
Please take a look.
Description:
Adds support for bundle import button
To QA:
Click on the import button in the header, select
a yaml file, and then import. It should deploy
the bundle.
https:/ /code.launchpad .net/~hatch/ juju-gui/ import- bundle- btn/+merge/ 194371
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/22850043/
Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>
Index: app/app.js
=== modified file 'app/app.js'
--- app/app.js 2013-11-06 17:12:26 +0000
+++ app/app.js 2013-11-07 15:49:57 +0000
@@ -51,7 +51,8 @@
Y.juju. SubAppRegistrat ion,
Y.juju. NSRouter,
Y.juju. Cookies, GhostDeployer] , { GhostDeployer, BundleImport] , {
- Y.juju.
+ Y.juju.
+ Y.juju.
/*
Extension properties
@@ -567,6 +568,22 @@
}, this);
}
+ var importNode = Y.one(' #import- trigger' ); .import- export input[type=file]'); on('click' , function(e) { .siblings( 'input[ type=file] ') .getDOMNode( ).click( ); .on('change' , function(e) { oyer(this. env, this.db, .get('files' )._nodes) ;
+ var importFileInput = Y.one('
+ // Tests won't have this node.
+ if (importNode && importFileInput) {
+ importNode.
+ e.halt();
+ e.currentTarget
+ .item(0)
+ });
+
+ importFileInput
+ this.sendToDepl
+ e.currentTarget
+ }, this);
+ }
+
// Attach SubApplications. The subapps should share the same db.
cfg.db = this.db;
@@ -1345,6 +1362,7 @@ juju-inspector- widget' , juju-ghost- inspector' , juju-view- bundle' , controls' , import- extension'
'
'
'
- 'viewmode-controls'
+ 'viewmode-
+ 'bundle-
]
});
Index: app/index.html
<i class="sprite icon-import-normal normal"></i>
<i class="sprite icon-import-hover hover"></i>
</a> trigger" >
<i class="sprite icon-export-normal normal"></i>
<i class="sprite icon-export-hover hover"></i>
=== modified file 'app/index.html'
--- app/index.html 2013-10-31 03:28:32 +0000
+++ app/index.html 2013-11-07 15:49:57 +0000
@@ -140,6 +140,7 @@
+ <input type="file" />
<a href="" id="export-
Index: app/modules- debug.js debug.js' debug.js 2013-11-04 02:17:54 +0000 debug.js 2013-11-07 15:49:57 +0000
fullpath: '/juju- ui/assets/ javascripts/ app-cookies- extension. js'
=== modified file 'app/modules-
--- app/modules-
+++ app/modules-
@@ -181,6 +181,10 @@
},
+ 'bundle- import- extensi. ..