This is such a cool feature thanks for implementing it. I added a comment about deploying to the position that the user dropped as a follow-up branch as it's probably a bit too much work to tack onto this one :-) My comments below are mostly just cleanup and few small improvement requests. If you have any questions don't hesitate to ask! https://codereview.appspot.com/10500044/diff/5001/app/app.js File app/app.js (right): https://codereview.appspot.com/10500044/diff/5001/app/app.js#newcode582 app/app.js:582: Y.on('initiateDeploy', function(charm) { as per comment in topology/service.js this should be: this.views.environment.instance.topo.on('initiateDeploy', function() { ... }); Environment is a bubble target for the topology so it might be preferable to do this.env.on('initiateDeploy', ... -or- this.env.on('Topology:initiateDeploy', ... I'd even entertain the idea of renaming the event to be 'deployFromCharm' https://codereview.appspot.com/10500044/diff/5001/app/views/topology/service.js File app/views/topology/service.js (right): https://codereview.appspot.com/10500044/diff/5001/app/views/topology/service.js#newcode387 app/views/topology/service.js:387: canvasDropHandler: function() { - possible followup branch This should take note of the drop position and place the service there instead of the default deploy location. https://codereview.appspot.com/10500044/diff/5001/app/views/topology/service.js#newcode388 app/views/topology/service.js:388: // XXX Why do we have to dig so deep just to get to the event? And why Typically libraries will wrap native objects with their own convenience layer and then provide access to the original one on a private property. As for why it's not passed to the handler....not sure Makyo might know. https://codereview.appspot.com/10500044/diff/5001/app/views/topology/service.js#newcode395 app/views/topology/service.js:395: Y.fire('initiateDeploy', charm); This should not be firing on Y, but firing from this class so that the app can listen on this class for the event. this.fire('initiateDeploy', charm); https://codereview.appspot.com/10500044/diff/5001/app/widgets/charm-token.js File app/widgets/charm-token.js (right): https://codereview.appspot.com/10500044/diff/5001/app/widgets/charm-token.js#newcode112 app/widgets/charm-token.js:112: if (!container) { should no longer be necessary as per my comments in the test script. https://codereview.appspot.com/10500044/diff/5001/app/widgets/charm-token.js#newcode117 app/widgets/charm-token.js:117: this._makeDraggable(container, container, charmData); this._makeDraggable(container.one('a'), container, charmData) will get you to a visibile UI while dragging without attaching to every child element. https://codereview.appspot.com/10500044/diff/5001/app/widgets/charm-token.js#newcode119 app/widgets/charm-token.js:119: container.all('*').each(function(child) { This can be removed as per comment above https://codereview.appspot.com/10500044/diff/5001/app/widgets/charm-token.js#newcode133 app/widgets/charm-token.js:133: var outerContainer = container.ancestor('.yui3-charmtoken') this is the bounding box this.get('boundingBox').addClass('yui3-u'); Although I'm not sure why you need to add this class? It appears to work fine without. https://codereview.appspot.com/10500044/diff/5001/test/test_charm_token_drag_and_drop.js File test/test_charm_token_drag_and_drop.js (right): https://codereview.appspot.com/10500044/diff/5001/test/test_charm_token_drag_and_drop.js#newcode37 test/test_charm_token_drag_and_drop.js:37: outerContainer = Y.namespace('juju-tests.utils').makeContainer() not necessary, the bounding box will be automatically created when the widget is rendered. https://codereview.appspot.com/10500044/diff/5001/test/test_charm_token_drag_and_drop.js#newcode39 test/test_charm_token_drag_and_drop.js:39: container = Y.namespace('juju-tests.utils').makeContainer(); you can just use Y['juju-tests'].utils.makeContainer() Y.juju-tests isn't available the tests will blow up anyways. https://codereview.appspot.com/10500044/diff/5001/test/test_charm_token_drag_and_drop.js#newcode44 test/test_charm_token_drag_and_drop.js:44: outerContainer.remove(true); this can be removed as per above and exchanged for container.remove().destroy(true); https://codereview.appspot.com/10500044/diff/5001/test/test_charm_token_drag_and_drop.js#newcode44 test/test_charm_token_drag_and_drop.js:44: outerContainer.remove(true); The charm token instances should be destroyed and removed at the end of the tests https://codereview.appspot.com/10500044/diff/5001/test/test_charm_token_drag_and_drop.js#newcode58 test/test_charm_token_drag_and_drop.js:58: token._makeDraggable = function(element, dragImage, charmData) { Should not be required if you call render() as mentioned below. https://codereview.appspot.com/10500044/diff/5001/test/test_charm_token_drag_and_drop.js#newcode61 test/test_charm_token_drag_and_drop.js:61: token.renderUI(container); you render widgets by calling render() on them, renderUI() is only part of the render cycle. https://codereview.appspot.com/10500044/diff/5001/test/test_charm_token_drag_and_drop.js#newcode71 test/test_charm_token_drag_and_drop.js:71: it('can make an element draggable', function() { I'm not sure what this is testing - you aren't going to be using these as utility methods so the previous test that something is draggable should suffice. https://codereview.appspot.com/10500044/diff/5001/test/test_notifier_widget.js File test/test_notifier_widget.js (right): https://codereview.appspot.com/10500044/diff/5001/test/test_notifier_widget.js#newcode92 test/test_notifier_widget.js:92: // A timeout of 250 milliseconds is used so that we ensure the destroying 500ms https://codereview.appspot.com/10500044/diff/5001/test/test_notifier_widget.js#newcode103 test/test_notifier_widget.js:103: // A timeout of 250 milliseconds is used so that we ensure the destroying 500ms https://codereview.appspot.com/10500044/diff/5001/test/test_notifier_widget.js#newcode114 test/test_notifier_widget.js:114: // A timeout of 250 milliseconds is used so that we ensure the node is not 500ms https://codereview.appspot.com/10500044/diff/5001/test/test_service_module.js File test/test_service_module.js (right): https://codereview.appspot.com/10500044/diff/5001/test/test_service_module.js#newcode372 test/test_service_module.js:372: var eventHandle = Y.on('initiateDeploy', function(charm) { see previous comment about firing from the topology https://codereview.appspot.com/10500044/