All Downloads are FREE. Search and download functionalities are using the official Maven repository.

app.panels.trends.module.js Maven / Gradle / Ivy

The newest version!
/** @scratch /panels/5
 *
 * include::panels/trends.asciidoc[]
 */

/** @scratch /panels/trends/0
 *
 * == trends
 * Status: *Beta*
 *
 * A stock-ticker style representation of how queries are moving over time. For example, if the
 * time is 1:10pm, your time picker was set to "Last 10m", and the "Time Ago" parameter was set to
 * "1h", the panel would show how much the query results have changed since 12:00-12:10pm
 *
 */
define([
  'angular',
  'app',
  'lodash',
  'kbn'
],
function (angular, app, _, kbn) {
  'use strict';

  var module = angular.module('kibana.panels.trends', []);
  app.useModule(module);

  module.controller('trends', function($scope, kbnIndex, querySrv, dashboard, filterSrv) {

    $scope.panelMeta = {
      modals : [
        {
          description: "Inspect",
          icon: "icon-info-sign",
          partial: "app/partials/inspector.html",
          show: $scope.panel.spyable
        }
      ],
      editorTabs : [
        {title:'Queries', src:'app/partials/querySelect.html'}
      ],
      status  : "Beta",
      description : "A stock-ticker style representation of how queries are moving over time. "+
      "For example, if the time is 1:10pm, your time picker was set to \"Last 10m\", and the \"Time "+
      "Ago\" parameter was set to '1h', the panel would show how much the query results have changed"+
      " since 12:00-12:10pm"
    };

    // Set and populate defaults
    var _d = {
      /** @scratch /panels/trends/5
       *
       * === Parameters
       *
       * ago:: A date math formatted string describing the relative time period to compare the
       * queries to.
       */
      ago     : '1d',
      /** @scratch /panels/trends/5
       * arrangement:: `horizontal' or `vertical'
       */
      arrangement : 'vertical',
      /** @scratch /panels/trends/5
       * reverse:: true or false. If true, use red for positive, green for negative
       */
      reverse : false,
      /** @scratch /panels/trends/5
       * spyable:: Set to false to disable the inspect icon
       */
      spyable: true,
      /** @scratch /panels/trends/5
       *
       * ==== Queries
       * queries object:: This object describes the queries to use on this panel.
       * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+
       * queries.ids::: In +selected+ mode, which query ids are selected.
       */
      queries     : {
        mode        : 'all',
        ids         : []
      },
      style   : { "font-size": '14pt'},
    };
    _.defaults($scope.panel,_d);

    $scope.init = function () {
      $scope.hits = 0;

      $scope.$on('refresh', function(){$scope.get_data();});

      $scope.get_data();
    };

    $scope.get_data = function(segment,query_id) {
      delete $scope.panel.error;
      $scope.panelMeta.loading = true;

      // Make sure we have everything for the request to complete
      if(dashboard.indices.length === 0) {
        return;
      } else {
        $scope.index = segment > 0 ? $scope.index : dashboard.indices;
      }

      // Determine a time field
      var timeField = _.uniq(_.pluck(filterSrv.getByType('time'),'field'));
      if(timeField.length > 1) {
        $scope.panel.error = "Time field must be consistent amongst time filters";
        return;
      } else if(timeField.length === 0) {
        $scope.panel.error = "A time filter must exist for this panel to function";
        return;
      } else {
        timeField = timeField[0];
      }

      // This logic can be simplified greatly with the new kbn.parseDate
      $scope.time = filterSrv.timeRange('last');


      $scope.old_time = {
        from : new Date($scope.time.from.getTime() - kbn.interval_to_ms($scope.panel.ago)).valueOf(),
        to   : new Date($scope.time.to.getTime() - kbn.interval_to_ms($scope.panel.ago)).valueOf()
      };

      var _segment = _.isUndefined(segment) ? 0 : segment;
      var request = $scope.ejs.Request();
      var _ids_without_time = _.difference(filterSrv.ids,filterSrv.idsByType('time'));

      $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries);
      var queries = querySrv.getQueryObjs($scope.panel.queries.ids);

      // Build the question part of the query
      _.each(queries, function(query) {
        var q = $scope.ejs.FilteredQuery(
          querySrv.toEjsObj(query),
          filterSrv.getBoolFilter(filterSrv.ids()));

        request = request
          .facet($scope.ejs.QueryFacet(query.id)
            .query(q)
          ).size(0);
      });


      // And again for the old time period
      _.each(queries, function(query) {
        var q = $scope.ejs.FilteredQuery(
          querySrv.toEjsObj(query),
          filterSrv.getBoolFilter(_ids_without_time).must(
            $scope.ejs.RangeFilter(timeField)
            .from($scope.old_time.from)
            .to($scope.old_time.to)
          ));
        request = request
          .facet($scope.ejs.QueryFacet("old_"+query.id)
            .query(q)
          ).size(0);
      });


      // Populate the inspector panel
      $scope.inspector = request.toJSON();

      // If we're on the first segment we need to get our indices
      if (_segment === 0) {
        kbnIndex.indices(
          $scope.old_time.from,
          $scope.old_time.to,
          dashboard.current.index.pattern,
          dashboard.current.index.interval
        ).then(function (p) {
          $scope.index = _.union(p,$scope.index);
          process_results($scope.ejs.doSearch($scope.index[_segment], request),_segment,query_id);
        });
      } else {
        process_results($scope.ejs.doSearch($scope.index[_segment], request),_segment,query_id);
      }

    };

    // Populate scope when we have results
    var process_results = function(results,_segment,query_id) {
      results.then(function(results) {
        $scope.panelMeta.loading = false;
        if(_segment === 0) {
          $scope.hits = {};
          $scope.data = [];
          query_id = $scope.query_id = new Date().getTime();
        }

        // Check for error and abort if found
        if(!(_.isUndefined(results.error))) {
          $scope.panel.error = $scope.parse_error(results.error);
          return;
        }

        // Make sure we're still on the same query/queries
        if($scope.query_id === query_id) {
          var i = 0;
          var queries = querySrv.getQueryObjs($scope.panel.queries.ids);

          _.each(queries, function(query) {
            var n = results.facets[query.id].count;
            var o = results.facets['old_'+query.id].count;

            var hits = {
              new : _.isUndefined($scope.data[i]) || _segment === 0 ? n : $scope.data[i].hits.new+n,
              old : _.isUndefined($scope.data[i]) || _segment === 0 ? o : $scope.data[i].hits.old+o
            };

            $scope.hits.new += n;
            $scope.hits.old += o;

            var percent = percentage(hits.old,hits.new) == null ?
              '?' : Math.round(percentage(hits.old,hits.new)*100)/100;
            // Create series
            $scope.data[i] = {
              info: query,
              hits: {
                new : hits.new,
                old : hits.old
              },
              percent: percent
            };

            i++;
          });
          $scope.$emit('render');
          if(_segment < $scope.index.length-1) {
            $scope.get_data(_segment+1,query_id);
          } else {
            $scope.trends = $scope.data;
          }
        }
      });
    };

    function percentage(x,y) {
      return x === 0 ? null : 100*(y-x)/x;
    }

    $scope.set_refresh = function (state) {
      $scope.refresh = state;
    };

    $scope.close_edit = function() {
      if($scope.refresh) {
        $scope.get_data();
      }
      $scope.refresh =  false;
      $scope.$emit('render');
    };

  });
});




© 2015 - 2025 Weber Informatics LLC | Privacy Policy