API Docs for:
Show:

File: app/views/charm.js

'use strict';

// Both of these views should probably either be deleted or converted to only
// show environment charms.  My (GP) favorite option is to convert CharmView
// into a service tab (viewing the environment's charm) and delete
// CharmCollectionView.

/**
 * Provide the CharmView and CharmCollectionView classes.
 *
 * @module views
 * @submodule views.charm
 */

YUI.add('juju-view-charm-collection', function(Y) {

  var views = Y.namespace('juju.views'),
      Templates = views.Templates,
      utils = Y.namespace('juju.views.utils'),
      models = Y.namespace('juju.models');

  var CharmView = Y.Base.create('CharmView', Y.View, [], {
    initializer: function() {
      this.set('charm', null);
      console.log('Loading charm view', this.get('charm_data_url'));
      this.get('charm_store').get('datasource').sendRequest({
        request: this.get('charm_data_url'),
        callback: {
          'success': Y.bind(this.on_charm_data, this),
          'failure': function er(e) {
            console.error(e.error);
          }
        }
      });
    },

    template: Templates.charm,

    render: function() {
      var charm = this.get('charm'),
          container = this.get('container');

      if (Y.Lang.isNull(container._node)) {
        // If the container node isn't in the dom yet then just return
        // This avoids a console error caused by out of order rendering
        return;
      }
      CharmCollectionView.superclass.render.apply(this, arguments);
      if (!charm) {
        container.setHTML('<div class="alert">Loading...</div>');
        return;
      }
      // Convert time stamp TODO: should be in db layer
      var last_modified = charm.last_change.created;
      if (last_modified) {
        charm.last_change.created = new Date(last_modified * 1000);
      }

      var settings;
      if (charm.config) {
        settings = utils.extractServiceSettings(charm.config.options);
      }

      container.setHTML(this.template({
        charm: charm,
        settings: settings}));

      container.one('#charm-deploy').on(
          'click', Y.bind(this.on_charm_deploy, this));
      return this;
    },

    on_charm_data: function(io_request) {
      var charm = Y.JSON.parse(
          io_request.response.results[0].responseText);
      this.set('charm', charm);
      this.render();
    },

    on_charm_deploy: function(evt) {
      var charm = this.get('charm'),
          container = this.get('container'),
          charmUrl = charm.series + '/' + charm.name,
          env = this.get('env');
      // Generating charm url: see http://jujucharms.com/tools/store-missing
      // for examples of charm addresses.
      if (charm.owner !== 'charmers') {
        charmUrl = '~' + charm.owner + '/' + charmUrl;
      }
      charmUrl = 'cs:' + charmUrl;

      // Gather the configuration values from the form.
      var serviceName = container.one('#service-name').get('value'),
          config = utils.getElementsValuesMapping(container,
              '#service-config .config-field');

      // The deploy call generates an event chain leading to a call to
      // `app.on_database_changed()`, which re-dispatches the current view.
      // For this reason we need to redirect to the root page right now.
      this.fire('navigateTo', {url: '/:gui:/'});
      env.deploy(charmUrl, serviceName, config,
          Y.bind(this._deployCallback, this)
      );
    },

    _deployCallback: function(ev) {
      if (ev.err) {
        this.get('db').notifications.add(
            new models.Notification({
              title: 'Error deploying charm',
              message: 'Service name: ' + ev.service_name +
                  '; Charm url: ' + ev.charm_url,
              level: 'error'
            })
        );
        return;
      }
      console.log(ev.charm_url + ' deployed');
    }
  });

  var CharmCollectionView = Y.Base.create('CharmCollectionView', Y.View, [], {

    initializer: function() {
      this.set('charms', []);
      this.set('current_request', null);
    },

    template: Templates['charm-collection'],

    render: function() {
      var container = this.get('container'),
          charm = this.get('charm'), // TODO change attribute name to "model"
          self = this;

      CharmCollectionView.superclass.render.apply(this, arguments);
      container.setHTML(this.template({charms: this.get('charms')}));

      // TODO: Use view.events structure to attach this
      container.all('div.thumbnail').each(function(el) {
        el.on('click', function(evt) {
          self.fire('navigateTo',
              {url: '/charms/' + this.getData('charm-url')});
        });
      });

      return this;
    },

    on_search_change: function(evt) {
      if (evt) {
        evt.preventDefault();
        evt.stopImmediatePropagation();
      }

      var query = Y.one('#charm-search').get('value');
      if (query) {
        this.set('query', query);
      } else {
        query = this.get('query');
      }

      // The handling in datasources-plugins is an example of doing this a bit
      // better ie. io cancellation outstanding requests, it does seem to
      // cause some interference with various datasource plugins though.
      this.get('charm_store').get('datasource').sendRequest({
        request: 'search/json?search_text=' + query,
        callback: {
          'success': Y.bind(this.on_results_change, this),
          'failure': function er(e) { console.error(e.error); }
        }});
    },

    on_results_change: function(io_request) {
      var result_set = Y.JSON.parse(
          io_request.response.results[0].responseText);
      this.set('charms', result_set.results);
      this.render();
    }

  });

  views.charm_collection = CharmCollectionView;
  views.charm = CharmView;

}, '0.1.0', {
  requires: [
    'node',
    'handlebars',
    'datasource-io',
    'datasource-jsonschema',
    'io-base',
    'json-parse',
    'view']
});