API Docs for:
Show:

File: app/views/landscape.js

'use strict';

/**
 * Methods to aid landscape integration.
 *
 * @module views
 * @submodule views.landscape
 */

YUI.add('juju-landscape', function(Y) {
  var views = Y.namespace('juju.views');

  /**
   * Ensure a trailing slash on a string.
   * @method slash
   * @return {String} string with trailing slash.
   */
  function slash(u) {
    if (u.lastIndexOf('/') !== u.length - 1) {
      u += '/';
    }
    return u;
  }

  /**
   * Collect annotation data about landscape integration
   * for easy consumption.
   *
   * For now this inspects the current database and
   * computes data.
   *
   * TODO: take set of [a/c] | [d] models and do
   * incremental updates.
   * @class Landscape
   */
  function Landscape() {
    Landscape.superclass.constructor.apply(this, arguments);
  }

  views.Landscape = Y.extend(Landscape, Y.Base, {
    /**
     * This tells `Y.Base` that it should create ad-hoc attributes for config
     * properties passed to Model's constructor. This makes it possible to
     * instantiate a model and set a bunch of attributes without having to
     * subclass `Y.Model` and declare all those attributes first.
     *
     * @property _allowAdHocAttrs
     * @type {Boolean}
     * @default true
     * @protected
     * @since 3.5.0
     */
    _allowAdHocAttrs: true,

    /**
     * Collect annotation information from units to services and from
     * services to environemnt.
     *
     * @method update
     * @chainable
     */
    update: function() {
      // Roll up information from the unit level
      // to the service level.
      var db = this.get('db');
      var env = db.environment;

      // Rollup each unit annotation name applying it
      // service and environment.
      //
      // Iterate each landscape annotation.
      Y.each([
              'landscape-security-upgrades',
              'landscape-needs-reboot'],
      function(annotationName) {
        // Iterate each service, we do this so we can rollup
        // when no unit in the services set has the annotation.
        // This is needed to be able to detect and clear annotations
        // at the service/environment level when the unit level flags
        // are cleared.
        // The inner loop uses Y.some allowing it to stop on the
        // first true value.
        var serviceFlagged = false;
        Y.each(db.services, function(service) {
          /*jslint bitwise: true*/
          // The above lint is needed to allow a |= expression
          // to pass the linter.
          serviceFlagged |= service[annotationName] = Y.some(
              db.units.get_units_for_service(service),
              function(unit) {
                var annotations = unit.annotations;
                return Boolean(
                    annotations && annotations[annotationName]);
              });
        });
        env[annotationName] = Boolean(serviceFlagged);
      });
      return this;
    },

    /**
     * Get the landscape url for a given service with respect to
     * the models in the db we've been passed. This depends on
     * the 'db' attribute of this object being set.
     *
     * @method getLandscapeURL
     * @param {Model} model to get URL for.
     * @param {String} intent (optional) can be 'security' or 'reboot'.
     * @return {String} URL to access model entity in landscape.
     */
    getLandscapeURL: function(model, intent) {
      var env = this.get('db').environment.get('annotations');
      var url = env['landscape-url'];
      var modelAnnotation;

      if (!url) {
        // If this environment annotation doesn't exist
        // we cannot generate URLs.
        return undefined;
      }

      url += env['landscape-computers'];
      if (model.name === 'service') {
        modelAnnotation = model.get('annotations')['landscape-computers'];
        if (!modelAnnotation) {
          console.warn('Service missing the landscape-computers annotation!');
          return undefined;
        }
        url += slash(modelAnnotation);
      } else if (model.name === 'serviceUnit') {
        modelAnnotation = (
            model.annotations && model.annotations['landscape-computer']);
        if (!modelAnnotation) {
          console.warn('Unit missing the landscape-computer annotation!');
          return undefined;
        }
        url += slash(modelAnnotation);
      }

      if (!intent) {
        return slash(url);
      } else if (intent === 'reboot') {
        return url + env['landscape-reboot-alert-url'];
      } else if (intent === 'security') {
        return url + env['landscape-security-alert-url'];
      }
    },

    /**
     * Given a model and an intent return an object
     * with the properties of a badge. If the object
     * shouldn't have a badge undefined is returned.
     *
     * @method getLandscapeBadge
     * @param {Model} model to render badge for.
     * @param {String} intent 'security' || 'reboot'.
     * @param {String} hint image postfix to use ex _round.
     * @return {Object} {link: {String}, sprite:{String}}.
     */
    getLandscapeBadge: function(model, intent, hint) {
      var badge = {};
      var props = model;
      var sprite = 'landscape_';

      if (model.name === 'serviceUnit' || !model.name) {
        props = model.annotations;
      }
      if (!props) {
        return undefined;
      }

      badge.link = this.getLandscapeURL(model, intent);
      if (intent === 'reboot') {
        if (!props['landscape-needs-reboot']) {
          return undefined;
        }
        sprite += 'restart';

      } else if (intent === 'security') {
        if (!props['landscape-security-upgrades']) {
          return undefined;
        }
        sprite += intent;
      }

      if (hint) {
        sprite += '_' + hint;
      }

      badge.sprite = sprite;
      return badge;
    }
  });

}, '0.1.0', {
  requires: [
    'juju-models',
    'base'
  ]
});