mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
removed visualize app
This commit is contained in:
parent
86e936d088
commit
42a3d5ba4b
45 changed files with 0 additions and 2302 deletions
8
TODOS.md
8
TODOS.md
|
@ -10,14 +10,6 @@
|
|||
- Move to utility class – (https://github.com/elasticsearch/kibana4/blob/master/src/kibana/apps/discover/controllers/discover.js)
|
||||
- **src/kibana/apps/settings/sections/indices/_create.js**
|
||||
- we should probably display a message of some kind – (https://github.com/elasticsearch/kibana4/blob/master/src/kibana/apps/settings/sections/indices/_create.js)
|
||||
- **src/kibana/apps/visualize/saved_visualizations/_adhoc_vis.js**
|
||||
- Should we abtract out the agg building stuff? – (https://github.com/elasticsearch/kibana4/blob/master/src/kibana/apps/visualize/saved_visualizations/_adhoc_vis.js)
|
||||
- Should this be abstracted somewhere? Its a copy/paste from _saved_vis.js – (https://github.com/elasticsearch/kibana4/blob/master/src/kibana/apps/visualize/saved_visualizations/_adhoc_vis.js)
|
||||
- **src/kibana/apps/visualize/saved_visualizations/_type_defs.js**
|
||||
- We need to be able to get ahold of angular services here – (https://github.com/elasticsearch/kibana4/blob/master/src/kibana/apps/visualize/saved_visualizations/_type_defs.js)
|
||||
- We need to be able to get ahold of angular services here – (https://github.com/elasticsearch/kibana4/blob/master/src/kibana/apps/visualize/saved_visualizations/_type_defs.js)
|
||||
- **src/kibana/apps/visualize/saved_visualizations/bucket_aggs/terms.js**
|
||||
- We need more just _count here. – (https://github.com/elasticsearch/kibana4/blob/master/src/kibana/apps/visualize/saved_visualizations/bucket_aggs/terms.js)
|
||||
- **src/kibana/components/agg_types/buckets/terms.js**
|
||||
- We need more than just _count here. – (https://github.com/elasticsearch/kibana4/blob/master/src/kibana/components/agg_types/buckets/terms.js)
|
||||
- **src/kibana/components/index_patterns/_mapper.js**
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
<div ng-controller="VisualizeEditor" class="vis-editor">
|
||||
<div ng-if="!appEmbedded" class="app-container">
|
||||
<navbar>
|
||||
<span ng-if="!!vis.title" class="name" ng-bind="vis.title"></span>
|
||||
<div class="fill bitty-modal-container">
|
||||
<div ng-if="linked && !unlinking"
|
||||
ng-dblclick="unlink()"
|
||||
tooltip="Double click to unlink this visualization from the saved search"
|
||||
class="bitty-modal visualize-linked">
|
||||
<i class="fa fa-link"></i>
|
||||
|
||||
This visualization is linked to a saved search:
|
||||
<b>{{ vis.savedSearchId | json}}</b>
|
||||
<a href="#/discover/{{ vis.savedSearchId | uriescape }}">
|
||||
<i class="fa fa-pencil" tooltip="Click here to edit the linked saved search"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div ng-if="linked && unlinking" ng-click="doneUnlinking()" class="bitty-modal">
|
||||
<i class="fa fa-chain-broken"></i> Unlinked!
|
||||
</div>
|
||||
|
||||
<form ng-submit="fetch()" class="inline-form" name="queryInput">
|
||||
<div class="typeahead" kbn-typeahead="visualize">
|
||||
<div class="input-group"
|
||||
ng-class="queryInput.$invalid ? 'has-error' : ''">
|
||||
<input query-input="vis.searchSource"
|
||||
kbn-typeahead-input
|
||||
placeholder="Search..."
|
||||
type="text"
|
||||
class="form-control"
|
||||
ng-model="state.query">
|
||||
|
||||
<button class="btn btn-default" type="submit"
|
||||
ng-disabled="queryInput.$invalid">
|
||||
<span class="fa fa-search"></span>
|
||||
</button>
|
||||
</div>
|
||||
<kbn-typeahead-items></kbn-typeahead-items>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<button ng-click="startOver()"><i class="fa fa-file-o"></i></button>
|
||||
<button ng-click="toggleSave()"><i class="fa fa-save"></i></button>
|
||||
<button ng-click="toggleLoad()"><i class="fa fa-folder-open"></i></button>
|
||||
<button ng-click="toggleShare()"><i class="fa fa-code"></i></button>
|
||||
<button ng-click="fetch()"><i class="fa fa-refresh"></i></button>
|
||||
</div>
|
||||
</navbar>
|
||||
|
||||
<config
|
||||
config-template="configTemplate"
|
||||
config-object="conf">
|
||||
</config>
|
||||
|
||||
<div class="vis-editor-content">
|
||||
<div class="vis-sidebar">
|
||||
<div class="sidebar-container">
|
||||
<form class="sidebar-list" ng-submit="fetch()" name="visualizeEditor">
|
||||
<ul class="list-unstyled">
|
||||
<li ng-repeat="category in visConfigCategories.displayOrder" class="sidebar-item">
|
||||
<vis-config-category
|
||||
vis="vis"
|
||||
category="vis[category.name]"
|
||||
fields="fields">
|
||||
</vis-config-category>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<button
|
||||
ng-click="fetch()"
|
||||
ng-if="stateDirty"
|
||||
ng-disabled="httpActive.length || visualizeEditor.$invalid"
|
||||
class="sidebar-item-button success">
|
||||
Apply
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="vis-canvas">
|
||||
<vis-canvas><visualize vis="vis"></visualize></vis-canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="appEmbedded" class="container-fluid">
|
||||
<div class="row vis-editor-content">
|
||||
<div class="vis-canvas">
|
||||
<vis-canvas><visualize vis="vis"></visualize></vis-canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,16 +0,0 @@
|
|||
define(function (require) {
|
||||
require('css!apps/visualize/styles/main.css');
|
||||
|
||||
require('apps/visualize/controllers/editor');
|
||||
require('apps/visualize/controllers/wizard');
|
||||
|
||||
require('apps/visualize/directives/canvas');
|
||||
require('apps/visualize/directives/visualize');
|
||||
require('apps/visualize/directives/config_category');
|
||||
require('apps/visualize/directives/search_editor');
|
||||
|
||||
require('routes')
|
||||
.when('/visualize', {
|
||||
redirectTo: '/visualize/step/1'
|
||||
});
|
||||
});
|
|
@ -1,24 +0,0 @@
|
|||
<div
|
||||
class="sidebar-item-title"
|
||||
ng-if="category.name !== 'group' || vis.segment.configs.length > 0">
|
||||
<span>
|
||||
<button
|
||||
type="button"
|
||||
ng-if="category.configs.length < category.max"
|
||||
ng-click="vis.addConfig(category.name)"
|
||||
class="btn btn-xs btn-default" >
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
{{ category.label }}
|
||||
</span>
|
||||
</div>
|
||||
<div ng-if="category.configs.length > 0" class="vis-config-details">
|
||||
<vis-config-editor
|
||||
ng-repeat="config in category.configs"
|
||||
category="category"
|
||||
config="config"
|
||||
vis="vis"
|
||||
fields="fields"
|
||||
move="moveHandler">
|
||||
</vis-config-editor>
|
||||
</div>
|
|
@ -1,22 +0,0 @@
|
|||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<label>Min <small>(optional)</small></label>
|
||||
<input
|
||||
ng-show="aggParams.min_doc_count"
|
||||
ng-model="config.extended_bounds.min"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="extended_bounds.min" />
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<label>Max <small>(optional)</small></label>
|
||||
<input
|
||||
ng-show="aggParams.min_doc_count"
|
||||
ng-model="config.extended_bounds.max"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="extended_bounds.max" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,26 +0,0 @@
|
|||
<div ng-init="config.filters = (config.filters || [{input: {}}])">
|
||||
<div class="form-group" >
|
||||
<div ng-repeat="filter in config.filters track by $index">
|
||||
<div class="config-controls pull-right btn-group">
|
||||
<span ng-click="config.filters.splice($index, 1)"
|
||||
class="btn btn-danger btn-xs ">
|
||||
<i class="fa fa-ban" ></i>
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Query string {{$index + 1}}</label>
|
||||
<input query-input
|
||||
ng-model="filter.input"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="filter{{$index}}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
ng-click="config.filters.push({input: {}})"
|
||||
class="sidebar-item-button primary">
|
||||
Add filter
|
||||
</div>
|
||||
</div>
|
|
@ -1,9 +0,0 @@
|
|||
<div class="checkbox">
|
||||
<label>
|
||||
<input
|
||||
ng-model="config.global"
|
||||
type="checkbox">Run First
|
||||
|
||||
<kbn-info info="Ensure that all charts have the same {{group.label | lowercase}} values." placement="right"></kbn-info>
|
||||
</label>
|
||||
</div>
|
|
@ -1,22 +0,0 @@
|
|||
<div class="form-group">
|
||||
<table class="agg-config-interval">
|
||||
<tr>
|
||||
<td>
|
||||
<label>Interval</label>
|
||||
<select
|
||||
ng-if="aggParams.interval.options"
|
||||
ng-model="config.interval"
|
||||
ng-options="opt.val as opt.display for opt in aggParams.interval.options"
|
||||
class="form-control"
|
||||
name="interval">
|
||||
</select>
|
||||
<input
|
||||
ng-if="!aggParams.interval.options"
|
||||
ng-model="config.interval"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="interval" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
|
@ -1,43 +0,0 @@
|
|||
<div ng-init="config.ranges = (config.ranges || [{}])">
|
||||
<div class="form-group" >
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-5">
|
||||
<label>From</label>
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<label>To</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row"
|
||||
ng-repeat="range in config.ranges track by $index">
|
||||
<div class="col-xs-5">
|
||||
<input validate-ip
|
||||
ng-model="range.from"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="range.from" />
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<input validate-ip
|
||||
ng-model="range.to"
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="range.to" />
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<button ng-click="config.ranges.splice($index, 1)"
|
||||
class="btn btn-danger btn-xs">
|
||||
<i class="fa fa-ban" ></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div
|
||||
ng-click="config.ranges.push({})"
|
||||
class="sidebar-item-button primary">
|
||||
Add Range
|
||||
</div>
|
||||
</div>
|
|
@ -1,16 +0,0 @@
|
|||
<div class="form-group">
|
||||
<table class="agg-config-interval">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="checkbox ng-scope">
|
||||
<label>
|
||||
<input ng-model="config.min_doc_count"
|
||||
type="checkbox">Show empty buckets
|
||||
|
||||
<kbn-info info="Show all buckets, not only the buckets with results." placement="right" class="ng-isolate-scope"></kbn-info>
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
|
@ -1,15 +0,0 @@
|
|||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<select
|
||||
class="form-control"
|
||||
name="order"
|
||||
ng-model="config.order"
|
||||
ng-options="opt.val as opt.display for opt in aggParams.order.options">
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<input class="form-control" type="number" ng-model="config.size" name="size">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,43 +0,0 @@
|
|||
<div ng-init="config.ranges = (config.ranges || [{}])">
|
||||
<div class="form-group" >
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-5">
|
||||
<label>From</label>
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<label>To</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row"
|
||||
ng-repeat="range in config.ranges track by $index">
|
||||
<div class="col-xs-5">
|
||||
<input
|
||||
ng-model="range.from"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="range.from" />
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<input
|
||||
ng-model="range.to"
|
||||
type="number"
|
||||
class="form-control"
|
||||
name="range.to" />
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<button ng-click="config.ranges.splice($index, 1)"
|
||||
class="btn btn-danger btn-xs">
|
||||
<i class="fa fa-ban" ></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div
|
||||
ng-click="config.ranges.push({})"
|
||||
class="sidebar-item-button primary">
|
||||
Add Range
|
||||
</div>
|
||||
</div>
|
|
@ -1,39 +0,0 @@
|
|||
<div ng-if="category.name === 'split'" class="form-group">
|
||||
<div class="btn-group">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-xs btn-default"
|
||||
ng-model="config.row"
|
||||
btn-radio="true">
|
||||
Row
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-xs btn-default"
|
||||
ng-model="config.row"
|
||||
btn-radio="false">
|
||||
Column
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" ng-show="availableAggs">
|
||||
<label>Aggregation</label>
|
||||
<select
|
||||
name="agg"
|
||||
class="form-control"
|
||||
ng-model="config.agg"
|
||||
ng-options="agg.name as agg.display for agg in availableAggs">
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="field">
|
||||
Field
|
||||
</label>
|
||||
<select
|
||||
class="form-control"
|
||||
name="field"
|
||||
ng-model="config.field"
|
||||
ng-options="field.name as field.name group by field.type for field in fields | filter:{indexed:true} |orderBy:['type','name']">
|
||||
</select>
|
||||
</div>
|
||||
<div class="agg-param-controls"></div>
|
|
@ -1,25 +0,0 @@
|
|||
<div class="config-controls pull-right btn-group">
|
||||
<button
|
||||
ng-if="category.configs.length > 1"
|
||||
ng-click="move(config, -1)"
|
||||
type="button"
|
||||
ng-disabled="category.configs.indexOf(config) < 1"
|
||||
class="btn btn-xs btn-default">
|
||||
<div tooltip="Increase Priority"><i class="fa fa-caret-up"></i></div>
|
||||
</button>
|
||||
<button
|
||||
ng-if="category.configs.length > 1"
|
||||
ng-click="move(config, 1)"
|
||||
type="button"
|
||||
ng-disabled="category.configs.indexOf(config) >= category.configs.length - 1"
|
||||
class="btn btn-xs btn-default">
|
||||
<div tooltip="Decrease Priority"><i class="fa fa-caret-down"></i></div>
|
||||
</button>
|
||||
<button
|
||||
ng-if="category.configs.length > category.min"
|
||||
ng-click="move(config, false)"
|
||||
type="button"
|
||||
class="btn btn-xs btn-danger">
|
||||
<div tooltip="Remove Dimension"><i class="fa fa-times"></i></div>
|
||||
</button>
|
||||
</div>
|
|
@ -1,21 +0,0 @@
|
|||
<div class="form-group">
|
||||
<label for="stat">Stat</label>
|
||||
<select
|
||||
class="form-control"
|
||||
name="stat"
|
||||
ng-model="config.agg"
|
||||
ng-options="agg.name as agg.name for agg in aggs.metricAggs">
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" ng-if="config.agg && config.agg !== 'count'">
|
||||
<label for="field">
|
||||
Field to {{config.agg}}
|
||||
<kbn-info placement="right" info="Field to use for the {{metric.label}}"></kbn-info>
|
||||
</label>
|
||||
<select
|
||||
class="form-control"
|
||||
name="field"
|
||||
ng-model="config.field"
|
||||
ng-options="field.name as field.name for field in fields | fieldType:aggs.metricAggsByName[config.agg].types">
|
||||
</select>
|
||||
</div>
|
|
@ -1 +0,0 @@
|
|||
<saved-object-finder type="visualizations"></saved-object-finder>
|
|
@ -1,12 +0,0 @@
|
|||
<form role="form" ng-submit="conf.doSave()">
|
||||
<div class="form-group">
|
||||
<label for="visTitle">Title</label>
|
||||
<input class="form-control" type="text" name="visTitle" ng-model="conf.vis.title" required input-focus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="visDescription">Description</label>
|
||||
<textarea class="form-control" name="visDescription" ng-model="conf.vis.description" placeholder=""></textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
</form>
|
|
@ -1,11 +0,0 @@
|
|||
<form role="form" class="vis-share">
|
||||
<div class="form-group">
|
||||
<label>Embed this visualization. <small>Copy code into your html source. Note all clients must still be able to access kibana</small></label>
|
||||
<div class="form-control" disabled><iframe src="{{conf.shareData().embed}}" height="400" width="600"></iframe></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Share a link</label>
|
||||
<div class="form-control" disabled>{{conf.shareData().link}}</div>
|
||||
</div>
|
||||
</form>
|
|
@ -1,8 +0,0 @@
|
|||
<div ng-if="chartData.hits === 0"
|
||||
class="visualize-error visualize-chart">
|
||||
<h2><i class="fa fa-meh-o"></i></h2>
|
||||
<h4>No results found</h4>
|
||||
</div>
|
||||
|
||||
<div ng-hide="chartData.hits === 0" class="visualize-chart"></div>
|
||||
<visualize-spy></visualize-spy>
|
|
@ -1,131 +0,0 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
|
||||
var module = require('modules').get('app/visualize');
|
||||
var configCats = require('apps/visualize/saved_visualizations/_config_categories');
|
||||
|
||||
|
||||
module.factory('AdhocVis', function (courier, Private, Promise) {
|
||||
var aggs = Private(require('apps/visualize/saved_visualizations/_aggs'));
|
||||
|
||||
/**
|
||||
opts params:
|
||||
{
|
||||
type: 'histogram', // The chart type
|
||||
listeners : {
|
||||
onClick: function,
|
||||
onHover: function,
|
||||
onBrush: function,
|
||||
},
|
||||
params: {}, // top level chart parameters
|
||||
searchSource: SearchSource // the search source for the visualization
|
||||
}
|
||||
|
||||
*/
|
||||
function AdhocVis(opts) {
|
||||
opts = opts || {};
|
||||
if (!_.isObject(opts)) throw new TypeError('options must be an object');
|
||||
|
||||
var vis = this;
|
||||
var params;
|
||||
|
||||
var createdSource = true;
|
||||
|
||||
vis.init = _.once(function () {
|
||||
vis.typeName = opts.type || 'histogram';
|
||||
vis.params = _.cloneDeep(opts.params);
|
||||
|
||||
// give vis the properties of config
|
||||
_.assign(vis, opts.config);
|
||||
|
||||
// also give it the on* interaction functions, if any
|
||||
_.assign(vis, opts.listeners);
|
||||
|
||||
vis._fillConfigsToMinimum();
|
||||
|
||||
// resolve the search source for this AdhocVis
|
||||
return Promise.cast((function () {
|
||||
if (opts.searchSource) {
|
||||
// did not create the source, so we won't destroy it either
|
||||
createdSource = false;
|
||||
return opts.searchSource;
|
||||
}
|
||||
|
||||
return courier.createSource('search');
|
||||
|
||||
}()))
|
||||
.then(function (searchSource) {
|
||||
// TODO: Should we abtract out the agg building stuff?
|
||||
searchSource.aggs(function () {
|
||||
// stores the config objects in queryDsl
|
||||
var dsl = {};
|
||||
// counter to ensure unique agg names
|
||||
var i = 0;
|
||||
// start at the root, but the current will move
|
||||
var current = dsl;
|
||||
|
||||
// continue to nest the aggs under each other
|
||||
// writes to the dsl object
|
||||
vis.getConfig().forEach(function (config) {
|
||||
current.aggs = {};
|
||||
var key = '_agg_' + (i++);
|
||||
|
||||
var aggDsl = {};
|
||||
aggDsl[config.agg] = config.aggParams;
|
||||
|
||||
current = current.aggs[key] = aggDsl;
|
||||
});
|
||||
|
||||
// set the dsl to the searchSource
|
||||
return dsl.aggs || {};
|
||||
});
|
||||
|
||||
vis.searchSource = searchSource;
|
||||
|
||||
return vis;
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: Should this be abstracted somewhere? Its a copy/paste from _saved_vis.js
|
||||
vis._fillConfigsToMinimum = function () {
|
||||
// satify the min count for each category
|
||||
configCats.fetchOrder.forEach(function (category) {
|
||||
var myCat = vis[category.name];
|
||||
|
||||
if (myCat.configs.length < myCat.min) {
|
||||
_.times(myCat.min - myCat.configs.length, function () {
|
||||
vis.addConfig(category.name);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
vis.destroy = function () {
|
||||
if (createdSource) {
|
||||
this.searchSource.cancelPending();
|
||||
} else {
|
||||
//remove our aggregations from the serarch source
|
||||
this.searchSource.set('aggs', null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a list of config objects, which are ready to be turned into aggregations,
|
||||
* in the order which they should be executed.
|
||||
*
|
||||
* @return {Array} - The list of config objects
|
||||
*/
|
||||
vis.getConfig = Private(require('apps/visualize/saved_visualizations/_read_config'));
|
||||
|
||||
/**
|
||||
* Transform an ES Response into data for this visualization
|
||||
* @param {object} resp The elasticsearch response
|
||||
* @return {array} An array of flattened response rows
|
||||
*/
|
||||
vis.buildChartDataFromResponse = Private(require('apps/visualize/saved_visualizations/_build_chart_data'));
|
||||
|
||||
}
|
||||
|
||||
return AdhocVis;
|
||||
});
|
||||
});
|
|
@ -1,103 +0,0 @@
|
|||
define(function (require) {
|
||||
return function AggsService(Private) {
|
||||
require('lodash');
|
||||
var _ = require('lodash');
|
||||
|
||||
var aggs = {};
|
||||
|
||||
aggs.metricAggs = [
|
||||
{
|
||||
name: 'count',
|
||||
display: 'Count',
|
||||
types: ['number'],
|
||||
makeLabel: function (params) {
|
||||
return 'Count of documents';
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'avg',
|
||||
display: 'Average',
|
||||
types: ['number'],
|
||||
makeLabel: function (params) {
|
||||
return 'Average ' + params.field;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'sum',
|
||||
display: 'Sum',
|
||||
types: ['number'],
|
||||
makeLabel: function (params) {
|
||||
return 'Sum of ' + params.field;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'min',
|
||||
display: 'Min',
|
||||
types: ['number'],
|
||||
makeLabel: function (params) {
|
||||
return 'Min ' + params.field;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'max',
|
||||
display: 'Max',
|
||||
types: ['number'],
|
||||
makeLabel: function (params) {
|
||||
return 'Max ' + params.field;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'cardinality',
|
||||
display: 'Unique count',
|
||||
types: ['*'],
|
||||
makeLabel: function (params) {
|
||||
return 'Unique count of ' + params.field;
|
||||
}
|
||||
},
|
||||
];
|
||||
aggs.metricAggsByName = _.indexBy(aggs.metricAggs, 'name');
|
||||
|
||||
aggs.bucketAggs = Private(require('apps/visualize/saved_visualizations/bucket_aggs/_index'));
|
||||
aggs.bucketAggsByName = _.indexBy(aggs.bucketAggs, 'name');
|
||||
|
||||
aggs.byName = _.assign({}, aggs.bucketAggsByName, aggs.metricAggsByName);
|
||||
|
||||
aggs.byFieldType = {
|
||||
number: [
|
||||
aggs.bucketAggsByName.terms,
|
||||
aggs.bucketAggsByName.histogram,
|
||||
aggs.bucketAggsByName.range,
|
||||
// 'range'
|
||||
],
|
||||
date: [
|
||||
// 'date range',
|
||||
aggs.bucketAggsByName.date_histogram,
|
||||
aggs.bucketAggsByName.terms,
|
||||
],
|
||||
boolean: [
|
||||
aggs.bucketAggsByName.terms,
|
||||
// 'terms'
|
||||
],
|
||||
ip: [
|
||||
aggs.bucketAggsByName.terms,
|
||||
aggs.bucketAggsByName.ip_range,
|
||||
// 'ipv4 range'
|
||||
],
|
||||
geo_point: [
|
||||
aggs.bucketAggsByName.terms,
|
||||
// 'geo distance'
|
||||
],
|
||||
geo_shape: [
|
||||
aggs.bucketAggsByName.terms,
|
||||
// 'geohash grid'
|
||||
],
|
||||
string: [
|
||||
// 'significant terms',
|
||||
aggs.bucketAggsByName.terms,
|
||||
// 'range'
|
||||
]
|
||||
};
|
||||
|
||||
return aggs;
|
||||
};
|
||||
});
|
|
@ -1,53 +0,0 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var categories = [
|
||||
{
|
||||
name: 'segment',
|
||||
displayOrder: 2,
|
||||
fetchOrder: 1,
|
||||
min: 0,
|
||||
max: Infinity,
|
||||
configDefaults: {
|
||||
size: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'metric',
|
||||
displayOrder: 1,
|
||||
fetchOrder: 2,
|
||||
min: 0,
|
||||
max: 1,
|
||||
configDefaults: {
|
||||
agg: 'count'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'group',
|
||||
displayOrder: 3,
|
||||
fetchOrder: 3,
|
||||
min: 0,
|
||||
max: 1,
|
||||
configDefaults: {
|
||||
global: false,
|
||||
size: 5
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'split',
|
||||
displayOrder: 4,
|
||||
fetchOrder: 4,
|
||||
min: 0,
|
||||
max: 2,
|
||||
configDefaults: {
|
||||
size: 5,
|
||||
row: true
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
categories.fetchOrder = _.sortBy(categories, 'fetchOrder');
|
||||
categories.displayOrder = _.sortBy(categories, 'displayOrder');
|
||||
categories.byName = _.indexBy(categories, 'name');
|
||||
|
||||
return categories;
|
||||
});
|
|
@ -1,111 +0,0 @@
|
|||
define(function (require) {
|
||||
return function ReadConfigFn(Private, $injector) {
|
||||
var _ = require('lodash');
|
||||
var configCategories = require('apps/visualize/saved_visualizations/_config_categories');
|
||||
var aggs = Private(require('apps/visualize/saved_visualizations/_aggs'));
|
||||
var courier = require('components/courier/courier');
|
||||
|
||||
return function readConfig() {
|
||||
var vis = this;
|
||||
|
||||
// these arrays represent the different sections used to create an aggregation, and when config objects are encountered
|
||||
// the are pushed into these array's based on their properties. Array's are used to make the logic and the final
|
||||
// combination simple. Many of these will be limited to a single value by the UI
|
||||
var positions = {
|
||||
// used to create rows/columns
|
||||
split: [],
|
||||
// global segments (eg. color, marked in the ui to be applied gloabally and the same values should be used across all charts)
|
||||
global: [],
|
||||
// primary segments (eg. x-axis)
|
||||
segment: [],
|
||||
// local segments (eg. color, marked in the ui that it should apply within each chart)
|
||||
local: [],
|
||||
// metric is the root "measurement" (eg. y-axis)
|
||||
metric: []
|
||||
};
|
||||
|
||||
function moveValidatedParam(input, output, paramDef, name) {
|
||||
if (!input[name]) {
|
||||
if (paramDef.default != null) input[name] = _.cloneDeep(paramDef.default);
|
||||
else return !paramDef.required;
|
||||
}
|
||||
|
||||
var val = input[name];
|
||||
var selectedOption = paramDef.options && _.find(paramDef.options, { val: val });
|
||||
if (!paramDef.custom && paramDef.options && !selectedOption) return false;
|
||||
|
||||
if (paramDef.write) {
|
||||
var selection = selectedOption;
|
||||
// either the value is custom or there just aren't any options defined
|
||||
if (!selectedOption && val != null) selection = { val: val };
|
||||
|
||||
// provide a hook to apply custom logic when writing this config value
|
||||
paramDef.write(selection, output);
|
||||
} else {
|
||||
// copy over the param
|
||||
output.aggParams[name] = val;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function makeCategoryValidator(category) {
|
||||
return function categoryValidator(config) {
|
||||
// filter out plain unusable configs
|
||||
if (!config || !config.agg || !config.field) return;
|
||||
|
||||
// get the agg used by this config
|
||||
var agg = aggs.byName[config.agg];
|
||||
if (!agg || agg.name === 'count') return;
|
||||
|
||||
// copy parts of the config to the validated "output" object
|
||||
var output = {
|
||||
agg: config.agg,
|
||||
aggParams: {},
|
||||
categoryName: category.name
|
||||
};
|
||||
|
||||
if (agg.name !== 'filters') output.aggParams.field = config.field;
|
||||
|
||||
// copy over other properties based on the category
|
||||
switch (category.name) {
|
||||
case 'split':
|
||||
output.row = !!config.row;
|
||||
break;
|
||||
case 'group':
|
||||
output.global = !!config.global;
|
||||
break;
|
||||
}
|
||||
|
||||
// this function will move valus from config.* to output.aggParams.* when they are
|
||||
// needed for that aggregation, and return true or false based on if all requirements
|
||||
// are meet
|
||||
var moveToAggParams = _.partial(moveValidatedParam, config, output);
|
||||
|
||||
// ensure that all of the declared params for the agg are declared on the config
|
||||
if (_.every(agg.params, moveToAggParams)) return output;
|
||||
};
|
||||
}
|
||||
|
||||
// collect all of the configs from each category,
|
||||
// validate them, filter the invalid ones, and put them into positions
|
||||
configCategories.fetchOrder.forEach(function (category) {
|
||||
var configs = vis[category.name].configs;
|
||||
|
||||
configs = configs
|
||||
.map(makeCategoryValidator(category))
|
||||
.filter(Boolean);
|
||||
|
||||
if (category.name === 'group') {
|
||||
positions.global = _.where(configs, { global: true });
|
||||
positions.local = _.where(configs, { global: false });
|
||||
} else {
|
||||
positions[category.name] = configs;
|
||||
}
|
||||
});
|
||||
|
||||
// join all of the different positions into a single array
|
||||
return positions.global.concat(positions.split, positions.segment, positions.local, positions.metric);
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,206 +0,0 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var inherits = require('lodash').inherits;
|
||||
|
||||
var configCats = require('apps/visualize/saved_visualizations/_config_categories');
|
||||
var typeDefs = require('apps/visualize/saved_visualizations/_type_defs');
|
||||
|
||||
var module = require('modules').get('app/visualize');
|
||||
|
||||
module.factory('SavedVis', function (config, $injector, courier, indexPatterns, Promise, savedSearches, Private) {
|
||||
var aggs = Private(require('apps/visualize/saved_visualizations/_aggs'));
|
||||
|
||||
function SavedVis(opts) {
|
||||
var vis = this;
|
||||
opts = opts || {};
|
||||
|
||||
if (typeof opts !== 'object') {
|
||||
opts = {
|
||||
id: opts
|
||||
};
|
||||
}
|
||||
|
||||
var defaultParent = opts.parentSearchSource;
|
||||
|
||||
courier.SavedObject.call(vis, {
|
||||
type: 'visualization',
|
||||
|
||||
id: opts.id,
|
||||
|
||||
mapping: {
|
||||
title: 'string',
|
||||
typeName: 'string',
|
||||
stateJSON: 'string',
|
||||
description: 'string',
|
||||
savedSearchId: 'string',
|
||||
indexPattern: 'string'
|
||||
},
|
||||
|
||||
defaults: {
|
||||
title: '',
|
||||
typeName: opts.type || 'histogram',
|
||||
stateJSON: null,
|
||||
description: '',
|
||||
savedSearchId: opts.savedSearchId,
|
||||
indexPattern: opts.indexPattern
|
||||
},
|
||||
|
||||
searchSource: true,
|
||||
|
||||
afterESResp: function setVisState() {
|
||||
if (!vis.typeDef || vis.typeName !== vis.typeDef.name) {
|
||||
// refresh the typeDef
|
||||
vis.typeDef = typeDefs.byName[vis.typeName];
|
||||
// refresh the defaults for all config categories
|
||||
configCats.forEach(function (category) {
|
||||
vis._initConfigCategory(category, vis[category.name]);
|
||||
});
|
||||
}
|
||||
|
||||
// get the saved state
|
||||
var state;
|
||||
if (vis.stateJSON) try { state = JSON.parse(vis.stateJSON); } catch (e) {}
|
||||
|
||||
// set the state on the vis
|
||||
if (state) vis.setState(state);
|
||||
|
||||
var relatedSearch = vis.savedSearchId;
|
||||
var relatedPattern = !relatedSearch && vis.indexPattern;
|
||||
|
||||
var promisedParent = (function () {
|
||||
if (relatedSearch) {
|
||||
// returns a promise
|
||||
return savedSearches.get(vis.savedSearchId);
|
||||
}
|
||||
|
||||
var fakeSavedSearch = {
|
||||
searchSource: courier.createSource('search')
|
||||
};
|
||||
|
||||
if (relatedPattern) {
|
||||
return indexPatterns.get(relatedPattern)
|
||||
.then(function (indexPattern) {
|
||||
fakeSavedSearch.searchSource.index(indexPattern);
|
||||
return fakeSavedSearch;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(fakeSavedSearch);
|
||||
|
||||
}());
|
||||
|
||||
return promisedParent
|
||||
.then(function (parent) {
|
||||
vis.savedSearch = parent;
|
||||
|
||||
vis.searchSource
|
||||
.inherits(parent.searchSource)
|
||||
.size(0)
|
||||
// reads the vis' config and write the agg to the searchSource
|
||||
.aggs(function () {
|
||||
// stores the config objects in queryDsl
|
||||
var dsl = {};
|
||||
// counter to ensure unique agg names
|
||||
var i = 0;
|
||||
// start at the root, but the current will move
|
||||
var current = dsl;
|
||||
|
||||
// continue to nest the aggs under each other
|
||||
// writes to the dsl object
|
||||
vis.getConfig().forEach(function (config) {
|
||||
current.aggs = {};
|
||||
var key = '_agg_' + (i++);
|
||||
|
||||
var aggDsl = {};
|
||||
aggDsl[config.agg] = config.aggParams;
|
||||
|
||||
current = current.aggs[key] = aggDsl;
|
||||
});
|
||||
|
||||
// set the dsl to the searchSource
|
||||
return dsl.aggs || {};
|
||||
});
|
||||
|
||||
vis._fillConfigsToMinimum();
|
||||
|
||||
_.assign(vis, vis.typeDef.listeners);
|
||||
|
||||
return vis;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
vis.addConfig = function (categoryName) {
|
||||
var category = configCats.byName[categoryName];
|
||||
var config = _.defaults({}, category.configDefaults);
|
||||
|
||||
vis[category.name].configs.push(config);
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
vis.removeConfig = function (config) {
|
||||
if (!config) return;
|
||||
configCats.forEach(function (category) {
|
||||
_.pull(vis[category.name].configs, config);
|
||||
});
|
||||
};
|
||||
|
||||
vis._fillConfigsToMinimum = function () {
|
||||
|
||||
// satify the min count for each category
|
||||
configCats.fetchOrder.forEach(function (category) {
|
||||
var myCat = vis[category.name];
|
||||
|
||||
if (myCat.configs.length < myCat.min) {
|
||||
_.times(myCat.min - myCat.configs.length, function () {
|
||||
vis.addConfig(category.name);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// init the config category, optionally pass in an existing category to refresh
|
||||
// it's defaults based on the
|
||||
vis._initConfigCategory = function (category, cat) {
|
||||
cat = cat || {};
|
||||
|
||||
if (vis.typeDef) _.assign(cat, category, vis.typeDef.config[category.name]);
|
||||
cat.configDefaults = _.clone(category.configDefaults),
|
||||
cat.configs = cat.config || [];
|
||||
|
||||
vis[category.name] = cat;
|
||||
|
||||
return cat;
|
||||
};
|
||||
|
||||
vis.setState = function (state) {
|
||||
configCats.forEach(function (category) {
|
||||
var categoryStates = state[category.name] || [];
|
||||
vis[category.name].configs.splice(0);
|
||||
categoryStates.forEach(function (configState) {
|
||||
var config = vis.addConfig(category.name);
|
||||
_.assign(config, configState);
|
||||
});
|
||||
});
|
||||
|
||||
vis._fillConfigsToMinimum();
|
||||
};
|
||||
|
||||
vis.getState = function () {
|
||||
return _.transform(configCats, function (state, category) {
|
||||
var configs = state[category.name] = [];
|
||||
|
||||
[].push.apply(configs, vis[category.name].configs.map(function (config) {
|
||||
return _.pick(config, function (val, key) {
|
||||
return key.substring(0, 2) !== '$$';
|
||||
});
|
||||
}));
|
||||
}, {});
|
||||
};
|
||||
}
|
||||
inherits(SavedVis, courier.SavedObject);
|
||||
|
||||
return SavedVis;
|
||||
});
|
||||
});
|
|
@ -1,153 +0,0 @@
|
|||
define(function (require) {
|
||||
var module = require('modules').get('apps/visualize');
|
||||
var _ = require('lodash');
|
||||
|
||||
var typeDefs = [
|
||||
{
|
||||
name: 'histogram',
|
||||
icon: 'icon-chart-bar',
|
||||
params: {
|
||||
shareYAxis: true,
|
||||
addTooltip: true,
|
||||
addLegend: true
|
||||
},
|
||||
listeners: {
|
||||
onClick: function (e) {
|
||||
// TODO: We need to be able to get ahold of angular services here
|
||||
console.log(e);
|
||||
}
|
||||
},
|
||||
config: {
|
||||
metric: {
|
||||
label: 'Y-Axis',
|
||||
min: 1,
|
||||
max: 1
|
||||
},
|
||||
segment: {
|
||||
label: 'X-Axis',
|
||||
min: 1,
|
||||
max: 1
|
||||
},
|
||||
group: {
|
||||
label: 'Color',
|
||||
min: 0,
|
||||
max: 1
|
||||
},
|
||||
split: {
|
||||
label: 'Rows & Columns',
|
||||
min: 0,
|
||||
max: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'line',
|
||||
icon: 'icon-chart-bar',
|
||||
params: {
|
||||
shareYAxis: true,
|
||||
addTooltip: true,
|
||||
addLegend: true
|
||||
},
|
||||
listeners: {
|
||||
},
|
||||
config: {
|
||||
metric: {
|
||||
label: 'Y-Axis',
|
||||
min: 1,
|
||||
max: 1
|
||||
},
|
||||
segment: {
|
||||
// limitToOrderedAggs: true,
|
||||
label: 'X-Axis',
|
||||
min: 1,
|
||||
max: 1
|
||||
},
|
||||
group: {
|
||||
label: 'Color',
|
||||
min: 0,
|
||||
max: 1
|
||||
},
|
||||
split: {
|
||||
label: 'Rows & Columns',
|
||||
min: 0,
|
||||
max: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'area',
|
||||
icon: 'icon-chart-bar',
|
||||
params: {
|
||||
shareYAxis: true,
|
||||
addTooltip: true,
|
||||
addLegend: true,
|
||||
isStacked: true
|
||||
},
|
||||
listeners: {
|
||||
onClick: function (e) {
|
||||
// TODO: We need to be able to get ahold of angular services here
|
||||
console.log(e);
|
||||
}
|
||||
},
|
||||
config: {
|
||||
metric: {
|
||||
label: 'Y-Axis',
|
||||
min: 1,
|
||||
max: 1
|
||||
},
|
||||
segment: {
|
||||
// limitToOrderedAggs: true,
|
||||
label: 'X-Axis',
|
||||
min: 1,
|
||||
max: 1
|
||||
},
|
||||
group: {
|
||||
label: 'Color',
|
||||
min: 0,
|
||||
max: 1
|
||||
},
|
||||
split: {
|
||||
label: 'Rows & Columns',
|
||||
min: 0,
|
||||
max: 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'pie',
|
||||
icon: 'icon-chart-bar',
|
||||
params: {
|
||||
addTooltip: true,
|
||||
addLegend: true
|
||||
},
|
||||
listeners: {
|
||||
},
|
||||
config: {
|
||||
metric: {
|
||||
label: 'Y-Axis',
|
||||
min: 1,
|
||||
max: 1
|
||||
},
|
||||
segment: {
|
||||
label: 'X-Axis',
|
||||
min: 1,
|
||||
max: 1
|
||||
},
|
||||
group: {
|
||||
label: 'Color',
|
||||
min: 0,
|
||||
max: 1
|
||||
},
|
||||
split: {
|
||||
label: 'Rows & Columns',
|
||||
min: 0,
|
||||
max: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
typeDefs.byName = _.indexBy(typeDefs, 'name');
|
||||
|
||||
return typeDefs;
|
||||
});
|
|
@ -1,13 +0,0 @@
|
|||
define(function (require) {
|
||||
return function AggsService(Private) {
|
||||
return [
|
||||
Private(require('apps/visualize/saved_visualizations/bucket_aggs/date_histogram')),
|
||||
Private(require('apps/visualize/saved_visualizations/bucket_aggs/histogram')),
|
||||
Private(require('apps/visualize/saved_visualizations/bucket_aggs/range')),
|
||||
Private(require('apps/visualize/saved_visualizations/bucket_aggs/ip_range')),
|
||||
Private(require('apps/visualize/saved_visualizations/bucket_aggs/terms')),
|
||||
Private(require('apps/visualize/saved_visualizations/bucket_aggs/filters')),
|
||||
Private(require('apps/visualize/saved_visualizations/bucket_aggs/significant_terms'))
|
||||
];
|
||||
};
|
||||
});
|
|
@ -1,119 +0,0 @@
|
|||
define(function (require) {
|
||||
return function DateHistogramAggDefinition(timefilter, config) {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var interval = require('utils/interval');
|
||||
|
||||
// shorthand
|
||||
var ms = function (type) { return moment.duration(1, type).asMilliseconds(); };
|
||||
|
||||
var pickInterval = function (bounds, targetBuckets) {
|
||||
bounds || (bounds = timefilter.getBounds());
|
||||
return interval.calculate(bounds.min, bounds.max, targetBuckets);
|
||||
};
|
||||
|
||||
var agg = this;
|
||||
agg.name = 'date_histogram';
|
||||
agg.display = 'Date Histogram';
|
||||
agg.ordered = {date: true};
|
||||
|
||||
agg.makeLabel = function (params, fullConfig) {
|
||||
if (fullConfig.metricScaleText) return params.field + ' per ' + fullConfig.metricScaleText;
|
||||
|
||||
var aggInterval = _.find(agg.params.interval.options, { ms: interval.toMs(params.interval) });
|
||||
if (aggInterval) return aggInterval.display + ' ' + params.field;
|
||||
else return params.field + ' per ' + interval.describe(params.interval);
|
||||
};
|
||||
|
||||
agg.params = {};
|
||||
agg.params.interval = {
|
||||
required: true,
|
||||
default: 'auto',
|
||||
custom: true,
|
||||
options: [
|
||||
{
|
||||
display: 'Auto',
|
||||
val: 'auto'
|
||||
},
|
||||
{
|
||||
display: 'Second',
|
||||
val: 'second',
|
||||
ms: ms('second')
|
||||
},
|
||||
{
|
||||
display: 'Minute',
|
||||
val: 'minute',
|
||||
ms: ms('minute')
|
||||
},
|
||||
{
|
||||
display: 'Hourly',
|
||||
val: 'hour',
|
||||
ms: ms('hour')
|
||||
},
|
||||
{
|
||||
display: 'Daily',
|
||||
val: 'day',
|
||||
ms: ms('day')
|
||||
},
|
||||
{
|
||||
display: 'Weekly',
|
||||
val: 'week',
|
||||
ms: ms('week')
|
||||
},
|
||||
{
|
||||
display: 'Monthly',
|
||||
val: 'month',
|
||||
ms: ms('month')
|
||||
},
|
||||
{
|
||||
display: 'Yearly',
|
||||
val: 'year',
|
||||
ms: ms('year')
|
||||
}
|
||||
],
|
||||
|
||||
write: function (selection, output) {
|
||||
var bounds = timefilter.getBounds();
|
||||
var auto;
|
||||
|
||||
if (selection.val === 'auto') {
|
||||
var bucketTarget = config.get('histogram:barTarget');
|
||||
auto = pickInterval(bounds, bucketTarget);
|
||||
output.aggParams.interval = auto.interval + 'ms';
|
||||
output.metricScaleText = auto.description;
|
||||
return;
|
||||
}
|
||||
|
||||
var ms = selection.ms || interval.toMs(selection.val);
|
||||
var buckets = Math.ceil((bounds.max - bounds.min) / ms);
|
||||
var maxBuckets = config.get('histogram:maxBars');
|
||||
if (buckets > maxBuckets) {
|
||||
// we should round these buckets out, and scale back the y values
|
||||
auto = pickInterval(bounds, maxBuckets);
|
||||
output.aggParams.interval = auto.interval + 'ms';
|
||||
output.metricScale = ms / auto.interval;
|
||||
output.metricScaleText = selection.val || auto.description;
|
||||
} else {
|
||||
output.aggParams.interval = selection.val;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
agg.params.format = {
|
||||
hide: true,
|
||||
custom: true
|
||||
};
|
||||
|
||||
agg.params.extended_bounds = {
|
||||
hide: true,
|
||||
default: {},
|
||||
write: function (selection, output) {
|
||||
var bounds = timefilter.getBounds();
|
||||
output.aggParams.extended_bounds = {
|
||||
min: bounds.min,
|
||||
max: bounds.max
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,44 +0,0 @@
|
|||
define(function (require) {
|
||||
return function HistogramAggDefinition(timefilter, config) {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
|
||||
var agg = this;
|
||||
agg.name = 'histogram';
|
||||
agg.display = 'Histogram';
|
||||
agg.ordered = {};
|
||||
|
||||
agg.makeLabel = function (params) {
|
||||
return params.field;
|
||||
};
|
||||
|
||||
agg.params = {};
|
||||
agg.params.interval = {
|
||||
required: true,
|
||||
write: function (input, output) {
|
||||
output.aggParams.interval = parseInt(input.val, 10);
|
||||
}
|
||||
};
|
||||
|
||||
agg.params.min_doc_count = {
|
||||
custom: true,
|
||||
default: false,
|
||||
write: function (input, output) {
|
||||
if (input.val) output.aggParams.min_doc_count = 0;
|
||||
else delete output.aggParams.min_doc_count;
|
||||
}
|
||||
};
|
||||
|
||||
agg.params.extended_bounds = {
|
||||
default: {},
|
||||
write: function (input, output) {
|
||||
output.aggParams.extended_bounds = {
|
||||
min: input.val.min,
|
||||
max: input.val.max
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
});
|
|
@ -1,31 +0,0 @@
|
|||
define(function (require) {
|
||||
require('directives/validate_ip');
|
||||
|
||||
return function RangeAggDefinition(timefilter, config) {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var angular = require('angular');
|
||||
|
||||
var agg = this;
|
||||
agg.name = 'ip_range';
|
||||
agg.display = 'IP Range';
|
||||
//agg.ordered = {};
|
||||
|
||||
agg.makeLabel = function (params) {
|
||||
return params.field;
|
||||
};
|
||||
|
||||
agg.params = {};
|
||||
|
||||
agg.params.ranges = {
|
||||
custom: true,
|
||||
default: [{from: '0.0.0.0', to: '255.255.255.255'}],
|
||||
write: function (input, output) {
|
||||
output.aggParams.ranges = input.val;
|
||||
output.aggParams.keyed = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
});
|
|
@ -1,29 +0,0 @@
|
|||
define(function (require) {
|
||||
return function RangeAggDefinition(timefilter, config) {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var angular = require('angular');
|
||||
|
||||
var agg = this;
|
||||
agg.name = 'range';
|
||||
agg.display = 'Range';
|
||||
//agg.ordered = {};
|
||||
|
||||
agg.makeLabel = function (params) {
|
||||
return params.field;
|
||||
};
|
||||
|
||||
agg.params = {};
|
||||
|
||||
agg.params.ranges = {
|
||||
custom: true,
|
||||
default: [{from: 0, to: 1000}, {from: 1000, to: 2000}],
|
||||
write: function (input, output) {
|
||||
output.aggParams.ranges = input.val;
|
||||
output.aggParams.keyed = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
define(function (require) {
|
||||
return function SignificantTermsAggDefinition() {
|
||||
var _ = require('lodash');
|
||||
|
||||
var agg = this;
|
||||
agg.name = 'significant_terms';
|
||||
agg.display = 'Significant Terms';
|
||||
|
||||
agg.makeLabel = function (params) {
|
||||
return 'Top ' + params.size + ' unusual terms in ' + params.field;
|
||||
};
|
||||
|
||||
agg.params = {
|
||||
size: {
|
||||
required: false,
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,32 +0,0 @@
|
|||
define(function (require) {
|
||||
return function TermsAggDefinition() {
|
||||
var _ = require('lodash');
|
||||
|
||||
var agg = this;
|
||||
agg.name = 'terms';
|
||||
agg.display = 'Terms';
|
||||
|
||||
agg.makeLabel = function (params) {
|
||||
var order = _.find(agg.params.order.options, { val: params.order._count });
|
||||
return order.display + ' ' + params.size + ' ' + params.field;
|
||||
};
|
||||
|
||||
agg.params = {
|
||||
size: {
|
||||
required: false,
|
||||
},
|
||||
order: {
|
||||
required: true,
|
||||
options: [
|
||||
{ display: 'Top', val: 'desc' },
|
||||
{ display: 'Bottom', val: 'asc' }
|
||||
],
|
||||
default: 'desc',
|
||||
write: function (selection, output) {
|
||||
// TODO: We need more just _count here.
|
||||
output.aggParams.order = { _count: selection.val };
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,38 +0,0 @@
|
|||
define(function (require) {
|
||||
return function ConfigGroupFactory() {
|
||||
var _ = require('lodash');
|
||||
|
||||
function ConfigGroup(def, visTypeDef) {
|
||||
this.def = def;
|
||||
|
||||
this.list = [];
|
||||
this.name = this.def.name;
|
||||
|
||||
this.setTypeDef(visTypeDef);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Update properties that can be overridden by the typeDef
|
||||
// *
|
||||
// * @param {visTypeDef} typeDef
|
||||
// */
|
||||
// ConfigGroup.prototype.setTypeDef = function (typeDef) {
|
||||
// var merged = _.merge({},
|
||||
// typeDef.configGroupDefs.byName[this.def.name],
|
||||
// this.def
|
||||
// );
|
||||
|
||||
// this.min = merged.min || 0;
|
||||
// this.max = merged.max || Infinity;
|
||||
// this.label = merged.label || '';
|
||||
// };
|
||||
|
||||
ConfigGroup.prototype.add =
|
||||
ConfigGroup.prototype.move =
|
||||
ConfigGroup.prototype.remove = function (config) {
|
||||
throw new Error('not implemented');
|
||||
};
|
||||
|
||||
return ConfigGroup;
|
||||
};
|
||||
});
|
|
@ -1,138 +0,0 @@
|
|||
define(function (require) {
|
||||
return function HistogramConverterFn(Private, timefilter) {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var aggs = Private(require('apps/visualize/saved_visualizations/_aggs'));
|
||||
var interval = require('utils/interval');
|
||||
|
||||
return function (chart, columns, rows) {
|
||||
// index of color
|
||||
var iColor = _.findIndex(columns, { categoryName: 'group' });
|
||||
var hasColor = iColor !== -1;
|
||||
|
||||
/*****
|
||||
* Get values related to the X-Axis
|
||||
*****/
|
||||
|
||||
// index of the x-axis column
|
||||
var iX = _.findIndex(columns, { categoryName: 'segment'});
|
||||
// when we don't have an x-axis, just push everything into '_all'
|
||||
if (iX === -1) {
|
||||
iX = columns.push({
|
||||
label: ''
|
||||
}) - 1;
|
||||
}
|
||||
// column that defines the x-axis
|
||||
var colX = columns[iX];
|
||||
// aggregation for the x-axis
|
||||
var aggX = colX.agg && aggs.byName[colX.agg];
|
||||
|
||||
/*****
|
||||
* Get values related to the X-Axis
|
||||
*****/
|
||||
|
||||
// index of y-axis stuff
|
||||
var iY = _.findIndex(columns, { categoryName: 'metric'});
|
||||
// column for the y-axis
|
||||
var colY = columns[iY];
|
||||
|
||||
|
||||
/*****
|
||||
* Build the chart
|
||||
*****/
|
||||
|
||||
// X-axis description
|
||||
chart.xAxisLabel = colX.label;
|
||||
if (aggX && aggX.ordered && aggX.ordered.date) {
|
||||
chart.xAxisFormatter = (function () {
|
||||
var bounds = timefilter.getBounds();
|
||||
var format = interval.calculate(
|
||||
moment(bounds.min.valueOf()),
|
||||
moment(bounds.max.valueOf()),
|
||||
rows.length
|
||||
).format;
|
||||
|
||||
return function (thing) {
|
||||
return moment(thing).format(format);
|
||||
};
|
||||
}());
|
||||
|
||||
var timeBounds = timefilter.getBounds();
|
||||
chart.ordered = {
|
||||
date: true,
|
||||
min: timeBounds.min.valueOf(),
|
||||
max: timeBounds.max.valueOf(),
|
||||
interval: interval.toMs(colX.aggParams.interval)
|
||||
};
|
||||
}
|
||||
else {
|
||||
chart.xAxisFormatter = colX.field && colX.field.format.convert;
|
||||
chart.ordered = aggX && aggX.ordered && {};
|
||||
if (aggX !== false && colX && colX.aggParams && colX.aggParams.interval) {
|
||||
chart.ordered.interval = colX.aggParams.interval;
|
||||
}
|
||||
}
|
||||
|
||||
// Y-axis description
|
||||
chart.yAxisLabel = colY.label;
|
||||
if (colY.field) chart.yAxisFormatter = colY.field.format.convert;
|
||||
|
||||
|
||||
|
||||
// setup the formatter for the label
|
||||
chart.tooltipFormatter = function (datapoint) {
|
||||
var datum = _.clone(datapoint);
|
||||
|
||||
if (colX.field) datum.x = colX.field.format.convert(datum.x);
|
||||
if (colY.field) datum.y = colY.field.format.convert(datum.y);
|
||||
|
||||
if (colX.metricScaleText) {
|
||||
datum.y += ' per ' + colX.metricScaleText;
|
||||
}
|
||||
|
||||
|
||||
var out = datum.label ? datum.label + '\n' : '';
|
||||
out += datum.x + '\n';
|
||||
out += datum.y;
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
var series = chart.series = [];
|
||||
var seriesByLabel = {};
|
||||
|
||||
rows.forEach(function (row) {
|
||||
var seriesLabel = hasColor && row[iColor];
|
||||
var s = hasColor ? seriesByLabel[seriesLabel] : series[0];
|
||||
|
||||
if (!s) {
|
||||
// I know this could be simplified but I wanted to keep the key order
|
||||
if (hasColor) {
|
||||
s = {
|
||||
label: seriesLabel,
|
||||
values: []
|
||||
};
|
||||
seriesByLabel[seriesLabel] = s;
|
||||
} else {
|
||||
s = {
|
||||
values: []
|
||||
};
|
||||
}
|
||||
series.push(s);
|
||||
}
|
||||
|
||||
var datum = {
|
||||
x: (row[iX] == null) ? '_all' : row[iX],
|
||||
y: row[iY === -1 ? row.length - 1 : iY] // y-axis value
|
||||
};
|
||||
|
||||
if (colX.metricScale) {
|
||||
// support scaling response values to represent an average value on the y-axis
|
||||
datum.y = datum.y * colX.metricScale;
|
||||
}
|
||||
|
||||
s.values.push(datum);
|
||||
});
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,11 +0,0 @@
|
|||
define(function (require) {
|
||||
return function RespConvertersService(Private) {
|
||||
var histogram = Private(require('apps/visualize/saved_visualizations/resp_converters/histogram'));
|
||||
return {
|
||||
histogram: histogram,
|
||||
line: histogram,
|
||||
area: histogram,
|
||||
pie: histogram
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,64 +0,0 @@
|
|||
define(function (require) {
|
||||
var app = require('modules').get('apps/visualize');
|
||||
var typeDefs = require('apps/visualize/saved_visualizations/_type_defs');
|
||||
var _ = require('lodash');
|
||||
|
||||
require('apps/visualize/saved_visualizations/_saved_vis');
|
||||
|
||||
// Register this service with the saved object registry so it can be
|
||||
// edited by the object editor.
|
||||
require('apps/settings/saved_object_registry').register({
|
||||
service: 'savedVisualizations',
|
||||
title: 'visualizations'
|
||||
});
|
||||
|
||||
app.service('savedVisualizations', function (Promise, es, config, SavedVis) {
|
||||
|
||||
this.get = function (id) {
|
||||
return (new SavedVis(id)).init();
|
||||
};
|
||||
|
||||
this.urlFor = function (id) {
|
||||
return '#/visualize/edit/' + encodeURIComponent(id);
|
||||
};
|
||||
|
||||
this.delete = function (ids) {
|
||||
ids = !_.isArray(ids) ? [ids] : ids;
|
||||
return Promise.map(ids, function (id) {
|
||||
return (new SavedVis(id)).delete();
|
||||
});
|
||||
};
|
||||
|
||||
this.find = function (searchString) {
|
||||
var self = this;
|
||||
var body = searchString ? {
|
||||
query: {
|
||||
simple_query_string: {
|
||||
query: searchString + '*',
|
||||
fields: ['title^3', 'description'],
|
||||
default_operator: 'AND'
|
||||
}
|
||||
}
|
||||
}: { query: {match_all: {}}};
|
||||
return es.search({
|
||||
index: config.file.kibanaIndex,
|
||||
type: 'visualization',
|
||||
body: body,
|
||||
size: 100,
|
||||
})
|
||||
.then(function (resp) {
|
||||
return {
|
||||
total: resp.hits.total,
|
||||
hits: resp.hits.hits.map(function (hit) {
|
||||
var source = hit._source;
|
||||
source.id = hit._id;
|
||||
source.url = self.urlFor(hit._id);
|
||||
source.typeDef = typeDefs.byName[source.typeName];
|
||||
source.icon = source.typeDef.icon;
|
||||
return source;
|
||||
})
|
||||
};
|
||||
});
|
||||
};
|
||||
});
|
||||
});
|
|
@ -1,16 +0,0 @@
|
|||
<div ng-show="spyMode.name === 'request'">
|
||||
<pre>{{history[0].req | json}}</pre>
|
||||
</div>
|
||||
|
||||
<div ng-show="spyMode.name === 'response'">
|
||||
<pre>{{history[0].resp | json}}</pre>
|
||||
</div>
|
||||
|
||||
<div ng-show="spyMode.name === 'stats'">
|
||||
<table class="table">
|
||||
<tr ng-repeat="pair in history[0].meta">
|
||||
<td>{{pair[0]}}</td>
|
||||
<td>{{pair[1]}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
|
@ -1,56 +0,0 @@
|
|||
define(function (require) {
|
||||
return function VisSpyReqRespStats() {
|
||||
var reqRespStatsHTML = require('text!apps/visualize/spy/_req_resp_stats.html');
|
||||
var linkReqRespStats = function ($scope, config) {
|
||||
$scope.$watchCollection('vis.searchSource.history', function (searchHistory) {
|
||||
if (!searchHistory) {
|
||||
$scope.history = [];
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.history = searchHistory.map(function (entry) {
|
||||
if (!entry.complete || !entry.state) return;
|
||||
|
||||
var state = entry.state;
|
||||
var resp = entry.resp;
|
||||
var meta = [];
|
||||
|
||||
if (resp && resp.took != null) meta.push(['Query Duration', resp.took + 'ms']);
|
||||
if (entry && entry.ms != null) meta.push(['Request Duration', entry.ms + 'ms']);
|
||||
if (resp && resp.hits) meta.push(['Hits', resp.hits.total]);
|
||||
|
||||
if (state.index) meta.push(['Index', state.index]);
|
||||
if (state.type) meta.push(['Type', state.type]);
|
||||
if (state.id) meta.push(['Id', state.id]);
|
||||
|
||||
return {
|
||||
meta: meta,
|
||||
req: state.body,
|
||||
resp: entry.resp
|
||||
};
|
||||
}).filter(Boolean);
|
||||
});
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
name: 'request',
|
||||
display: 'Request',
|
||||
template: reqRespStatsHTML,
|
||||
link: linkReqRespStats
|
||||
},
|
||||
{
|
||||
name: 'response',
|
||||
display: 'Response',
|
||||
template: reqRespStatsHTML,
|
||||
link: linkReqRespStats
|
||||
},
|
||||
{
|
||||
name: 'stats',
|
||||
display: 'Statistics',
|
||||
template: reqRespStatsHTML,
|
||||
link: linkReqRespStats
|
||||
}
|
||||
];
|
||||
};
|
||||
});
|
|
@ -1,12 +0,0 @@
|
|||
<div ng-click="toggleDisplay()" class="visualize-show-spy">
|
||||
<small>
|
||||
<i class="fa" ng-class="spyMode ? 'fa-chevron-down' : 'fa-chevron-up'"></i>
|
||||
</small>
|
||||
</div>
|
||||
<ul ng-if="spyMode" class="nav nav-tabs visualize-spy-tabs">
|
||||
<li
|
||||
ng-repeat="mode in modes"
|
||||
ng-class="{ active: spyMode.name === mode.name }">
|
||||
<a ng-click="setSpyMode(mode)">{{mode.display}}</a>
|
||||
</li>
|
||||
</ul>
|
|
@ -1,26 +0,0 @@
|
|||
<paginate list="rows" per-page="10">
|
||||
<table class="table table-condensed visualize-table">
|
||||
<thead>
|
||||
<tr bindonce>
|
||||
<th
|
||||
ng-repeat="col in columns track by $index"
|
||||
ng-click="cycleSort(col)"
|
||||
ng-class="getColumnClass(columns, $first, $last)">
|
||||
<span bo-text="col"></span>
|
||||
<i
|
||||
class="fa"
|
||||
ng-class="{
|
||||
'fa-sort-asc': sort.field === col && sort.asc === true,
|
||||
'fa-sort-desc': sort.field === col && sort.asc === false,
|
||||
'fa-sort': !sort || sort.field !== col
|
||||
}">
|
||||
</i>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody kbn-rows="page" kbn-rows-min="paginate.perPage"></tbody>
|
||||
</table>
|
||||
<a class="small" ng-click="exportAsCsv()">
|
||||
Export <i class="fa fa-download"></i>
|
||||
</a>
|
||||
</paginate>
|
|
@ -1,137 +0,0 @@
|
|||
define(function (require) {
|
||||
var module = require('modules').get('app/visualize');
|
||||
var _ = require('lodash');
|
||||
var saveAs = require('file_saver');
|
||||
|
||||
return function VisSpyTable(Notifier, $filter, $rootScope, config) {
|
||||
return {
|
||||
name: 'table',
|
||||
display: 'Table',
|
||||
template: require('text!apps/visualize/spy/_table.html'),
|
||||
link: function tableLinkFn($scope, $el) {
|
||||
var notify = new Notifier();
|
||||
var orderBy = $filter('orderBy');
|
||||
|
||||
$scope.sort = null;
|
||||
$scope.csv = {
|
||||
showOptions: false,
|
||||
separator: config.get('csv:separator'),
|
||||
quoteValues: config.get('csv:quoteValues'),
|
||||
filename: 'table.csv'
|
||||
};
|
||||
|
||||
$scope.getColumnClass = function (col, $first, $last) {
|
||||
var cls = [];
|
||||
|
||||
if ($last || $scope.fields && $scope.fields[col] && $scope.fields[col].type === 'number') {
|
||||
cls.push('visualize-table-right');
|
||||
}
|
||||
|
||||
if (!$scope.sort || $scope.sort.field !== col) {
|
||||
cls.push('no-sort');
|
||||
}
|
||||
|
||||
return cls.join(' ');
|
||||
};
|
||||
|
||||
$scope.cycleSort = function (col) {
|
||||
if (!$scope.sort || $scope.sort.field !== col) {
|
||||
$scope.sort = {
|
||||
field: col,
|
||||
asc: true
|
||||
};
|
||||
} else if ($scope.sort.asc) {
|
||||
$scope.sort.asc = false;
|
||||
} else {
|
||||
delete $scope.sort;
|
||||
}
|
||||
|
||||
if ($scope.sort && !$scope.sort.getter) {
|
||||
var fieldi = $scope.columns.indexOf($scope.sort.field);
|
||||
$scope.sort.getter = function (row) {
|
||||
return row[fieldi];
|
||||
};
|
||||
if (fieldi === -1) delete $scope.sort;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.exportAsCsv = function () {
|
||||
$scope.csv.showOptions = false;
|
||||
if (!$scope.chartData) return;
|
||||
|
||||
var text = '';
|
||||
var nonAlphaNumRE = /[^a-zA-Z0-9]/;
|
||||
var allDoubleQuoteRE = /"/g;
|
||||
var escape = function (val) {
|
||||
val = String(val);
|
||||
if ($scope.csv.quoteValues && nonAlphaNumRE.test(val)) {
|
||||
val = '"' + val.replace(allDoubleQuoteRE, '""') + '"';
|
||||
}
|
||||
return val;
|
||||
};
|
||||
|
||||
var raw = $scope.chartData.raw;
|
||||
var rows = new Array(raw.rows.length + 1);
|
||||
var colRow = [];
|
||||
rows[0] = colRow;
|
||||
|
||||
raw.columns.forEach(function (col) {
|
||||
colRow.push(escape(col.aggParams ? col.aggParams.field : 'count'));
|
||||
});
|
||||
|
||||
raw.rows.forEach(function (rawRow, i) {
|
||||
var row = new Array(rawRow.length);
|
||||
rows[i + 1] = row;
|
||||
|
||||
rawRow.forEach(function (cell, i) {
|
||||
row[i] = escape(cell);
|
||||
});
|
||||
});
|
||||
|
||||
var blob = new Blob(rows.map(function (row) {
|
||||
return row.join($scope.csv.separator) + '\r\n';
|
||||
}), { type: 'text/plain' });
|
||||
|
||||
saveAs(blob, $scope.csv.filename);
|
||||
};
|
||||
|
||||
$rootScope.$watchMulti.call($scope, [
|
||||
'chartData',
|
||||
'sort.asc',
|
||||
'sort.field'
|
||||
], function () {
|
||||
$scope.rows = null;
|
||||
$scope.columns = null;
|
||||
|
||||
if (!$scope.chartData) return;
|
||||
|
||||
notify.event('flatten data for table', function () {
|
||||
// flatten the fields to a list of strings
|
||||
$scope.columns = [];
|
||||
// collect the formatter for each column, in order
|
||||
var formats = [];
|
||||
|
||||
// populate columns and formates
|
||||
$scope.chartData.raw.columns.forEach(function (col) {
|
||||
$scope.columns.push(col.aggParams ? col.aggParams.field : 'count');
|
||||
formats.push(col.field ? col.field.format.convert : _.identity);
|
||||
});
|
||||
|
||||
|
||||
$scope.rows = $scope.chartData.raw.rows;
|
||||
|
||||
// sort the row values
|
||||
if ($scope.sort) $scope.rows = orderBy($scope.rows, $scope.sort.getter, $scope.sort.asc);
|
||||
|
||||
// format all row values
|
||||
$scope.rows = $scope.rows.map(function (row) {
|
||||
return row.map(function (cell, i) {
|
||||
return formats[i](cell);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
|
@ -1,69 +0,0 @@
|
|||
define(function (require) {
|
||||
require('modules')
|
||||
.get('apps/visualize')
|
||||
.directive('visualizeSpy', function (Private, $compile) {
|
||||
var $ = require('jquery');
|
||||
var _ = require('lodash');
|
||||
|
||||
var modes = _.flatten([
|
||||
Private(require('apps/visualize/spy/_table')),
|
||||
Private(require('apps/visualize/spy/_req_resp_stats'))
|
||||
]);
|
||||
var defaultMode = modes[0];
|
||||
modes.byName = _.indexBy(modes, 'name');
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: require('text!apps/visualize/spy/_spy.html'),
|
||||
link: function ($scope, $el) {
|
||||
$scope.spyMode = null;
|
||||
$scope.modes = modes;
|
||||
|
||||
$scope.toggleDisplay = function () {
|
||||
$scope.setSpyMode($scope.spyMode ? null : defaultMode);
|
||||
};
|
||||
|
||||
$scope.setSpyMode = function (newMode) {
|
||||
// allow passing in a mode name
|
||||
if (_.isString(newMode)) newMode = modes.byName[newMode];
|
||||
|
||||
var current = $scope.spyMode;
|
||||
var change = false;
|
||||
|
||||
function set() {
|
||||
// no change
|
||||
if (current && newMode && newMode.name === current.name) return;
|
||||
|
||||
// clear the current value
|
||||
if (current) {
|
||||
current.$container.remove();
|
||||
current.$scope.$destroy();
|
||||
delete $scope.spyMode;
|
||||
current = null;
|
||||
change = true;
|
||||
}
|
||||
|
||||
// no further changes
|
||||
if (!newMode) return;
|
||||
|
||||
change = true;
|
||||
current = $scope.spyMode = {
|
||||
// copy a couple values over
|
||||
name: newMode.name,
|
||||
display: newMode.display,
|
||||
$scope: $scope.$new(),
|
||||
$container: $('<div class="visualize-spy-container">').appendTo($el)
|
||||
};
|
||||
|
||||
current.$container.append($compile(newMode.template)(current.$scope));
|
||||
newMode.link(current.$scope, current.$container);
|
||||
}
|
||||
|
||||
// wrapped in fn to enable early return
|
||||
set();
|
||||
if (change) $scope.$emit('change:spyMode', newMode);
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
|
@ -1,103 +0,0 @@
|
|||
@import (reference) "../../../styles/_bootstrap.less";
|
||||
@import (reference) "../../../styles/theme/_theme.less";
|
||||
@import (reference) "../../../styles/_variables.less";
|
||||
@import (reference) "lesshat.less";
|
||||
|
||||
@media (min-width: @screen-md-min) {
|
||||
.vis-editor-content {
|
||||
display: flex;
|
||||
.flex-direction(row);
|
||||
.justify-content(flex-start);
|
||||
|
||||
.vis-sidebar {
|
||||
.flex(0, 0, 300px);
|
||||
}
|
||||
|
||||
.vis-canvas {
|
||||
.flex(1, 1, 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vis-editor-content {
|
||||
vis-config-editor {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sidebar-item-title:hover {
|
||||
color: inherit !important;
|
||||
background-color: inherit !important;
|
||||
}
|
||||
|
||||
.vis-config-details {
|
||||
border-top: 1px solid @well-border;
|
||||
padding: 5px 10px;
|
||||
background-color: @body-bg;
|
||||
color: @text-color;
|
||||
|
||||
.config-controls {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.agg-config-interval {
|
||||
td {
|
||||
padding-left: 10px;
|
||||
&:first-child {
|
||||
padding-left: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vis-wizard {
|
||||
h1 {
|
||||
margin-top: 45px;
|
||||
}
|
||||
}
|
||||
|
||||
vis-canvas {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vis-editor navbar {
|
||||
.bitty-modal-container {
|
||||
position: relative;
|
||||
|
||||
.bitty-modal {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
z-index: 10;
|
||||
background: rgba(70, 82, 93, 0.9);
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding-top: 6px;
|
||||
.user-select(none);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
form.vis-share {
|
||||
div.form-control {
|
||||
height: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
// vis-search-editor {
|
||||
// display: block;
|
||||
// background: @sidebar-bg;
|
||||
// text-align: center;
|
||||
// min-height: 0;
|
||||
// border-bottom: 1px solid darken(@sidebar-bg, 10%);
|
||||
// .user-select(none);
|
||||
|
||||
// color: @sidebar-color;
|
||||
// a {
|
||||
// color: @sidebar-color;
|
||||
// }
|
||||
// }
|
|
@ -1,130 +0,0 @@
|
|||
@import (reference) "../../../styles/_bootstrap.less";
|
||||
@import (reference) "../../../styles/theme/_theme.less";
|
||||
@import (reference) "../../../styles/_variables.less";
|
||||
@import (reference) "lesshat.less";
|
||||
|
||||
visualize {
|
||||
.display(flex);
|
||||
.flex-direction(column);
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
|
||||
.visualize-error {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
font-size: 1em;
|
||||
|
||||
.fa-exclamation-triangle {
|
||||
font-size: 2em;
|
||||
color: @btn-danger-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.k4tip {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.visualize-chart {
|
||||
.flex(1, 1);
|
||||
overflow: hidden;
|
||||
|
||||
&.spy-visible {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
&.spy-only {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visualize-spy {
|
||||
// this element should flex
|
||||
.flex(0, 0, auto);
|
||||
|
||||
// it's children should also flex vertically
|
||||
.flex-direction(column);
|
||||
.display(flex);
|
||||
|
||||
overflow: auto;
|
||||
padding-top: 10px;
|
||||
|
||||
&.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&.only {
|
||||
.flex(1, 1, auto);
|
||||
padding-top: 0px;
|
||||
}
|
||||
|
||||
.visualize-show-spy {
|
||||
.flex(0, 0, auto);
|
||||
background-color: @well-bg;
|
||||
text-align: center;
|
||||
|
||||
i {
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.visualize-spy-container {
|
||||
.flex(1, 1, auto);
|
||||
|
||||
.display(flex);
|
||||
.flex-direction(column);
|
||||
|
||||
padding: 10px 10px 0;
|
||||
overflow-y: auto;
|
||||
|
||||
tr > td {
|
||||
font-size: 0.85em;
|
||||
}
|
||||
}
|
||||
|
||||
// this is the default, double-arrow sort that is just a hint to the user that they can sort
|
||||
.visualize-table th i.fa-sort {
|
||||
color: @gray-light;
|
||||
}
|
||||
|
||||
.visualize-table-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.visualize-table-controls {
|
||||
padding: 0 5px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.visualize-csv-options {
|
||||
.form-control {
|
||||
padding: 0px 6px;
|
||||
height: auto;
|
||||
}
|
||||
label {
|
||||
margin: 0 10px;
|
||||
padding: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
.visualize-csv-separator {
|
||||
width: 1.5em;
|
||||
}
|
||||
button[type=submit] {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.visualize-spy-tabs {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
.flex(0, 0, auto);
|
||||
}
|
||||
|
||||
pre {
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue