Merge lp:~hatch/juju-gui/import-bundle-btn into lp:juju-gui/experimental

Proposed by Jeff Pihach
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
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+194371@code.launchpad.net

Description of the change

Adds support for bundle import button

https://codereview.appspot.com/22850043/

To post a comment you must log in.
Revision history for this message
Jeff Pihach (hatch) wrote :
Download full text (16.5 KiB)

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.SubAppRegistration,
                                                    Y.juju.NSRouter,
                                                    Y.juju.Cookies,
- Y.juju.GhostDeployer], {
+ Y.juju.GhostDeployer,
+ Y.juju.BundleImport], {

      /*
        Extension properties
@@ -567,6 +568,22 @@
          }, this);
        }

+ var importNode = Y.one('#import-trigger');
+ var importFileInput = Y.one('.import-export input[type=file]');
+ // Tests won't have this node.
+ if (importNode && importFileInput) {
+ importNode.on('click', function(e) {
+ e.halt();
+ e.currentTarget.siblings('input[type=file]')
+ .item(0).getDOMNode().click();
+ });
+
+ importFileInput.on('change', function(e) {
+ this.sendToDeployer(this.env, this.db,
+ e.currentTarget.get('files')._nodes);
+ }, 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',
- 'viewmode-controls'
+ 'viewmode-controls',
+ 'bundle-import-extension'
    ]
  });

Index: app/index.html
=== 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 @@
                  <i class="sprite icon-import-normal normal"></i>
                  <i class="sprite icon-import-hover hover"></i>
                </a>
+ <input type="file" />
                <a href="" id="export-trigger">
                  <i class="sprite icon-export-normal normal"></i>
                  <i class="sprite icon-export-hover hover"></i>

Index: app/modules-debug.js
=== modified file 'app/modules-debug.js'
--- app/modules-debug.js 2013-11-04 02:17:54 +0000
+++ app/modules-debug.js 2013-11-07 15:49:57 +0000
@@ -181,6 +181,10 @@
            fullpath: '/juju-ui/assets/javascripts/app-cookies-extension.js'
          },

+ 'bundle-import-extensi...

Revision history for this message
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://codereview.appspot.com/22850043/diff/1/app/index.html
File app/index.html (right):

https://codereview.appspot.com/22850043/diff/1/app/index.html#newcode143
app/index.html:143:
should we #id this since we only expect one?

https://codereview.appspot.com/22850043/diff/1/bin/merge-files
File bin/merge-files (right):

https://codereview.appspot.com/22850043/diff/1/bin/merge-files#newcode91
bin/merge-files:91:
is it not picked up by the deps on app.js?

https://codereview.appspot.com/22850043/

Revision history for this message
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

https://codereview.appspot.com/22850043/

Revision history for this message
Jeff Pihach (hatch) wrote :

Thanks for the review! Changes made

https://codereview.appspot.com/22850043/

Revision history for this message
Jeff Pihach (hatch) wrote :

*** Submitted:

Adds support for bundle import button

R=rharding
CC=
https://codereview.appspot.com/22850043

https://codereview.appspot.com/22850043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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;

Subscribers

People subscribed via source and target branches