mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
This reverts commit 3000221fac
.
This change broke Xpack, due to some modules being moved to a different location.
This commit is contained in:
parent
363a06555c
commit
c20a48cbc9
170 changed files with 3003 additions and 2837 deletions
|
@ -1,22 +1,22 @@
|
|||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import pointSeriesTemplate from 'plugins/kbn_vislib_vis_types/editors/point_series.html';
|
||||
import image from './images/icon-area.svg';
|
||||
|
||||
export default function PointSeriesVisType(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return VisFactory.createVislibVisualization({
|
||||
return new VislibVisType({
|
||||
name: 'area',
|
||||
title: 'Area',
|
||||
image,
|
||||
description: 'Emphasize the quantity beneath a line chart',
|
||||
category: CATEGORY.BASIC,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.BASIC,
|
||||
params: {
|
||||
defaults: {
|
||||
type: 'area',
|
||||
grid: {
|
||||
categoryLines: false,
|
||||
style: {
|
||||
|
@ -29,7 +29,8 @@ export default function PointSeriesVisType(Private) {
|
|||
type: 'category',
|
||||
position: 'bottom',
|
||||
show: true,
|
||||
style: {},
|
||||
style: {
|
||||
},
|
||||
scale: {
|
||||
type: 'linear'
|
||||
},
|
||||
|
@ -47,7 +48,8 @@ export default function PointSeriesVisType(Private) {
|
|||
type: 'value',
|
||||
position: 'left',
|
||||
show: true,
|
||||
style: {},
|
||||
style: {
|
||||
},
|
||||
scale: {
|
||||
type: 'linear',
|
||||
mode: 'normal'
|
||||
|
@ -82,34 +84,31 @@ export default function PointSeriesVisType(Private) {
|
|||
times: [],
|
||||
addTimeMarker: false,
|
||||
},
|
||||
},
|
||||
editorConfig: {
|
||||
collections: {
|
||||
positions: ['top', 'left', 'right', 'bottom'],
|
||||
chartTypes: [{
|
||||
value: 'line',
|
||||
text: 'line'
|
||||
}, {
|
||||
value: 'area',
|
||||
text: 'area'
|
||||
}, {
|
||||
value: 'histogram',
|
||||
text: 'bar'
|
||||
}],
|
||||
axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'],
|
||||
scaleTypes: ['linear', 'log', 'square root'],
|
||||
chartModes: ['normal', 'stacked'],
|
||||
interpolationModes: [{
|
||||
value: 'linear',
|
||||
text: 'straight',
|
||||
}, {
|
||||
value: 'cardinal',
|
||||
text: 'smoothed',
|
||||
}, {
|
||||
value: 'step-after',
|
||||
text: 'stepped',
|
||||
}],
|
||||
},
|
||||
positions: ['top', 'left', 'right', 'bottom'],
|
||||
chartTypes: [{
|
||||
value: 'line',
|
||||
text: 'line'
|
||||
}, {
|
||||
value: 'area',
|
||||
text: 'area'
|
||||
}, {
|
||||
value: 'histogram',
|
||||
text: 'bar'
|
||||
}],
|
||||
axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'],
|
||||
scaleTypes: ['linear', 'log', 'square root'],
|
||||
chartModes: ['normal', 'stacked'],
|
||||
interpolationModes: [{
|
||||
value: 'linear',
|
||||
text: 'straight',
|
||||
}, {
|
||||
value: 'cardinal',
|
||||
text: 'smoothed',
|
||||
}, {
|
||||
value: 'step-after',
|
||||
text: 'stepped',
|
||||
}],
|
||||
editor: pointSeriesTemplate,
|
||||
optionTabs: [
|
||||
{
|
||||
name: 'advanced',
|
||||
|
@ -119,50 +118,50 @@ export default function PointSeriesVisType(Private) {
|
|||
},
|
||||
{ name: 'options', title: 'Panel Settings', editor: pointSeriesTemplate },
|
||||
],
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Y-Axis',
|
||||
aggFilter: ['!geo_centroid'],
|
||||
min: 1,
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'radius',
|
||||
title: 'Dot Size',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality']
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'X-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Series',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
}
|
||||
},
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Y-Axis',
|
||||
aggFilter: ['!geo_centroid'],
|
||||
min: 1,
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'radius',
|
||||
title: 'Dot Size',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality']
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'X-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Series',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
id="gaugeType"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.gauge.gaugeType"
|
||||
ng-options="mode for mode in collections.gaugeTypes"
|
||||
ng-options="mode for mode in vis.type.params.gaugeTypes"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -183,7 +183,7 @@
|
|||
id="colorSchema"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.gauge.colorSchema"
|
||||
ng-options="mode for mode in collections.colorSchemas"
|
||||
ng-options="mode for mode in vis.type.params.colorSchemas"
|
||||
></select>
|
||||
</div>
|
||||
<div class="text-info text-center" ng-show="customColors" ng-click="resetColors()">reset colors</div>
|
||||
|
@ -255,7 +255,7 @@
|
|||
id="gaugeColorMode"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.gauge.gaugeColorMode"
|
||||
ng-options="mode for mode in collections.gaugeColorMode"
|
||||
ng-options="mode for mode in vis.type.params.gaugeColorMode"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,7 @@ module.directive('gaugeOptions', function () {
|
|||
template: gaugeOptionsTemplate,
|
||||
replace: true,
|
||||
link: function ($scope) {
|
||||
$scope.collections = $scope.vis.type.editorConfig.collections;
|
||||
|
||||
$scope.showColorRange = true;
|
||||
|
||||
$scope.$watch('vis.params.gauge.gaugeType', type => {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
id="colorSchema"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.colorSchema"
|
||||
ng-options="mode for mode in collections.colorSchemas"
|
||||
ng-options="mode for mode in vis.type.params.colorSchemas"
|
||||
></select>
|
||||
</div>
|
||||
<div
|
||||
|
@ -39,7 +39,7 @@
|
|||
id="axisScale"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.valueAxes[0].scale.type"
|
||||
ng-options="mode for mode in collections.scales"
|
||||
ng-options="mode for mode in vis.type.params.scales"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -141,7 +141,7 @@
|
|||
ng-click="removeRange($index)"
|
||||
class="kuiButton kuiButton--danger kuiButton--small"
|
||||
>
|
||||
<span class="kuiIcon fa-times"></span>
|
||||
<span class="kuiIcon fa-times"><span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -149,7 +149,7 @@
|
|||
|
||||
<div class="hintbox" ng-show="!vis.params.colorsRange.length">
|
||||
<p>
|
||||
<span class="kuiIcon fa-danger text-danger"></span>
|
||||
<span class="kuiIcon fa-danger text-danger"><span>
|
||||
<strong>Required:</strong> You must specify at least one range.
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -9,9 +9,6 @@ module.directive('heatmapOptions', function () {
|
|||
template: heatmapOptionsTemplate,
|
||||
replace: true,
|
||||
link: function ($scope) {
|
||||
|
||||
$scope.collections = $scope.vis.type.editorConfig.collections;
|
||||
|
||||
const verticalRotation = 270;
|
||||
$scope.showColorRange = false;
|
||||
$scope.showLabels = false;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
id="categoryAxisPosition"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.categoryAxes[0].position"
|
||||
ng-options="mode for mode in vis.type.editorConfig.collections.positions"
|
||||
ng-options="mode for mode in vis.type.params.positions"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
id="{{ 'seriesType' + $index }}"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="chart.type"
|
||||
ng-options="mode.value as mode.text for mode in vis.type.editorConfig.collections.chartTypes"
|
||||
ng-options="mode.value as mode.text for mode in vis.type.params.chartTypes"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -54,7 +54,7 @@
|
|||
id="{{ 'seriesMode' + $index }}"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="chart.mode"
|
||||
ng-options="mode for mode in vis.type.editorConfig.collections.chartModes"
|
||||
ng-options="mode for mode in vis.type.params.chartModes"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -86,7 +86,7 @@
|
|||
id="{{ 'lineMode' + $index }}"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="chart.interpolate"
|
||||
ng-options="mode.value as mode.text for mode in vis.type.editorConfig.collections.interpolationModes"
|
||||
ng-options="mode.value as mode.text for mode in vis.type.params.interpolationModes"
|
||||
>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -61,7 +61,7 @@ module.directive('vislibSeries', function () {
|
|||
return $scope.vis.params.seriesParams.map(series => series.type).join();
|
||||
}, () => {
|
||||
const types = _.uniq(_.map($scope.vis.params.seriesParams, 'type'));
|
||||
$scope.vis.type.type = types.length === 1 ? types[0] : 'histogram';
|
||||
$scope.savedVis.type = types.length === 1 ? types[0] : 'histogram';
|
||||
});
|
||||
|
||||
$scope.$watch('vis.params.valueAxes.length', () => {
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-change="updateAxisName(axis)"
|
||||
ng-model="axis.position"
|
||||
ng-options="mode disable when isPositionDisabled(mode) for mode in vis.type.editorConfig.collections.positions"
|
||||
ng-options="mode disable when isPositionDisabled(mode) for mode in vis.type.params.positions"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -98,7 +98,7 @@
|
|||
id="{{ 'valueAxisMode' + $index }}"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="axis.scale.mode"
|
||||
ng-options="mode for mode in vis.type.editorConfig.collections.axisModes"
|
||||
ng-options="mode for mode in vis.type.params.axisModes"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -112,7 +112,7 @@
|
|||
id="{{ 'valueAxisScaleType' + $index }}"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="axis.scale.type"
|
||||
ng-options="type for type in vis.type.editorConfig.collections.scaleTypes"
|
||||
ng-options="type for type in vis.type.params.scaleTypes"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<select
|
||||
class="form-control"
|
||||
ng-model="vis.params.legendPosition"
|
||||
ng-options="position.value as position.text for position in vis.type.editorConfig.collections.legendPositions"
|
||||
ng-options="position.value as position.text for position in vis.type.params.legendPositions"
|
||||
>
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -20,7 +20,7 @@ describe('point series editor', function () {
|
|||
function makeConfig() {
|
||||
return {
|
||||
type: 'line',
|
||||
params: lineVisType.visConfig.defaults,
|
||||
params: lineVisType.params.defaults,
|
||||
aggs: [
|
||||
{ type: 'count', schema: 'metric', params: { field: 'bytes' } },
|
||||
{ type: 'terms', schema: 'segment', params: { field: 'machine.os' } },
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
id="legendPosition"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.legendPosition"
|
||||
ng-options="position.value as position.text for position in vis.type.editorConfig.collections.legendPositions"
|
||||
ng-options="position.value as position.text for position in vis.type.params.legendPositions"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
<select name="agg"
|
||||
class="form-control"
|
||||
ng-model="vis.params.mapType"
|
||||
ng-init="vis.params.mapType || vis.type.editorConfig.collections.mapTypes[0]"
|
||||
ng-options="mapType as mapType for mapType in vis.type.editorConfig.collections.mapTypes"
|
||||
ng-init="vis.params.mapType || vis.type.params.mapTypes[0]"
|
||||
ng-options="mapType as mapType for mapType in vis.type.params.mapTypes"
|
||||
>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -104,7 +104,7 @@
|
|||
<label>
|
||||
<input type="checkbox"
|
||||
name="isDesaturated"
|
||||
ng-disabled="!vis.type.visConfig.canDesaturate"
|
||||
ng-disabled="!vis.type.params.canDesaturate"
|
||||
ng-model="vis.params.isDesaturated">
|
||||
|
||||
Desaturate map tiles
|
|
@ -1,24 +1,24 @@
|
|||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import gaugeTemplate from 'plugins/kbn_vislib_vis_types/editors/gauge.html';
|
||||
import { vislibColorMaps } from 'ui/vislib/components/color/colormaps';
|
||||
import image from './images/icon-gauge.svg';
|
||||
|
||||
export default function GaugeVisType(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return VisFactory.createVislibVisualization({
|
||||
return new VislibVisType({
|
||||
name: 'gauge',
|
||||
title: 'Gauge',
|
||||
image,
|
||||
description: `Gauges indicate the status of a metric. Use it to show how a metric's value relates
|
||||
to reference threshold values.`,
|
||||
category: CATEGORY.DATA,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.DATA,
|
||||
params: {
|
||||
defaults: {
|
||||
type:'gauge',
|
||||
addTooltip: true,
|
||||
addLegend: true,
|
||||
|
||||
|
@ -61,37 +61,35 @@ export default function GaugeVisType(Private) {
|
|||
}
|
||||
}
|
||||
},
|
||||
gaugeTypes: ['Arc', 'Circle', 'Metric'],
|
||||
gaugeColorMode: ['None', 'Labels', 'Background'],
|
||||
gaugeStyles: ['Full', 'Bars', 'Lines'],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
editor: gaugeTemplate
|
||||
},
|
||||
editorConfig: {
|
||||
collections: {
|
||||
gaugeTypes: ['Arc', 'Circle', 'Metric'],
|
||||
gaugeColorMode: ['None', 'Labels', 'Background'],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
implementsRenderComplete: true,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
min: 1,
|
||||
aggFilter: [
|
||||
'!std_dev', '!geo_centroid', '!percentiles', '!percentile_ranks',
|
||||
'!derivative', '!serial_diff', '!moving_avg', '!cumulative_sum'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
optionsTemplate: gaugeTemplate,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
min: 1,
|
||||
aggFilter: [
|
||||
'!std_dev', '!geo_centroid', '!percentiles', '!percentile_ranks',
|
||||
'!derivative', '!serial_diff', '!moving_avg', '!cumulative_sum'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Group',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
}
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Group',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import gaugeTemplate from 'plugins/kbn_vislib_vis_types/editors/gauge.html';
|
||||
import { vislibColorMaps } from 'ui/vislib/components/color/colormaps';
|
||||
import image from './images/icon-goal.svg';
|
||||
|
||||
export default function GoalVisType(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return VisFactory.createVislibVisualization({
|
||||
return new VislibVisType({
|
||||
name: 'goal',
|
||||
title: 'Goal',
|
||||
image,
|
||||
description: 'A goal chart indicates how close you are to your final goal.',
|
||||
category: CATEGORY.DATA,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.DATA,
|
||||
params: {
|
||||
defaults: {
|
||||
addTooltip: true,
|
||||
addLegend: false,
|
||||
|
@ -55,37 +56,34 @@ export default function GoalVisType(Private) {
|
|||
}
|
||||
}
|
||||
},
|
||||
gaugeTypes: ['Arc', 'Circle', 'Metric'],
|
||||
gaugeColorMode: ['None', 'Labels', 'Background'],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
editor: gaugeTemplate
|
||||
},
|
||||
editorConfig: {
|
||||
collections: {
|
||||
gaugeTypes: ['Arc', 'Circle', 'Metric'],
|
||||
gaugeColorMode: ['None', 'Labels', 'Background'],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
implementsRenderComplete: true,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
min: 1,
|
||||
aggFilter: [
|
||||
'!std_dev', '!geo_centroid', '!percentiles', '!percentile_ranks',
|
||||
'!derivative', '!serial_diff', '!moving_avg', '!cumulative_sum'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
optionsTemplate: gaugeTemplate,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
min: 1,
|
||||
aggFilter: [
|
||||
'!std_dev', '!geo_centroid', '!percentiles', '!percentile_ranks',
|
||||
'!derivative', '!serial_diff', '!moving_avg', '!cumulative_sum'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Group',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
}
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Group',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import heatmapTemplate from 'plugins/kbn_vislib_vis_types/editors/heatmap.html';
|
||||
import { vislibColorMaps } from 'ui/vislib/components/color/colormaps';
|
||||
import image from './images/icon-heatmap.svg';
|
||||
|
||||
export default function HeatmapVisType(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return VisFactory.createVislibVisualization({
|
||||
return new VislibVisType({
|
||||
name: 'heatmap',
|
||||
title: 'Heat Map',
|
||||
image,
|
||||
description: 'Shade cells within a matrix',
|
||||
category: CATEGORY.BASIC,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.BASIC,
|
||||
params: {
|
||||
defaults: {
|
||||
type: 'heatmap',
|
||||
addTooltip: true,
|
||||
addLegend: true,
|
||||
enableHover: false,
|
||||
|
@ -44,64 +44,59 @@ export default function HeatmapVisType(Private) {
|
|||
}
|
||||
}]
|
||||
},
|
||||
legendPositions: [{
|
||||
value: 'left',
|
||||
text: 'left',
|
||||
}, {
|
||||
value: 'right',
|
||||
text: 'right',
|
||||
}, {
|
||||
value: 'top',
|
||||
text: 'top',
|
||||
}, {
|
||||
value: 'bottom',
|
||||
text: 'bottom',
|
||||
}],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
editor: heatmapTemplate
|
||||
},
|
||||
editorConfig: {
|
||||
collections: {
|
||||
legendPositions: [{
|
||||
value: 'left',
|
||||
text: 'left',
|
||||
}, {
|
||||
value: 'right',
|
||||
text: 'right',
|
||||
}, {
|
||||
value: 'top',
|
||||
text: 'top',
|
||||
}, {
|
||||
value: 'bottom',
|
||||
text: 'bottom',
|
||||
}],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Value',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'median', 'sum', 'min', 'max', 'cardinality', 'std_dev', 'top_hits'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
optionsTemplate: heatmapTemplate,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Value',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'median', 'sum', 'min', 'max', 'cardinality', 'std_dev', 'top_hits'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'X-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Y-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'X-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Y-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import pointSeriesTemplate from 'plugins/kbn_vislib_vis_types/editors/point_series.html';
|
||||
import image from './images/icon-vertical.svg';
|
||||
|
||||
export default function PointSeriesVisType(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return VisFactory.createVislibVisualization({
|
||||
return new VislibVisType({
|
||||
name: 'histogram',
|
||||
title: 'Vertical Bar',
|
||||
image,
|
||||
description: 'Assign a continuous variable to each axis',
|
||||
category: CATEGORY.BASIC,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.BASIC,
|
||||
params: {
|
||||
defaults: {
|
||||
type: 'histogram',
|
||||
grid: {
|
||||
categoryLines: false,
|
||||
style: {
|
||||
|
@ -29,7 +29,8 @@ export default function PointSeriesVisType(Private) {
|
|||
type: 'category',
|
||||
position: 'bottom',
|
||||
show: true,
|
||||
style: {},
|
||||
style: {
|
||||
},
|
||||
scale: {
|
||||
type: 'linear'
|
||||
},
|
||||
|
@ -47,7 +48,8 @@ export default function PointSeriesVisType(Private) {
|
|||
type: 'value',
|
||||
position: 'left',
|
||||
show: true,
|
||||
style: {},
|
||||
style: {
|
||||
},
|
||||
scale: {
|
||||
type: 'linear',
|
||||
mode: 'normal'
|
||||
|
@ -83,34 +85,31 @@ export default function PointSeriesVisType(Private) {
|
|||
times: [],
|
||||
addTimeMarker: false,
|
||||
},
|
||||
},
|
||||
editorConfig: {
|
||||
collections: {
|
||||
positions: ['top', 'left', 'right', 'bottom'],
|
||||
chartTypes: [{
|
||||
value: 'line',
|
||||
text: 'line'
|
||||
}, {
|
||||
value: 'area',
|
||||
text: 'area'
|
||||
}, {
|
||||
value: 'histogram',
|
||||
text: 'bar'
|
||||
}],
|
||||
axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'],
|
||||
scaleTypes: ['linear', 'log', 'square root'],
|
||||
chartModes: ['normal', 'stacked'],
|
||||
interpolationModes: [{
|
||||
value: 'linear',
|
||||
text: 'straight',
|
||||
}, {
|
||||
value: 'cardinal',
|
||||
text: 'smoothed',
|
||||
}, {
|
||||
value: 'step-after',
|
||||
text: 'stepped',
|
||||
}],
|
||||
},
|
||||
positions: ['top', 'left', 'right', 'bottom'],
|
||||
chartTypes: [{
|
||||
value: 'line',
|
||||
text: 'line'
|
||||
}, {
|
||||
value: 'area',
|
||||
text: 'area'
|
||||
}, {
|
||||
value: 'histogram',
|
||||
text: 'bar'
|
||||
}],
|
||||
axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'],
|
||||
scaleTypes: ['linear', 'log', 'square root'],
|
||||
chartModes: ['normal', 'stacked'],
|
||||
interpolationModes: [{
|
||||
value: 'linear',
|
||||
text: 'straight',
|
||||
}, {
|
||||
value: 'cardinal',
|
||||
text: 'smoothed',
|
||||
}, {
|
||||
value: 'step-after',
|
||||
text: 'stepped',
|
||||
}],
|
||||
editor: pointSeriesTemplate,
|
||||
optionTabs: [
|
||||
{
|
||||
name: 'advanced',
|
||||
|
@ -120,51 +119,50 @@ export default function PointSeriesVisType(Private) {
|
|||
},
|
||||
{ name: 'options', title: 'Panel Settings', editor: pointSeriesTemplate },
|
||||
],
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Y-Axis',
|
||||
min: 1,
|
||||
aggFilter: ['!geo_centroid'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'radius',
|
||||
title: 'Dot Size',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality']
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'X-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Series',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
},
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Y-Axis',
|
||||
min: 1,
|
||||
aggFilter: ['!geo_centroid'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'radius',
|
||||
title: 'Dot Size',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality']
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'X-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Series',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import pointSeriesTemplate from 'plugins/kbn_vislib_vis_types/editors/point_series.html';
|
||||
import image from './images/icon-horizontal.svg';
|
||||
|
||||
export default function PointSeriesVisType(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return VisFactory.createVislibVisualization({
|
||||
return new VislibVisType({
|
||||
name: 'horizontal_bar',
|
||||
title: 'Horizontal Bar',
|
||||
image,
|
||||
description: 'Assign a continuous variable to each axis',
|
||||
category: CATEGORY.BASIC,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.BASIC,
|
||||
params: {
|
||||
defaults: {
|
||||
type: 'histogram',
|
||||
grid: {
|
||||
categoryLines: false,
|
||||
style: {
|
||||
|
@ -85,34 +85,31 @@ export default function PointSeriesVisType(Private) {
|
|||
times: [],
|
||||
addTimeMarker: false,
|
||||
},
|
||||
},
|
||||
editorConfig: {
|
||||
collections: {
|
||||
positions: ['top', 'left', 'right', 'bottom'],
|
||||
chartTypes: [{
|
||||
value: 'line',
|
||||
text: 'line'
|
||||
}, {
|
||||
value: 'area',
|
||||
text: 'area'
|
||||
}, {
|
||||
value: 'histogram',
|
||||
text: 'bar'
|
||||
}],
|
||||
axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'],
|
||||
scaleTypes: ['linear', 'log', 'square root'],
|
||||
chartModes: ['normal', 'stacked'],
|
||||
interpolationModes: [{
|
||||
value: 'linear',
|
||||
text: 'straight',
|
||||
}, {
|
||||
value: 'cardinal',
|
||||
text: 'smoothed',
|
||||
}, {
|
||||
value: 'step-after',
|
||||
text: 'stepped',
|
||||
}],
|
||||
},
|
||||
positions: ['top', 'left', 'right', 'bottom'],
|
||||
chartTypes: [{
|
||||
value: 'line',
|
||||
text: 'line'
|
||||
}, {
|
||||
value: 'area',
|
||||
text: 'area'
|
||||
}, {
|
||||
value: 'histogram',
|
||||
text: 'bar'
|
||||
}],
|
||||
axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'],
|
||||
scaleTypes: ['linear', 'log', 'square root'],
|
||||
chartModes: ['normal', 'stacked'],
|
||||
interpolationModes: [{
|
||||
value: 'linear',
|
||||
text: 'straight',
|
||||
}, {
|
||||
value: 'cardinal',
|
||||
text: 'smoothed',
|
||||
}, {
|
||||
value: 'step-after',
|
||||
text: 'stepped',
|
||||
}],
|
||||
editor: pointSeriesTemplate,
|
||||
optionTabs: [
|
||||
{
|
||||
name: 'advanced',
|
||||
|
@ -122,50 +119,50 @@ export default function PointSeriesVisType(Private) {
|
|||
},
|
||||
{ name: 'options', title: 'Panel Settings', editor: pointSeriesTemplate },
|
||||
],
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Y-Axis',
|
||||
min: 1,
|
||||
aggFilter: ['!geo_centroid'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'radius',
|
||||
title: 'Dot Size',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality']
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'X-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Series',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
}
|
||||
},
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Y-Axis',
|
||||
min: 1,
|
||||
aggFilter: ['!geo_centroid'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'radius',
|
||||
title: 'Dot Size',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality']
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'X-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Series',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import histogramVisTypeProvider from 'plugins/kbn_vislib_vis_types/histogram';
|
|||
import lineVisTypeProvider from 'plugins/kbn_vislib_vis_types/line';
|
||||
import pieVisTypeProvider from 'plugins/kbn_vislib_vis_types/pie';
|
||||
import areaVisTypeProvider from 'plugins/kbn_vislib_vis_types/area';
|
||||
import tileMapVisTypeProvider from 'plugins/kbn_vislib_vis_types/tile_map';
|
||||
import heatmapVisTypeProvider from 'plugins/kbn_vislib_vis_types/heatmap';
|
||||
import horizontalBarVisTypeProvider from 'plugins/kbn_vislib_vis_types/horizontal_bar';
|
||||
import gaugeVisTypeProvider from 'plugins/kbn_vislib_vis_types/gauge';
|
||||
|
@ -14,6 +15,7 @@ VisTypesRegistryProvider.register(histogramVisTypeProvider);
|
|||
VisTypesRegistryProvider.register(lineVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(pieVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(areaVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(tileMapVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(heatmapVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(horizontalBarVisTypeProvider);
|
||||
VisTypesRegistryProvider.register(gaugeVisTypeProvider);
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import pointSeriesTemplate from 'plugins/kbn_vislib_vis_types/editors/point_series.html';
|
||||
import image from './images/icon-line.svg';
|
||||
|
||||
export default function PointSeriesVisType(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return VisFactory.createVislibVisualization({
|
||||
return new VislibVisType({
|
||||
name: 'line',
|
||||
title: 'Line',
|
||||
image,
|
||||
description: 'Emphasize trends',
|
||||
category: CATEGORY.BASIC,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.BASIC,
|
||||
params: {
|
||||
defaults: {
|
||||
type: 'line',
|
||||
grid: {
|
||||
categoryLines: false,
|
||||
style: {
|
||||
|
@ -29,7 +29,8 @@ export default function PointSeriesVisType(Private) {
|
|||
type: 'category',
|
||||
position: 'bottom',
|
||||
show: true,
|
||||
style: {},
|
||||
style: {
|
||||
},
|
||||
scale: {
|
||||
type: 'linear'
|
||||
},
|
||||
|
@ -47,7 +48,8 @@ export default function PointSeriesVisType(Private) {
|
|||
type: 'value',
|
||||
position: 'left',
|
||||
show: true,
|
||||
style: {},
|
||||
style: {
|
||||
},
|
||||
scale: {
|
||||
type: 'linear',
|
||||
mode: 'normal'
|
||||
|
@ -83,34 +85,31 @@ export default function PointSeriesVisType(Private) {
|
|||
times: [],
|
||||
addTimeMarker: false,
|
||||
},
|
||||
},
|
||||
editorConfig: {
|
||||
collections: {
|
||||
positions: ['top', 'left', 'right', 'bottom'],
|
||||
chartTypes: [{
|
||||
value: 'line',
|
||||
text: 'line'
|
||||
}, {
|
||||
value: 'area',
|
||||
text: 'area'
|
||||
}, {
|
||||
value: 'histogram',
|
||||
text: 'bar'
|
||||
}],
|
||||
axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'],
|
||||
scaleTypes: ['linear', 'log', 'square root'],
|
||||
chartModes: ['normal', 'stacked'],
|
||||
interpolationModes: [{
|
||||
value: 'linear',
|
||||
text: 'straight',
|
||||
}, {
|
||||
value: 'cardinal',
|
||||
text: 'smoothed',
|
||||
}, {
|
||||
value: 'step-after',
|
||||
text: 'stepped',
|
||||
}],
|
||||
},
|
||||
positions: ['top', 'left', 'right', 'bottom'],
|
||||
chartTypes: [{
|
||||
value: 'line',
|
||||
text: 'line'
|
||||
}, {
|
||||
value: 'area',
|
||||
text: 'area'
|
||||
}, {
|
||||
value: 'histogram',
|
||||
text: 'bar'
|
||||
}],
|
||||
axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'],
|
||||
scaleTypes: ['linear', 'log', 'square root'],
|
||||
chartModes: ['normal', 'stacked'],
|
||||
interpolationModes: [{
|
||||
value: 'linear',
|
||||
text: 'straight',
|
||||
}, {
|
||||
value: 'cardinal',
|
||||
text: 'smoothed',
|
||||
}, {
|
||||
value: 'step-after',
|
||||
text: 'stepped',
|
||||
}],
|
||||
editor: pointSeriesTemplate,
|
||||
optionTabs: [
|
||||
{
|
||||
name: 'advanced',
|
||||
|
@ -120,50 +119,50 @@ export default function PointSeriesVisType(Private) {
|
|||
},
|
||||
{ name: 'options', title: 'Panel Settings', editor: pointSeriesTemplate },
|
||||
],
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Y-Axis',
|
||||
min: 1,
|
||||
aggFilter: ['!geo_centroid'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'radius',
|
||||
title: 'Dot Size',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality', 'top_hits']
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'X-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Series',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
}
|
||||
},
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Y-Axis',
|
||||
min: 1,
|
||||
aggFilter: ['!geo_centroid'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'radius',
|
||||
title: 'Dot Size',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality', 'top_hits']
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'X-Axis',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Series',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Chart',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import gaugeTemplate from 'plugins/kbn_vislib_vis_types/editors/gauge.html';
|
||||
import { vislibColorMaps } from 'ui/vislib/components/color/colormaps';
|
||||
import image from './images/icon-number.svg';
|
||||
|
||||
export default function MetricVisType(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return VisFactory.createVislibVisualization({
|
||||
return new VislibVisType({
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
image,
|
||||
description: 'Display a calculation as a single number',
|
||||
category: CATEGORY.DATA,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.DATA,
|
||||
params: {
|
||||
defaults: {
|
||||
addTooltip: true,
|
||||
addLegend: false,
|
||||
|
@ -55,37 +56,34 @@ export default function MetricVisType(Private) {
|
|||
}
|
||||
}
|
||||
},
|
||||
gaugeTypes: ['Arc', 'Circle', 'Metric'],
|
||||
gaugeColorMode: ['None', 'Labels', 'Background'],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
editor: gaugeTemplate
|
||||
},
|
||||
editorConfig: {
|
||||
collections: {
|
||||
gaugeTypes: ['Arc', 'Circle', 'Metric'],
|
||||
gaugeColorMode: ['None', 'Labels', 'Background'],
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
colorSchemas: Object.keys(vislibColorMaps),
|
||||
implementsRenderComplete: true,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
min: 1,
|
||||
aggFilter: [
|
||||
'!std_dev', '!geo_centroid', '!percentiles', '!percentile_ranks',
|
||||
'!derivative', '!serial_diff', '!moving_avg', '!cumulative_sum'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
optionsTemplate: gaugeTemplate,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
min: 1,
|
||||
aggFilter: [
|
||||
'!std_dev', '!geo_centroid', '!percentiles', '!percentile_ranks',
|
||||
'!derivative', '!serial_diff', '!moving_avg', '!cumulative_sum'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Group',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
}
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'group',
|
||||
title: 'Split Group',
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,79 +1,76 @@
|
|||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { VislibVisTypeVislibVisTypeProvider } from 'ui/vislib_vis_type/vislib_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import pieTemplate from 'plugins/kbn_vislib_vis_types/editors/pie.html';
|
||||
import image from './images/icon-pie.svg';
|
||||
|
||||
export default function HistogramVisType(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const VislibVisType = Private(VislibVisTypeVislibVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return VisFactory.createVislibVisualization({
|
||||
return new VislibVisType({
|
||||
name: 'pie',
|
||||
title: 'Pie',
|
||||
image,
|
||||
description: 'Compare parts of a whole',
|
||||
category: CATEGORY.BASIC,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.BASIC,
|
||||
params: {
|
||||
defaults: {
|
||||
type: 'pie',
|
||||
addTooltip: true,
|
||||
addLegend: true,
|
||||
legendPosition: 'right',
|
||||
isDonut: false
|
||||
},
|
||||
legendPositions: [{
|
||||
value: 'left',
|
||||
text: 'left',
|
||||
}, {
|
||||
value: 'right',
|
||||
text: 'right',
|
||||
}, {
|
||||
value: 'top',
|
||||
text: 'top',
|
||||
}, {
|
||||
value: 'bottom',
|
||||
text: 'bottom',
|
||||
}],
|
||||
editor: pieTemplate
|
||||
},
|
||||
editorConfig: {
|
||||
collections: {
|
||||
legendPositions: [{
|
||||
value: 'left',
|
||||
text: 'left',
|
||||
}, {
|
||||
value: 'right',
|
||||
text: 'right',
|
||||
}, {
|
||||
value: 'top',
|
||||
text: 'top',
|
||||
}, {
|
||||
value: 'bottom',
|
||||
text: 'bottom',
|
||||
}],
|
||||
},
|
||||
optionsTemplate: pieTemplate,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Slice Size',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['sum', 'count', 'cardinality', 'top_hits'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
icon: 'fa fa-scissors',
|
||||
title: 'Split Slices',
|
||||
min: 0,
|
||||
max: Infinity,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
icon: 'fa fa-th',
|
||||
title: 'Split Chart',
|
||||
mustBeFirst: true,
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
},
|
||||
responseConverter: false,
|
||||
hierarchicalData: true,
|
||||
implementsRenderComplete: true
|
||||
implementsRenderComplete: true,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Slice Size',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['sum', 'count', 'cardinality', 'top_hits'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
icon: 'fa fa-scissors',
|
||||
title: 'Split Slices',
|
||||
min: 0,
|
||||
max: Infinity,
|
||||
aggFilter: '!geohash_grid'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
icon: 'fa fa-th',
|
||||
title: 'Split Chart',
|
||||
mustBeFirst: true,
|
||||
min: 0,
|
||||
max: 1,
|
||||
aggFilter: '!geohash_grid'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
|
80
src/core_plugins/kbn_vislib_vis_types/public/tile_map.js
Normal file
80
src/core_plugins/kbn_vislib_vis_types/public/tile_map.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
import { supports } from 'ui/utils/supports';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { MapsVisTypeProvider } from 'ui/vis_maps/maps_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import { AggResponseGeoJsonProvider } from 'ui/agg_response/geo_json/geo_json';
|
||||
import tileMapTemplate from 'plugins/kbn_vislib_vis_types/editors/tile_map.html';
|
||||
import image from './images/icon-tilemap.svg';
|
||||
|
||||
export default function TileMapVisType(Private, getAppState, courier, config) {
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const MapsVisType = Private(MapsVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
const geoJsonConverter = Private(AggResponseGeoJsonProvider);
|
||||
|
||||
return new MapsVisType({
|
||||
name: 'tile_map',
|
||||
title: 'Coordinate Map',
|
||||
image,
|
||||
description: 'Plot latitude and longitude coordinates on a map',
|
||||
category: VisType.CATEGORY.MAP,
|
||||
params: {
|
||||
defaults: {
|
||||
mapType: 'Scaled Circle Markers',
|
||||
isDesaturated: true,
|
||||
addTooltip: true,
|
||||
heatMaxZoom: 0,
|
||||
heatMinOpacity: 0.1,
|
||||
heatRadius: 25,
|
||||
heatBlur: 15,
|
||||
legendPosition: 'bottomright',
|
||||
mapZoom: 2,
|
||||
mapCenter: [0, 0],
|
||||
wms: config.get('visualization:tileMap:WMSdefaults')
|
||||
},
|
||||
legendPositions: [{
|
||||
value: 'bottomleft',
|
||||
text: 'bottom left',
|
||||
}, {
|
||||
value: 'bottomright',
|
||||
text: 'bottom right',
|
||||
}, {
|
||||
value: 'topleft',
|
||||
text: 'top left',
|
||||
}, {
|
||||
value: 'topright',
|
||||
text: 'top right',
|
||||
}],
|
||||
mapTypes: ['Scaled Circle Markers',
|
||||
'Shaded Circle Markers',
|
||||
'Shaded Geohash Grid',
|
||||
'Heatmap'
|
||||
],
|
||||
canDesaturate: !!supports.cssFilters,
|
||||
editor: tileMapTemplate
|
||||
},
|
||||
responseConverter: geoJsonConverter,
|
||||
implementsRenderComplete: true,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Value',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality', 'top_hits'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'Geo Coordinates',
|
||||
aggFilter: 'geohash_grid',
|
||||
min: 1,
|
||||
max: 1
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
|
@ -117,7 +117,6 @@
|
|||
get-vis-click-handler="getFilterBarClickHandler"
|
||||
get-vis-brush-handler="getBrushEvent"
|
||||
save-state="saveState"
|
||||
app-state="appState"
|
||||
toggle-expand="toggleExpandPanel"
|
||||
create-child-ui-state="createChildUiState"
|
||||
toggle-expand="toggleExpandPanel"
|
||||
|
@ -134,7 +133,6 @@
|
|||
get-vis-click-handler="getFilterBarClickHandler"
|
||||
get-vis-brush-handler="getBrushEvent"
|
||||
save-state="saveState"
|
||||
app-state="appState"
|
||||
register-panel-index-pattern="registerPanelIndexPattern"
|
||||
create-child-ui-state="createChildUiState"
|
||||
toggle-expand="toggleExpandPanel(expandedPanel.panelIndex)"
|
||||
|
|
|
@ -147,7 +147,6 @@ app.directive('dashboardApp', function ($injector) {
|
|||
$scope.timefilter = timefilter;
|
||||
$scope.expandedPanel = null;
|
||||
$scope.dashboardViewMode = dashboardState.getViewMode();
|
||||
$scope.appState = dashboardState.getAppState();
|
||||
|
||||
$scope.landingPageUrl = () => `#${DashboardConstants.LANDING_PAGE_PATH}`;
|
||||
$scope.getBrushEvent = () => brushEvent(dashboardState.getAppState());
|
||||
|
|
|
@ -53,7 +53,6 @@ app.directive('dashboardGrid', function ($compile, Notifier) {
|
|||
* @type {function}
|
||||
*/
|
||||
saveState: '=',
|
||||
appState: '=',
|
||||
/**
|
||||
* Expand or collapse a panel, so it either takes up the whole screen or goes back to its
|
||||
* natural size.
|
||||
|
@ -220,7 +219,6 @@ app.directive('dashboardGrid', function ($compile, Notifier) {
|
|||
get-vis-click-handler="getVisClickHandler"
|
||||
get-vis-brush-handler="getVisBrushHandler"
|
||||
save-state="saveState"
|
||||
app-state="appState"
|
||||
register-panel-index-pattern="registerPanelIndexPattern"
|
||||
toggle-expand="toggleExpand(${panel.panelIndex})"
|
||||
create-child-ui-state="createChildUiState">
|
||||
|
|
|
@ -79,9 +79,9 @@
|
|||
<visualize
|
||||
ng-if="!error"
|
||||
ng-switch-when="visualization"
|
||||
vis="savedObj.vis"
|
||||
search-source="savedObj.searchSource"
|
||||
show-spy-panel="!isFullScreenMode"
|
||||
saved-obj="savedObj"
|
||||
app-state="appState"
|
||||
ui-state="uiState"
|
||||
data-shared-item
|
||||
data-title="{{savedObj.title}}"
|
||||
|
|
|
@ -85,8 +85,7 @@ uiModules
|
|||
* Call when changes should be propagated to the url and thus saved in state.
|
||||
* @type {function}
|
||||
*/
|
||||
saveState: '=',
|
||||
appState: '=',
|
||||
saveState: '='
|
||||
},
|
||||
link: function ($scope, element) {
|
||||
if (!$scope.panel.id || !$scope.panel.type) return;
|
||||
|
|
|
@ -16,7 +16,6 @@ import 'ui/state_management/app_state';
|
|||
import 'ui/timefilter';
|
||||
import 'ui/share';
|
||||
import { VisProvider } from 'ui/vis';
|
||||
import { BasicResponseHandlerProvider } from 'ui/vis/response_handlers/basic';
|
||||
import { DocTitleProvider } from 'ui/doc_title';
|
||||
import { UtilsBrushEventProvider } from 'ui/utils/brush_event';
|
||||
import PluginsKibanaDiscoverHitSortFnProvider from 'plugins/kibana/discover/_hit_sort_fn';
|
||||
|
@ -99,7 +98,7 @@ function discoverController($scope, config, courier, $route, $window, Notifier,
|
|||
const HitSortFn = Private(PluginsKibanaDiscoverHitSortFnProvider);
|
||||
const queryFilter = Private(FilterBarQueryFilterProvider);
|
||||
const filterManager = Private(FilterManagerProvider);
|
||||
const responseHandler = Private(BasicResponseHandlerProvider).handler;
|
||||
|
||||
const notify = new Notifier({
|
||||
location: 'Discover'
|
||||
});
|
||||
|
@ -488,9 +487,6 @@ function discoverController($scope, config, courier, $route, $window, Notifier,
|
|||
|
||||
segmented.on('mergedSegment', function (merged) {
|
||||
$scope.mergedEsResp = merged;
|
||||
responseHandler($scope.vis, merged).then(resp => {
|
||||
$scope.visData = resp;
|
||||
});
|
||||
$scope.hits = merged.hits.total;
|
||||
|
||||
const indexPattern = $scope.searchSource.get('index');
|
||||
|
|
|
@ -130,14 +130,13 @@
|
|||
|
||||
</header>
|
||||
|
||||
<visualization
|
||||
<visualize
|
||||
ng-if="vis && rows.length != 0"
|
||||
vis="vis"
|
||||
ui-state="uiState"
|
||||
vis-data="visData"
|
||||
style="height: 200px"
|
||||
>
|
||||
</visualization>
|
||||
es-resp="mergedEsResp"
|
||||
search-source="searchSource">
|
||||
</visualize>
|
||||
</div>
|
||||
|
||||
<div class="discover-table" fixed-scroll>
|
||||
|
|
|
@ -3,7 +3,7 @@ import angular from 'angular';
|
|||
import _ from 'lodash';
|
||||
import expect from 'expect.js';
|
||||
import ngMock from 'ng_mock';
|
||||
import '../agg';
|
||||
import 'plugins/kibana/visualize/editor/agg';
|
||||
|
||||
|
||||
describe('Vis-Editor-Agg plugin directive', function () {
|
|
@ -3,10 +3,10 @@ import angular from 'angular';
|
|||
import _ from 'lodash';
|
||||
import expect from 'expect.js';
|
||||
import ngMock from 'ng_mock';
|
||||
import '../agg_params';
|
||||
import 'plugins/kibana/visualize/editor/agg_params';
|
||||
import { VisProvider } from 'ui/vis';
|
||||
import { VisAggConfigProvider } from 'ui/vis/agg_config';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
|
||||
|
|
@ -90,5 +90,5 @@
|
|||
<vis-editor-agg-add
|
||||
ng-if="$index + 1 === stats.count"
|
||||
ng-hide="dragging"
|
||||
class="vis-editor-agg-add vis-editor-agg-add-subagg">
|
||||
class="vis-editor-agg-add">
|
||||
</vis-editor-agg-add>
|
|
@ -1,8 +1,8 @@
|
|||
import './agg_params';
|
||||
import './agg_add';
|
||||
import 'plugins/kibana/visualize/editor/agg_params';
|
||||
import 'plugins/kibana/visualize/editor/agg_add';
|
||||
import _ from 'lodash';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import aggTemplate from './agg.html';
|
||||
import aggTemplate from 'plugins/kibana/visualize/editor/agg.html';
|
||||
uiModules
|
||||
.get('app/visualize')
|
||||
.directive('visEditorAgg', function ($compile, $parse, $filter, Private, Notifier) {
|
|
@ -1,6 +1,6 @@
|
|||
import { VisAggConfigProvider } from 'ui/vis/agg_config';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import aggAddTemplate from './agg_add.html';
|
||||
import aggAddTemplate from 'plugins/kibana/visualize/editor/agg_add.html';
|
||||
|
||||
uiModules
|
||||
.get('kibana')
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<div ng-class="groupName" draggable-container="group" class="vis-editor-agg-group">
|
||||
<!-- wrapper needed for nesting-indicator -->
|
||||
<div ng-repeat="agg in group track by agg.id" draggable-item="agg" class="vis-editor-agg-wrapper">
|
||||
<div ng-repeat="agg in group" draggable-item="agg" class="vis-editor-agg-wrapper">
|
||||
<!-- agg.html - controls for aggregation -->
|
||||
<ng-form vis-editor-agg name="aggForm" class="vis-editor-agg"></ng-form>
|
||||
</div>
|
|
@ -1,10 +1,9 @@
|
|||
import _ from 'lodash';
|
||||
import './agg';
|
||||
import './agg_add';
|
||||
import './nesting_indicator';
|
||||
|
||||
import 'plugins/kibana/visualize/editor/agg';
|
||||
import 'plugins/kibana/visualize/editor/agg_add';
|
||||
import 'plugins/kibana/visualize/editor/nesting_indicator';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import aggGroupTemplate from './agg_group.html';
|
||||
import aggGroupTemplate from 'plugins/kibana/visualize/editor/agg_group.html';
|
||||
|
||||
uiModules
|
||||
.get('app/visualize')
|
|
@ -1,11 +1,11 @@
|
|||
import $ from 'jquery';
|
||||
import aggSelectHtml from './agg_select.html';
|
||||
import advancedToggleHtml from './advanced_toggle.html';
|
||||
import aggSelectHtml from 'plugins/kibana/visualize/editor/agg_select.html';
|
||||
import advancedToggleHtml from 'plugins/kibana/visualize/editor/advanced_toggle.html';
|
||||
import 'ui/filters/match_any';
|
||||
import './agg_param';
|
||||
import 'plugins/kibana/visualize/editor/agg_param';
|
||||
import { AggTypesIndexProvider } from 'ui/agg_types/index';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import aggParamsTemplate from './agg_params.html';
|
||||
import aggParamsTemplate from 'plugins/kibana/visualize/editor/agg_params.html';
|
||||
|
||||
uiModules
|
||||
.get('app/visualize')
|
|
@ -85,16 +85,53 @@
|
|||
index-patterns="[indexPattern]"
|
||||
></filter-bar>
|
||||
|
||||
<visualize
|
||||
saved-obj="savedVis"
|
||||
ui-state="uiState"
|
||||
app-state="state"
|
||||
editor-mode="true"
|
||||
data-shared-item
|
||||
render-counter
|
||||
data-title="{{savedVis.lastSavedTitle}}"
|
||||
data-description="{{savedVis.description}}"
|
||||
show-spy-panel="chrome.getVisible()">
|
||||
</visualize>
|
||||
<!-- Custom, full-screen editing UI. -->
|
||||
<div
|
||||
ng-if="vis.type.fullEditor"
|
||||
class="vis-editor-content"
|
||||
>
|
||||
<vis-editor-vis-options
|
||||
vis="vis"
|
||||
saved-vis="savedVis"
|
||||
editor="vis.type.params.editor"
|
||||
ui-state="uiState"
|
||||
stage-editable-vis="stageEditableVis"
|
||||
class="vis-editor-full-options"
|
||||
></vis-editor-vis-options>
|
||||
</div>
|
||||
|
||||
<!-- Traditional sidebar-and-visualization editor. -->
|
||||
<div
|
||||
ng-if="!vis.type.fullEditor"
|
||||
class="vis-editor-content"
|
||||
>
|
||||
<!-- Sidebar -->
|
||||
<div
|
||||
class="collapsible-sidebar"
|
||||
ng-if="chrome.getVisible()"
|
||||
>
|
||||
<vis-editor-sidebar
|
||||
vis="editableVis"
|
||||
class="vis-editor-sidebar"
|
||||
></vis-editor-sidebar>
|
||||
</div>
|
||||
|
||||
<!-- Visualization -->
|
||||
<div
|
||||
class="vis-editor-canvas"
|
||||
ng-class="{ embedded: !chrome.getVisible() }"
|
||||
>
|
||||
<visualize
|
||||
vis="vis"
|
||||
data-shared-item
|
||||
data-title="{{savedVis.lastSavedTitle}}"
|
||||
data-description="{{savedVis.description}}"
|
||||
render-counter
|
||||
ui-state="uiState"
|
||||
show-spy-panel="chrome.getVisible()"
|
||||
editable-vis="editableVis"
|
||||
search-source="savedVis.searchSource">
|
||||
</visualize>
|
||||
</div>
|
||||
</div>
|
||||
</visualize-app>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import _ from 'lodash';
|
||||
import 'plugins/kibana/visualize/saved_visualizations/saved_visualizations';
|
||||
import 'ui/vis/editors/default/sidebar';
|
||||
import 'plugins/kibana/visualize/editor/sidebar';
|
||||
import 'plugins/kibana/visualize/editor/agg_filter';
|
||||
import 'ui/visualize';
|
||||
import 'ui/collapsible_sidebar';
|
||||
|
@ -10,7 +10,9 @@ import angular from 'angular';
|
|||
import { Notifier } from 'ui/notify/notifier';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
import { DocTitleProvider } from 'ui/doc_title';
|
||||
import { UtilsBrushEventProvider } from 'ui/utils/brush_event';
|
||||
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
|
||||
import { FilterBarClickHandlerProvider } from 'ui/filter_bar/filter_bar_click_handler';
|
||||
import { stateMonitorFactory } from 'ui/state_management/state_monitor_factory';
|
||||
import uiRoutes from 'ui/routes';
|
||||
import { uiModules } from 'ui/modules';
|
||||
|
@ -28,9 +30,7 @@ uiRoutes
|
|||
savedVis: function (savedVisualizations, courier, $route, Private) {
|
||||
const visTypes = Private(VisTypesRegistryProvider);
|
||||
const visType = _.find(visTypes, { name: $route.current.params.type });
|
||||
const shouldHaveIndex = visType.requiresSearch && visType.options.showIndexSelection;
|
||||
const hasIndex = $route.current.params.indexPattern || $route.current.params.savedSearchId;
|
||||
if (shouldHaveIndex && !hasIndex) {
|
||||
if (visType.requiresSearch && !$route.current.params.indexPattern && !$route.current.params.savedSearchId) {
|
||||
throw new Error('You must provide either an indexPattern or a savedSearchId');
|
||||
}
|
||||
|
||||
|
@ -69,34 +69,52 @@ uiModules
|
|||
};
|
||||
});
|
||||
|
||||
function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courier, Private, Promise, kbnBaseUrl) {
|
||||
function VisEditor($rootScope, $scope, $route, timefilter, AppState, $window, kbnUrl, courier, Private, Promise, kbnBaseUrl) {
|
||||
const docTitle = Private(DocTitleProvider);
|
||||
const brushEvent = Private(UtilsBrushEventProvider);
|
||||
const queryFilter = Private(FilterBarQueryFilterProvider);
|
||||
const filterBarClickHandler = Private(FilterBarClickHandlerProvider);
|
||||
|
||||
const notify = new Notifier({
|
||||
location: 'Visualization Editor'
|
||||
});
|
||||
|
||||
let stateMonitor;
|
||||
|
||||
// Retrieve the resolved SavedVis instance.
|
||||
const savedVis = $route.current.locals.savedVis;
|
||||
// vis is instance of src/ui/public/vis/vis.js.
|
||||
// SearchSource is a promise-based stream of search results that can inherit from other search sources.
|
||||
const { vis, searchSource } = savedVis;
|
||||
$scope.vis = vis;
|
||||
|
||||
const $appStatus = this.appStatus = {
|
||||
dirty: !savedVis.id
|
||||
};
|
||||
|
||||
// Instance of src/ui/public/vis/vis.js.
|
||||
const vis = savedVis.vis;
|
||||
|
||||
// Clone the _vis instance.
|
||||
const editableVis = vis.createEditableVis();
|
||||
|
||||
// We intend to keep editableVis and vis in sync with one another, so calling `requesting` on
|
||||
// vis should call it on both.
|
||||
vis.requesting = function () {
|
||||
const requesting = editableVis.requesting;
|
||||
// Invoking requesting() calls onRequest on each agg's type param. When a vis is marked as being
|
||||
// requested, the bounds of that vis are updated and new data is fetched using the new bounds.
|
||||
requesting.call(vis);
|
||||
|
||||
// We need to keep editableVis in sync with vis.
|
||||
requesting.call(editableVis);
|
||||
};
|
||||
|
||||
// SearchSource is a promise-based stream of search results that can inherit from other search
|
||||
// sources.
|
||||
const searchSource = savedVis.searchSource;
|
||||
|
||||
$scope.topNavMenu = [{
|
||||
key: 'save',
|
||||
description: 'Save Visualization',
|
||||
template: require('plugins/kibana/visualize/editor/panels/save.html'),
|
||||
testId: 'visualizeSaveButton',
|
||||
disableButton() {
|
||||
return Boolean(vis.dirty);
|
||||
},
|
||||
tooltip() {
|
||||
if (vis.dirty) {
|
||||
return 'Apply or Discard your changes before saving';
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: 'share',
|
||||
description: 'Share Visualization',
|
||||
|
@ -109,12 +127,6 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
|
|||
testId: 'visualizeRefreshButton',
|
||||
}];
|
||||
|
||||
let stateMonitor;
|
||||
|
||||
const $appStatus = this.appStatus = {
|
||||
dirty: !savedVis.id
|
||||
};
|
||||
|
||||
if (savedVis.id) {
|
||||
docTitle.change(savedVis.title);
|
||||
}
|
||||
|
@ -125,13 +137,13 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
|
|||
const stateDefaults = {
|
||||
uiState: savedVis.uiStateJSON ? JSON.parse(savedVis.uiStateJSON) : {},
|
||||
linked: !!savedVis.savedSearchId,
|
||||
query: searchSource.getOwn('query') || { query_string: { analyze_wildcard: true, query: '*' } },
|
||||
query: searchSource.getOwn('query') || { query_string: { query: '*' } },
|
||||
filters: searchSource.getOwn('filter') || [],
|
||||
vis: savedVisState
|
||||
};
|
||||
|
||||
// Instance of app_state.js.
|
||||
const $state = (function initState() {
|
||||
const $state = $scope.$state = (function initState() {
|
||||
// This is used to sync visualization state with the url when `appState.save()` is called.
|
||||
const appState = new AppState(stateDefaults);
|
||||
|
||||
|
@ -140,7 +152,8 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
|
|||
// appState then they won't be equal.
|
||||
if (!angular.equals(appState.vis, savedVisState)) {
|
||||
Promise.try(function () {
|
||||
vis.setState(appState.vis);
|
||||
editableVis.setState(appState.vis);
|
||||
vis.setState(editableVis.getEnabledState());
|
||||
})
|
||||
.catch(courier.redirectWhenMissing({
|
||||
'index-pattern-field': '/visualize'
|
||||
|
@ -153,8 +166,10 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
|
|||
function init() {
|
||||
// export some objects
|
||||
$scope.savedVis = savedVis;
|
||||
$scope.indexPattern = vis.indexPattern;
|
||||
$scope.searchSource = searchSource;
|
||||
$scope.vis = vis;
|
||||
$scope.indexPattern = vis.indexPattern;
|
||||
$scope.editableVis = editableVis;
|
||||
$scope.state = $state;
|
||||
$scope.queryDocLinks = documentationLinks.query;
|
||||
$scope.dateDocLinks = documentationLinks.date;
|
||||
|
@ -181,6 +196,30 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
|
|||
stateMonitor.ignoreProps([ 'vis.listeners' ]).onChange((status) => {
|
||||
$appStatus.dirty = status.dirty || !savedVis.id;
|
||||
});
|
||||
$scope.$on('$destroy', () => stateMonitor.destroy());
|
||||
|
||||
editableVis.listeners.click = vis.listeners.click = filterBarClickHandler($state);
|
||||
editableVis.listeners.brush = vis.listeners.brush = brushEvent($state);
|
||||
|
||||
// track state of editable vis vs. "actual" vis
|
||||
$scope.stageEditableVis = transferVisState(editableVis, vis, true);
|
||||
$scope.resetEditableVis = transferVisState(vis, editableVis);
|
||||
$scope.$watch(function () {
|
||||
return editableVis.getEnabledState();
|
||||
}, function (newState) {
|
||||
editableVis.dirty = !angular.equals(newState, vis.getEnabledState());
|
||||
|
||||
$scope.responseValueAggs = null;
|
||||
try {
|
||||
$scope.responseValueAggs = editableVis.aggs.getResponseAggs().filter(function (agg) {
|
||||
return _.get(agg, 'schema.group') === 'metrics';
|
||||
});
|
||||
}
|
||||
// this can fail when the agg.type is changed but the
|
||||
// params have not been set yet. watcher will trigger again
|
||||
// when the params update
|
||||
catch (e) {} // eslint-disable-line no-empty
|
||||
}, true);
|
||||
|
||||
$state.replace();
|
||||
|
||||
|
@ -190,20 +229,56 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
|
|||
|
||||
$scope.$watchMulti([
|
||||
'searchSource.get("index").timeFieldName',
|
||||
'vis.type.options.showTimePicker',
|
||||
'vis.type.requiresTimePicker',
|
||||
], function ([timeField, requiresTimePicker]) {
|
||||
timefilter.enabled = Boolean(timeField || requiresTimePicker);
|
||||
});
|
||||
|
||||
// update the searchSource when filters update
|
||||
$scope.$listen(queryFilter, 'update', function () {
|
||||
searchSource.set('filter', queryFilter.getFilters());
|
||||
$state.save();
|
||||
});
|
||||
|
||||
// update the searchSource when query updates
|
||||
$scope.fetch = function () {
|
||||
$state.save();
|
||||
};
|
||||
// fetch data when filters fire fetch event
|
||||
$scope.$listen(queryFilter, 'fetch', $scope.fetch);
|
||||
|
||||
|
||||
$scope.$listen($state, 'fetch_with_changes', function (keys) {
|
||||
if (_.contains(keys, 'linked') && $state.linked === true) {
|
||||
// abort and reload route
|
||||
$route.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_.contains(keys, 'vis')) {
|
||||
$state.vis.listeners = _.defaults($state.vis.listeners || {}, vis.listeners);
|
||||
|
||||
// only update when we need to, otherwise colors change and we
|
||||
// risk loosing an in-progress result
|
||||
vis.setState($state.vis);
|
||||
editableVis.setState($state.vis);
|
||||
}
|
||||
|
||||
// we use state to track query, must write before we fetch
|
||||
if ($state.query && !$state.linked) {
|
||||
searchSource.set('query', $state.query);
|
||||
} else {
|
||||
searchSource.set('query', null);
|
||||
}
|
||||
|
||||
if (_.isEqual(keys, ['filters'])) {
|
||||
// updates will happen in filter watcher if needed
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.fetch();
|
||||
});
|
||||
|
||||
// Without this manual emission, we'd miss filters and queries that were on the $state initially
|
||||
$state.emit('fetch_with_changes');
|
||||
|
||||
$scope.$listen(timefilter, 'fetch', _.bindKey($scope, 'fetch'));
|
||||
|
||||
$scope.$on('ready:vis', function () {
|
||||
$scope.$emit('application.load');
|
||||
|
@ -211,10 +286,20 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
|
|||
|
||||
$scope.$on('$destroy', function () {
|
||||
savedVis.destroy();
|
||||
stateMonitor.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
$scope.fetch = function () {
|
||||
// This is used by some plugins to trigger a fetch (Timelion and Time Series Visual Builder)
|
||||
$rootScope.$broadcast('fetch');
|
||||
$state.save();
|
||||
searchSource.set('filter', queryFilter.getFilters());
|
||||
if (!$state.linked) searchSource.set('query', $state.query);
|
||||
if ($scope.vis.type.requiresSearch) {
|
||||
courier.fetch();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the user clicks "Save" button.
|
||||
*/
|
||||
|
@ -283,5 +368,29 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie
|
|||
searchSource.inherits(parentsParent);
|
||||
};
|
||||
|
||||
function transferVisState(fromVis, toVis, stage) {
|
||||
return function () {
|
||||
|
||||
//verify this before we copy the "new" state
|
||||
const isAggregationsChanged = !fromVis.aggs.jsonDataEquals(toVis.aggs);
|
||||
|
||||
const view = fromVis.getEnabledState();
|
||||
const full = fromVis.getState();
|
||||
toVis.setState(view);
|
||||
editableVis.dirty = false;
|
||||
$state.vis = full;
|
||||
|
||||
/**
|
||||
* Only fetch (full ES round trip), if the play-button has been pressed (ie. 'stage' variable) and if there
|
||||
* has been changes in the Data-tab.
|
||||
*/
|
||||
if (stage && isAggregationsChanged) {
|
||||
$scope.fetch();
|
||||
} else {
|
||||
$state.save();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
<div
|
||||
css-truncate
|
||||
aria-label="{{:: 'Index pattern: ' + vis.indexPattern.id}}"
|
||||
aria-label="{{:: 'Index pattern: ' + indexPattern.id}}"
|
||||
ng-if="vis.type.requiresSearch"
|
||||
class="index-pattern"
|
||||
>
|
||||
{{ vis.indexPattern.id }}
|
||||
{{ indexPattern.id }}
|
||||
</div>
|
||||
|
||||
<nav class="navbar navbar-default subnav">
|
||||
|
@ -31,7 +31,7 @@
|
|||
</a>
|
||||
</li>
|
||||
|
||||
<li ng-repeat="tab in vis.type.editorConfig.optionTabs" ng-class="{active: sidebar.section == tab.name}">
|
||||
<li ng-repeat="tab in vis.type.params.optionTabs" ng-class="{active: sidebar.section == tab.name}">
|
||||
<a
|
||||
class="vis-editor-subnav-link"
|
||||
ng-class="{'is-vis-editor-sub-nav-link-selected': sidebar.section == tab.name}"
|
||||
|
@ -44,7 +44,7 @@
|
|||
</ul>
|
||||
|
||||
<!-- controls -->
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<ul class="nav navbar-nav navbar-right sidebar-controls">
|
||||
<li
|
||||
ng-if="visualizeEditor.softErrorCount() > 0"
|
||||
disabled
|
||||
|
@ -68,7 +68,7 @@
|
|||
>
|
||||
<button
|
||||
data-test-subj="visualizeEditorRenderButton"
|
||||
class="kuiButton kuiButton--primary navbar-btn-link"
|
||||
class="kuiButton kuiButton--success navbar-btn-link"
|
||||
type="submit"
|
||||
ng-disabled="!vis.dirty || visualizeEditor.errorCount() > 0"
|
||||
aria-label="Update the visualization with your changes"
|
||||
|
@ -104,14 +104,8 @@
|
|||
<vis-editor-agg-group ng-if="vis.type.schemas.buckets" group-name="buckets"></vis-editor-agg-group>
|
||||
</div>
|
||||
|
||||
<div class="vis-editor-config" ng-repeat="tab in vis.type.editorConfig.optionTabs" ng-show="sidebar.section == tab.name">
|
||||
<vis-editor-vis-options
|
||||
vis="vis"
|
||||
vis-data="visData"
|
||||
ui-state="uiState"
|
||||
visualize-editor="visualizeEditor"
|
||||
editor="tab.editor"
|
||||
></vis-editor-vis-options>
|
||||
<div class="vis-editor-config" ng-repeat="tab in vis.type.params.optionTabs" ng-show="sidebar.section == tab.name">
|
||||
<vis-editor-vis-options vis="vis" saved-vis="savedVis" ui-state="uiState" editor="tab.editor"></vis-editor-vis-options>
|
||||
</div>
|
||||
|
||||
</form>
|
|
@ -1,8 +1,7 @@
|
|||
import './agg_group';
|
||||
import './vis_options';
|
||||
import 'plugins/kibana/visualize/editor/agg_group';
|
||||
import 'plugins/kibana/visualize/editor/vis_options';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import sidebarTemplate from './sidebar.html';
|
||||
|
||||
import sidebarTemplate from 'plugins/kibana/visualize/editor/sidebar.html';
|
||||
uiModules
|
||||
.get('app/visualize')
|
||||
.directive('visEditorSidebar', function () {
|
||||
|
@ -14,6 +13,7 @@ uiModules
|
|||
scope: true,
|
||||
controllerAs: 'sidebar',
|
||||
controller: function ($scope) {
|
||||
$scope.$bind('vis', 'editableVis');
|
||||
|
||||
$scope.$watch('vis.type', (visType) => {
|
||||
if (visType) {
|
|
@ -47,11 +47,7 @@
|
|||
.flex-parent(0, 1, auto);
|
||||
}
|
||||
|
||||
> visualize {
|
||||
height: 100%;
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -61,7 +57,6 @@
|
|||
|
||||
.vis-editor-content {
|
||||
.flex-parent();
|
||||
width: 100%;
|
||||
z-index: 0;
|
||||
|
||||
// overrides for tablet and desktop
|
||||
|
@ -306,8 +301,9 @@
|
|||
}
|
||||
|
||||
.vis-editor-canvas {
|
||||
flex: 1 0 (@screen-md-min - @vis-editor-sidebar-basis);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
padding-left: @collapser-width;
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
<div class="sidebar-item">
|
||||
<div
|
||||
ng-show="vis.type.params.editor"
|
||||
>
|
||||
<!-- Visualization and other editing UI gets inserted in here. -->
|
||||
<div
|
||||
data-visualization-options
|
|
@ -0,0 +1,35 @@
|
|||
import { uiModules } from 'ui/modules';
|
||||
import visOptionsTemplate from 'plugins/kibana/visualize/editor/vis_options.html';
|
||||
|
||||
/**
|
||||
* This directive sort of "transcludes" in whatever template you pass in via the `editor` attribute.
|
||||
* This lets you specify a full-screen UI for editing a vis type, instead of using the regular
|
||||
* sidebar.
|
||||
*/
|
||||
|
||||
uiModules
|
||||
.get('app/visualize')
|
||||
.directive('visEditorVisOptions', function (Private, $timeout, $compile) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: visOptionsTemplate,
|
||||
scope: {
|
||||
vis: '=',
|
||||
savedVis: '=',
|
||||
uiState: '=',
|
||||
editor: '=',
|
||||
stageEditableVis: '='
|
||||
},
|
||||
link: function ($scope, $el) {
|
||||
const $optionContainer = $el.find('[data-visualization-options]');
|
||||
|
||||
// Bind the `editor` template with the scope.
|
||||
const $editor = $compile($scope.editor)($scope);
|
||||
$optionContainer.append($editor);
|
||||
|
||||
$scope.$watch('vis.type.schemas.all.length', function (len) {
|
||||
$scope.alwaysShowOptions = len === 0;
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
|
@ -1,7 +1,16 @@
|
|||
import 'plugins/kibana/visualize/styles/main.less';
|
||||
import 'plugins/kibana/visualize/editor/editor';
|
||||
import 'plugins/kibana/visualize/wizard/wizard';
|
||||
import 'plugins/kibana/visualize/editor/add_bucket_agg';
|
||||
import 'plugins/kibana/visualize/editor/agg';
|
||||
import 'plugins/kibana/visualize/editor/agg_add';
|
||||
import 'plugins/kibana/visualize/editor/agg_filter';
|
||||
import 'plugins/kibana/visualize/editor/agg_group';
|
||||
import 'plugins/kibana/visualize/editor/agg_param';
|
||||
import 'plugins/kibana/visualize/editor/agg_params';
|
||||
import 'plugins/kibana/visualize/editor/nesting_indicator';
|
||||
import 'plugins/kibana/visualize/editor/sidebar';
|
||||
import 'plugins/kibana/visualize/editor/vis_options';
|
||||
import 'ui/draggable/draggable_container';
|
||||
import 'ui/draggable/draggable_item';
|
||||
import 'ui/draggable/draggable_handle';
|
||||
|
@ -15,17 +24,6 @@ import { VisualizeListingController } from './listing/visualize_listing';
|
|||
import { VisualizeConstants } from './visualize_constants';
|
||||
import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry';
|
||||
import { savedVisualizationProvider } from 'plugins/kibana/visualize/saved_visualizations/saved_visualization_register';
|
||||
import { noneRequestHandlerProvider } from 'ui/vis/request_handlers/none';
|
||||
import { CourierRequestHandlerProvider } from 'ui/vis/request_handlers/courier';
|
||||
import { noneResponseHandler } from 'ui/vis/response_handlers/none';
|
||||
import { BasicResponseHandlerProvider } from 'ui/vis/response_handlers/basic';
|
||||
|
||||
import { defaultEditor } from 'ui/vis/editors/default/default';
|
||||
|
||||
|
||||
import { VisRequestHandlersRegistryProvider } from 'ui/registry/vis_request_handlers';
|
||||
import { VisResponseHandlersRegistryProvider } from 'ui/registry/vis_response_handlers';
|
||||
import { VisEditorTypesRegistryProvider } from 'ui/registry/vis_editor_types';
|
||||
|
||||
uiRoutes
|
||||
.defaults(/visualize/, {
|
||||
|
@ -38,10 +36,5 @@ uiRoutes
|
|||
});
|
||||
|
||||
// preloading
|
||||
SavedObjectRegistryProvider.register(savedVisualizationProvider);
|
||||
VisRequestHandlersRegistryProvider.register(CourierRequestHandlerProvider);
|
||||
VisRequestHandlersRegistryProvider.register(noneRequestHandlerProvider);
|
||||
VisResponseHandlersRegistryProvider.register(noneResponseHandler);
|
||||
VisResponseHandlersRegistryProvider.register(BasicResponseHandlerProvider);
|
||||
VisEditorTypesRegistryProvider.register(defaultEditor);
|
||||
|
||||
SavedObjectRegistryProvider.register(savedVisualizationProvider);
|
||||
|
|
|
@ -5,7 +5,7 @@ import 'plugins/kibana/discover/saved_searches/saved_searches';
|
|||
import './wizard.less';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { DashboardConstants } from 'plugins/kibana/dashboard/dashboard_constants';
|
||||
import { VisualizeConstants } from '../visualize_constants';
|
||||
import routes from 'ui/routes';
|
||||
|
@ -33,13 +33,15 @@ routes.when(VisualizeConstants.WIZARD_STEP_1_PAGE_PATH, {
|
|||
module.controller('VisualizeWizardStep1', function ($scope, $route, kbnUrl, timefilter, Private) {
|
||||
timefilter.enabled = false;
|
||||
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
|
||||
const visTypeCategoryToHumanReadableMap = {
|
||||
[CATEGORY.BASIC]: 'Basic Charts',
|
||||
[CATEGORY.DATA]: 'Data',
|
||||
[CATEGORY.GRAPHIC]: 'Graphic',
|
||||
[CATEGORY.MAP]: 'Maps',
|
||||
[CATEGORY.OTHER]: 'Other',
|
||||
[CATEGORY.TIME]: 'Time Series'
|
||||
[VisType.CATEGORY.BASIC]: 'Basic Charts',
|
||||
[VisType.CATEGORY.DATA]: 'Data',
|
||||
[VisType.CATEGORY.GRAPHIC]: 'Graphic',
|
||||
[VisType.CATEGORY.MAP]: 'Maps',
|
||||
[VisType.CATEGORY.OTHER]: 'Other',
|
||||
[VisType.CATEGORY.TIME]: 'Time Series',
|
||||
};
|
||||
|
||||
const addToDashMode = $route.current.params[DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM];
|
||||
|
@ -52,8 +54,6 @@ module.controller('VisualizeWizardStep1', function ($scope, $route, kbnUrl, time
|
|||
visTypes.forEach(visType => {
|
||||
const categoryName = visType.category;
|
||||
|
||||
if (categoryName === CATEGORY.HIDDEN) return;
|
||||
|
||||
// Create category object if it doesn't exist yet.
|
||||
if (!categoryToVisTypesMap[categoryName]) {
|
||||
categoryToVisTypesMap[categoryName] = {
|
||||
|
@ -74,7 +74,7 @@ module.controller('VisualizeWizardStep1', function ($scope, $route, kbnUrl, time
|
|||
|
||||
// Sort the categories alphabetically.
|
||||
const sortedVisTypeCategories = Object.values(categoryToVisTypesMap).sort((a, b) => {
|
||||
const other = CATEGORY.OTHER.toLowerCase();
|
||||
const other = VisType.CATEGORY.OTHER.toLowerCase();
|
||||
|
||||
// Put "other" category at the end of the list.
|
||||
const labelA = a.label.toLowerCase();
|
||||
|
@ -137,7 +137,7 @@ module.controller('VisualizeWizardStep1', function ($scope, $route, kbnUrl, time
|
|||
|
||||
$scope.getVisTypeUrl = function (visType) {
|
||||
const baseUrl =
|
||||
visType.requiresSearch && visType.options.showIndexSelection
|
||||
visType.requiresSearch
|
||||
? `#${VisualizeConstants.WIZARD_STEP_2_PAGE_PATH}?`
|
||||
: `#${VisualizeConstants.CREATE_PATH}?`;
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ describe('markdown vis controller', function () {
|
|||
beforeEach(ngMock.module('kibana/markdown_vis'));
|
||||
beforeEach(ngMock.inject(function ($rootScope, $controller) {
|
||||
$scope = $rootScope.$new();
|
||||
$scope.renderComplete = () => {};
|
||||
const $element = $('<div>');
|
||||
$controller('KbnMarkdownVisController', { $scope, $element });
|
||||
$scope.$digest();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'plugins/markdown_vis/markdown_vis.less';
|
||||
import 'plugins/markdown_vis/markdown_vis_controller';
|
||||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { TemplateVisTypeProvider } from 'ui/template_vis_type/template_vis_type';
|
||||
import markdownVisTemplate from 'plugins/markdown_vis/markdown_vis.html';
|
||||
import markdownVisParamsTemplate from 'plugins/markdown_vis/markdown_vis_params.html';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
|
@ -14,23 +14,22 @@ import image from './images/icon-markdown.svg';
|
|||
VisTypesRegistryProvider.register(MarkdownVisProvider);
|
||||
|
||||
function MarkdownVisProvider(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const TemplateVisType = Private(TemplateVisTypeProvider);
|
||||
|
||||
// return the visType object, which kibana will use to display and configure new
|
||||
// Vis object of this type.
|
||||
return VisFactory.createAngularVisualization({
|
||||
return new TemplateVisType({
|
||||
name: 'markdown',
|
||||
title: 'Markdown',
|
||||
image,
|
||||
description: 'Create a document using markdown syntax',
|
||||
category: CATEGORY.OTHER,
|
||||
visConfig: {
|
||||
template: markdownVisTemplate,
|
||||
category: VisType.CATEGORY.OTHER,
|
||||
template: markdownVisTemplate,
|
||||
params: {
|
||||
editor: markdownVisParamsTemplate
|
||||
},
|
||||
editorConfig: {
|
||||
optionsTemplate: markdownVisParamsTemplate
|
||||
},
|
||||
requestHandler: 'none',
|
||||
requiresSearch: false,
|
||||
implementsRenderComplete: true,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ marked.setOptions({
|
|||
|
||||
|
||||
const module = uiModules.get('kibana/markdown_vis', ['kibana', 'ngSanitize']);
|
||||
module.controller('KbnMarkdownVisController', function ($scope) {
|
||||
module.controller('KbnMarkdownVisController', function ($scope, $element) {
|
||||
$scope.$watch('vis.params.markdown', function (html) {
|
||||
if (html) {
|
||||
$scope.html = marked(html);
|
||||
}
|
||||
$scope.renderComplete();
|
||||
$element.trigger('renderComplete');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,42 +3,28 @@ import VisEditorVisualization from './vis_editor_visualization';
|
|||
import Visualization from './visualization';
|
||||
import VisPicker from './vis_picker';
|
||||
import PanelConfig from './panel_config';
|
||||
import brushHandler from '../lib/create_brush_handler';
|
||||
|
||||
class VisEditor extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { model: props.vis.params, dirty: false, autoApply: true };
|
||||
this.onBrush = brushHandler(props.vis.API.timeFilter);
|
||||
this.state = { model: props.model };
|
||||
}
|
||||
|
||||
render() {
|
||||
const handleChange = (part) => {
|
||||
const nextModel = { ...this.state.model, ...part };
|
||||
|
||||
this.props.vis.params = nextModel;
|
||||
if (this.state.autoApply) {
|
||||
this.props.vis.updateState();
|
||||
this.setState({ model: nextModel });
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(nextModel);
|
||||
}
|
||||
|
||||
this.setState({ model: nextModel, dirty: !this.state.autoApply });
|
||||
};
|
||||
|
||||
const handleAutoApplyToggle = (part) => {
|
||||
this.setState({ autoApply: part.target.checked });
|
||||
};
|
||||
|
||||
const handleCommit = () => {
|
||||
this.props.vis.updateState();
|
||||
this.setState({ dirty: false });
|
||||
};
|
||||
|
||||
if (!this.props.vis.isEditorMode()) {
|
||||
if (this.props.embedded) {
|
||||
return (
|
||||
<Visualization
|
||||
fields={this.props.vis.fields}
|
||||
model={this.props.vis.params}
|
||||
fields={this.props.fields}
|
||||
model={this.props.model}
|
||||
visData={this.props.visData} />
|
||||
);
|
||||
}
|
||||
|
@ -53,30 +39,25 @@ class VisEditor extends Component {
|
|||
model={model}
|
||||
onChange={handleChange} />
|
||||
<VisEditorVisualization
|
||||
dirty={this.state.dirty}
|
||||
autoApply={this.state.autoApply}
|
||||
dirty={this.props.dirty}
|
||||
autoApply={this.props.autoApply}
|
||||
model={model}
|
||||
visData={this.props.visData}
|
||||
onBrush={this.onBrush}
|
||||
onCommit={handleCommit}
|
||||
onToggleAutoApply={handleAutoApplyToggle}
|
||||
onBrush={this.props.onBrush}
|
||||
onCommit={this.props.onCommit}
|
||||
onToggleAutoApply={this.props.onToggleAutoApply}
|
||||
onChange={handleChange} />
|
||||
<PanelConfig
|
||||
fields={this.props.vis.fields}
|
||||
fields={this.props.fields}
|
||||
model={model}
|
||||
visData={this.props.visData}
|
||||
onChange={handleChange} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.renderComplete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VisEditor.propTypes = {
|
||||
|
|
37
src/core_plugins/metrics/public/directives/vis_editor.js
Normal file
37
src/core_plugins/metrics/public/directives/vis_editor.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import VisEditor from '../components/vis_editor';
|
||||
import addScope from '../lib/add_scope';
|
||||
import angular from 'angular';
|
||||
import createBrushHandler from '../lib/create_brush_handler';
|
||||
const app = uiModules.get('apps/metrics/directives');
|
||||
app.directive('metricsVisEditor', (timefilter) => {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: ($scope, $el) => {
|
||||
const addToState = ['autoApply', 'dirty', 'embedded', 'fields', 'visData'];
|
||||
const Component = addScope(VisEditor, $scope, addToState);
|
||||
const handleBrush = createBrushHandler($scope, timefilter);
|
||||
const handleChange = part => {
|
||||
$scope.$evalAsync(() => angular.copy(part, $scope.model));
|
||||
};
|
||||
const handleCommit = () => {
|
||||
$scope.$evalAsync(() => $scope.commit());
|
||||
};
|
||||
const handleToggleAutoApply = () => {
|
||||
$scope.$evalAsync(() => $scope.toggleAutoApply());
|
||||
};
|
||||
render(<Component
|
||||
model={$scope.model}
|
||||
onCommit={handleCommit}
|
||||
onToggleAutoApply={handleToggleAutoApply}
|
||||
onChange={handleChange}
|
||||
onBrush={handleBrush} />, $el[0]);
|
||||
$scope.$on('$destroy', () => {
|
||||
unmountComponentAtNode($el[0]);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
46
src/core_plugins/metrics/public/directives/visualization.js
Normal file
46
src/core_plugins/metrics/public/directives/visualization.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import Visualization from '../components/visualization';
|
||||
import addScope from '../lib/add_scope';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import createBrushHandler from '../lib/create_brush_handler';
|
||||
|
||||
const app = uiModules.get('apps/metrics/directives');
|
||||
app.directive('metricsVisualization', (timefilter, $timeout) => {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: ($scope, $el) => {
|
||||
const addToState = ['model', 'visData', 'reversed'];
|
||||
const Component = addScope(Visualization, $scope, addToState);
|
||||
const handleBrush = createBrushHandler($scope, timefilter);
|
||||
render(<Component onBrush={handleBrush} className="dashboard__visualization"/>, $el[0]);
|
||||
$scope.$on('$destroy', () => unmountComponentAtNode($el[0]));
|
||||
|
||||
// For Metrics, Gauges and markdown visualizations we want to hide the
|
||||
// panel title because it just doens't make sense to show it.
|
||||
// This is wrapped in a timeout so it happens after the directive is mouted.
|
||||
// otherwise the .panel might not be available.
|
||||
$timeout(() => {
|
||||
const panel = $($el[0]).parents('.panel');
|
||||
if (panel.length) {
|
||||
const panelHeading = panel.find('.panel-heading');
|
||||
const panelTitle = panel.find('.panel-title');
|
||||
const matchingTypes = ['metric', 'gauge', 'markdown'];
|
||||
if (panelHeading.length && panelTitle.length && _.contains(matchingTypes, $scope.model.type)) {
|
||||
panel.css({ position: 'relative' });
|
||||
panelHeading.css({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
zIndex: 100
|
||||
});
|
||||
panelTitle.css({ display: 'none' });
|
||||
}
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<div
|
||||
class="vis_editor_container"
|
||||
ng-controller="MetricsEditorController" >
|
||||
<metrics-vis-editor/>
|
||||
</div>
|
|
@ -1,47 +1,122 @@
|
|||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { FetchFieldsProvider } from '../lib/fetch_fields';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import '../services/executor';
|
||||
import createNewPanel from '../lib/create_new_panel';
|
||||
import '../directives/vis_editor';
|
||||
import _ from 'lodash';
|
||||
import angular from 'angular';
|
||||
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
|
||||
const AUTO_APPLY_KEY = 'metrics_autoApply';
|
||||
|
||||
function ReactEditorControllerProvider(Private, localStorage) {
|
||||
const fetchFields = Private(FetchFieldsProvider);
|
||||
const app = uiModules.get('kibana/metrics_vis', ['kibana']);
|
||||
app.controller('MetricsEditorController', (
|
||||
$location,
|
||||
$element,
|
||||
$scope,
|
||||
Private,
|
||||
timefilter,
|
||||
localStorage,
|
||||
metricsExecutor
|
||||
) => {
|
||||
|
||||
class ReactEditorController {
|
||||
constructor(el, vis) {
|
||||
this.el = el;
|
||||
this.vis = vis;
|
||||
const autoApply = localStorage.get(AUTO_APPLY_KEY);
|
||||
$scope.autoApply = autoApply != null ? autoApply : true;
|
||||
$scope.embedded = $location.search().embed === 'true';
|
||||
const queryFilter = Private(FilterBarQueryFilterProvider);
|
||||
const createFetch = Private(require('../lib/fetch'));
|
||||
const fetch = () => {
|
||||
const fn = createFetch($scope);
|
||||
return fn().then((resp) => {
|
||||
$element.trigger('renderComplete');
|
||||
return resp;
|
||||
});
|
||||
};
|
||||
const fetchFields = Private(require('../lib/fetch_fields'));
|
||||
|
||||
const autoApply = localStorage.get(AUTO_APPLY_KEY);
|
||||
vis.autoApply = autoApply != null ? autoApply : true;
|
||||
const debouncedFetch = _.debounce(() => fetch(), 1000, {
|
||||
leading: false,
|
||||
trailing: true
|
||||
});
|
||||
|
||||
const debouncedFetchFields = _.debounce(fetchFields($scope), 1000, {
|
||||
leading: false,
|
||||
trailing: true
|
||||
});
|
||||
|
||||
// If the model doesn't exist we need to either intialize it with a copy from
|
||||
// the $scope.vis._editableVis.params or create a new panel all together.
|
||||
if (!$scope.model) {
|
||||
if ($scope.vis._editableVis.params.type) {
|
||||
$scope.model = _.assign({}, $scope.vis._editableVis.params);
|
||||
} else {
|
||||
$scope.model = createNewPanel();
|
||||
angular.copy($scope.model, $scope.vis._editableVis.params);
|
||||
}
|
||||
fetch();
|
||||
}
|
||||
|
||||
$scope.commit = () => {
|
||||
fetch();
|
||||
$scope.dirty = false;
|
||||
};
|
||||
|
||||
$scope.toggleAutoApply = () => {
|
||||
$scope.autoApply = !$scope.autoApply;
|
||||
localStorage.set(AUTO_APPLY_KEY, $scope.autoApply);
|
||||
};
|
||||
|
||||
$scope.$watchCollection('model', (newValue, oldValue) => {
|
||||
angular.copy(newValue, $scope.vis._editableVis.params);
|
||||
$scope.stageEditableVis();
|
||||
$scope.dirty = !_.isEqual(newValue, oldValue);
|
||||
|
||||
if ($scope.dirty && $scope.autoApply) {
|
||||
debouncedFetch();
|
||||
$scope.dirty = false;
|
||||
}
|
||||
|
||||
render(visData) {
|
||||
this.visData = visData;
|
||||
const patternsToFetch = [];
|
||||
// Fetch any missing index patterns
|
||||
if (!$scope.fields[newValue.index_pattern]) {
|
||||
patternsToFetch.push(newValue.index_pattern);
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
fetchFields(this.vis.params.index_pattern).then(fields => {
|
||||
this.vis.fields = fields;
|
||||
const Component = this.vis.type.editorConfig.component;
|
||||
render(<Component vis={this.vis} visData={visData} renderComplete={resolve}/>, this.el);
|
||||
});
|
||||
newValue.series.forEach(series => {
|
||||
if (series.override_index_pattern &&
|
||||
!$scope.fields[series.series_index_pattern]) {
|
||||
patternsToFetch.push(series.series_index_pattern);
|
||||
}
|
||||
});
|
||||
|
||||
if (newValue.annotations) {
|
||||
newValue.annotations.forEach(item => {
|
||||
if (item.index_pattern &&
|
||||
!$scope.fields[item.index_pattern]) {
|
||||
patternsToFetch.push(item.index_pattern);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
resize() {
|
||||
if (this.visData) {
|
||||
this.render(this.visData);
|
||||
}
|
||||
if(patternsToFetch.length) {
|
||||
debouncedFetchFields(_.unique(patternsToFetch));
|
||||
}
|
||||
});
|
||||
|
||||
destroy() {
|
||||
unmountComponentAtNode(this.el);
|
||||
}
|
||||
}
|
||||
$scope.visData = {};
|
||||
$scope.fields = {};
|
||||
// All those need to be consolidated
|
||||
$scope.$listen(queryFilter, 'fetch', fetch);
|
||||
$scope.$on('fetch', fetch);
|
||||
|
||||
return {
|
||||
name: 'react_editor',
|
||||
handler: ReactEditorController
|
||||
};
|
||||
}
|
||||
fetchFields($scope)($scope.model.index_pattern);
|
||||
|
||||
// Register fetch
|
||||
metricsExecutor.register({ execute: fetch });
|
||||
|
||||
// Start the executor
|
||||
metricsExecutor.start();
|
||||
|
||||
// Destory the executor
|
||||
$scope.$on('$destroy', metricsExecutor.destroy);
|
||||
|
||||
});
|
||||
|
||||
export { ReactEditorControllerProvider };
|
||||
|
|
|
@ -1,65 +1,36 @@
|
|||
import './vis_controller';
|
||||
import './editor_controller';
|
||||
import '../visualizations/less/main.less';
|
||||
import 'react-select/dist/react-select.css';
|
||||
import '../less/main.less';
|
||||
import image from '../images/icon-visualbuilder.svg';
|
||||
import { MetricsRequestHandlerProvider } from './request_handler';
|
||||
import { ReactEditorControllerProvider } from './editor_controller';
|
||||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { TemplateVisTypeProvider } from 'ui/template_vis_type';
|
||||
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
// register the provider with the visTypes registry so that other know it exists
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
VisTypesRegistryProvider.register(MetricsVisProvider);
|
||||
|
||||
export default function MetricsVisProvider(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const ReactEditorController = Private(ReactEditorControllerProvider).handler;
|
||||
const metricsRequestHandler = Private(MetricsRequestHandlerProvider).handler;
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const TemplateVisType = Private(TemplateVisTypeProvider);
|
||||
|
||||
return VisFactory.createReactVisualization({
|
||||
// return the visType object, which kibana will use to display and configure new
|
||||
// Vis object of this type.
|
||||
return new TemplateVisType({
|
||||
name: 'metrics',
|
||||
title: 'Visual Builder',
|
||||
description: 'Build time-series using a visual pipeline interface',
|
||||
category: CATEGORY.TIME,
|
||||
image,
|
||||
description: 'Build time-series using a visual pipeline interface',
|
||||
category: VisType.CATEGORY.TIME,
|
||||
isExperimental: true,
|
||||
visConfig: {
|
||||
defaults: {
|
||||
id: '61ca57f0-469d-11e7-af02-69e470af7417',
|
||||
type: 'timeseries',
|
||||
series: [
|
||||
{
|
||||
id: '61ca57f1-469d-11e7-af02-69e470af7417',
|
||||
color: '#68BC00',
|
||||
split_mode: 'everything',
|
||||
metrics: [
|
||||
{
|
||||
id: '61ca57f2-469d-11e7-af02-69e470af7417',
|
||||
type: 'count'
|
||||
}],
|
||||
seperate_axis: 0,
|
||||
axis_position: 'right',
|
||||
formatter: 'number',
|
||||
chart_type: 'line',
|
||||
line_width: 1,
|
||||
point_size: 1,
|
||||
fill: 0.5,
|
||||
stacked: 'none'
|
||||
}],
|
||||
time_field: '@timestamp',
|
||||
index_pattern: '*',
|
||||
interval: 'auto',
|
||||
axis_position: 'left',
|
||||
axis_formatter: 'number',
|
||||
show_legend:1
|
||||
},
|
||||
component: require('../components/vis_editor')
|
||||
template: require('./vis.html'),
|
||||
fullEditor: true,
|
||||
params: {
|
||||
editor: require('./editor.html')
|
||||
},
|
||||
editor: ReactEditorController,
|
||||
editorConfig: {
|
||||
component: require('../components/vis_editor')
|
||||
},
|
||||
requestHandler: metricsRequestHandler,
|
||||
responseHandler: 'none'
|
||||
requiresSearch: false,
|
||||
requiresTimePicker: true,
|
||||
implementsRenderComplete: true,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
import { validateInterval } from '../lib/validate_interval';
|
||||
import { dashboardContextProvider } from 'plugins/kibana/dashboard/dashboard_context';
|
||||
|
||||
const MetricsRequestHandlerProvider = function (Private, Notifier, config, timefilter, $http) {
|
||||
const dashboardContext = Private(dashboardContextProvider);
|
||||
const notify = new Notifier({ location: 'Metrics' });
|
||||
|
||||
return {
|
||||
name: 'metrics',
|
||||
handler: function (vis /*, appState, uiState*/) {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const panel = vis.params;
|
||||
if (panel && panel.id) {
|
||||
const params = {
|
||||
timerange: timefilter.getBounds(),
|
||||
filters: [dashboardContext()],
|
||||
panels: [panel]
|
||||
};
|
||||
|
||||
try {
|
||||
const maxBuckets = config.get('metrics:max_buckets');
|
||||
validateInterval(timefilter, panel, maxBuckets);
|
||||
return $http.post('../api/metrics/vis/data', params)
|
||||
.success(resp => {
|
||||
|
||||
const patternsToFetch = [];
|
||||
// Fetch any missing index patterns
|
||||
if (!vis.fields) vis.fields = {};
|
||||
|
||||
if (!vis.fields[vis.params.index_pattern]) {
|
||||
patternsToFetch.push(vis.params.index_pattern);
|
||||
}
|
||||
|
||||
vis.params.series.forEach(series => {
|
||||
if (series.override_index_pattern &&
|
||||
!vis.fields[series.series_index_pattern]) {
|
||||
patternsToFetch.push(series.series_index_pattern);
|
||||
}
|
||||
});
|
||||
|
||||
if (vis.params.annotations) {
|
||||
vis.params.annotations.forEach(item => {
|
||||
if (item.index_pattern &&
|
||||
!vis.fields[item.index_pattern]) {
|
||||
patternsToFetch.push(item.index_pattern);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
resolve(resp);
|
||||
})
|
||||
.error(resp => {
|
||||
resolve({});
|
||||
const err = new Error(resp.message);
|
||||
err.stack = resp.stack;
|
||||
notify.error(err);
|
||||
});
|
||||
} catch (e) {
|
||||
notify.error(e);
|
||||
return resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { MetricsRequestHandlerProvider };
|
4
src/core_plugins/metrics/public/kbn_vis_types/vis.html
Normal file
4
src/core_plugins/metrics/public/kbn_vis_types/vis.html
Normal file
|
@ -0,0 +1,4 @@
|
|||
<div
|
||||
ng-controller="MetricsVisController">
|
||||
<metrics-visualization/>
|
||||
</div>
|
|
@ -0,0 +1,49 @@
|
|||
import { uiModules } from 'ui/modules';
|
||||
import 'ui/state_management/app_state';
|
||||
import '../directives/visualization';
|
||||
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
|
||||
|
||||
const app = uiModules.get('kibana/metrics_vis');
|
||||
|
||||
app.controller('MetricsVisController', (
|
||||
$scope,
|
||||
$element,
|
||||
Private,
|
||||
timefilter,
|
||||
getAppState,
|
||||
$location
|
||||
) => {
|
||||
|
||||
// If we are in the visualize editor context (and not embedded) we should not
|
||||
// render the visualizations. This is handled by the editor itself.
|
||||
const embedded = $location.search().embed === 'true';
|
||||
if (!embedded && $scope.vis._editableVis) {
|
||||
return;
|
||||
}
|
||||
// We need to watch the app state for changes to the dark theme attribute.
|
||||
$scope.state = getAppState();
|
||||
$scope.$watch('state.options.darkTheme', newValue => {
|
||||
$scope.reversed = Boolean(newValue);
|
||||
});
|
||||
|
||||
const queryFilter = Private(FilterBarQueryFilterProvider);
|
||||
const createFetch = Private(require('../lib/fetch'));
|
||||
const fetch = () => {
|
||||
const fn = createFetch($scope);
|
||||
return fn().then((resp) => {
|
||||
$element.trigger('renderComplete');
|
||||
return resp;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$scope.model = $scope.vis.params;
|
||||
$scope.$watch('vis.params', fetch);
|
||||
|
||||
// All those need to be consolidated
|
||||
$scope.$listen(timefilter, 'fetch', fetch);
|
||||
$scope.$listen(queryFilter, 'fetch', fetch);
|
||||
|
||||
$scope.$on('courier:searchRefresh', fetch);
|
||||
$scope.$on('fetch', fetch);
|
||||
});
|
|
@ -1,8 +1,5 @@
|
|||
@borderRadius: 4px;
|
||||
|
||||
.vis_editor {
|
||||
flex: 1;
|
||||
}
|
||||
.vis_editor_container {
|
||||
background: @pageColor;
|
||||
}
|
||||
|
|
58
src/core_plugins/metrics/public/lib/__tests__/add_scope.js
Normal file
58
src/core_plugins/metrics/public/lib/__tests__/add_scope.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
import React from 'react';
|
||||
import { expect } from 'chai';
|
||||
import { shallow } from 'enzyme';
|
||||
import sinon from 'sinon';
|
||||
import addScope from '../add_scope';
|
||||
|
||||
const Component = React.createClass({
|
||||
render() {
|
||||
return (<div/>);
|
||||
}
|
||||
});
|
||||
|
||||
describe('addScope()', () => {
|
||||
|
||||
let unsubStub;
|
||||
let watchCollectionStub;
|
||||
let $scope;
|
||||
|
||||
beforeEach(() => {
|
||||
unsubStub = sinon.stub();
|
||||
watchCollectionStub = sinon.stub().returns(unsubStub);
|
||||
$scope = {
|
||||
$watchCollection: watchCollectionStub,
|
||||
testOne: 1,
|
||||
testTwo: 2
|
||||
};
|
||||
});
|
||||
|
||||
it('adds $scope variables as props to wrapped component', () => {
|
||||
const WrappedComponent = addScope(Component, $scope, ['testOne', 'testTwo']);
|
||||
const wrapper = shallow(<WrappedComponent/>);
|
||||
expect(wrapper.state('testOne')).to.equal(1);
|
||||
expect(wrapper.state('testTwo')).to.equal(2);
|
||||
});
|
||||
|
||||
it('calls $scope.$watchCollection on each scoped item', () => {
|
||||
const WrappedComponent = addScope(Component, $scope, ['testOne', 'testTwo']);
|
||||
shallow(<WrappedComponent/>);
|
||||
expect(watchCollectionStub.calledTwice).to.equal(true);
|
||||
expect(watchCollectionStub.firstCall.args[0]).to.equal('testOne');
|
||||
expect(watchCollectionStub.secondCall.args[0]).to.equal('testTwo');
|
||||
});
|
||||
|
||||
it('unsubscribes from watches', () => {
|
||||
const WrappedComponent = addScope(Component, $scope, ['testOne', 'testTwo']);
|
||||
const wrapper = shallow(<WrappedComponent/>);
|
||||
wrapper.unmount();
|
||||
expect(unsubStub.calledTwice).to.equal(true);
|
||||
});
|
||||
|
||||
it('updates state when watch is called', () => {
|
||||
const WrappedComponent = addScope(Component, $scope, ['testOne']);
|
||||
const wrapper = shallow(<WrappedComponent/>);
|
||||
watchCollectionStub.firstCall.args[1].call(null, 3);
|
||||
expect(wrapper.state('testOne')).to.equal(3);
|
||||
});
|
||||
|
||||
});
|
|
@ -1,19 +1,29 @@
|
|||
import createBrushHandler from '../create_brush_handler';
|
||||
import sinon from 'sinon';
|
||||
import moment from 'moment';
|
||||
import { expect } from 'chai';
|
||||
|
||||
describe('createBrushHandler', () => {
|
||||
|
||||
let evalAsyncStub;
|
||||
let $scope;
|
||||
let timefilter;
|
||||
let fn;
|
||||
let range;
|
||||
|
||||
beforeEach(() => {
|
||||
timefilter = { time: {}, update: () => {} };
|
||||
fn = createBrushHandler(timefilter);
|
||||
evalAsyncStub = sinon.stub().yields();
|
||||
$scope = { $evalAsync: evalAsyncStub };
|
||||
timefilter = { time: {} };
|
||||
fn = createBrushHandler($scope, timefilter);
|
||||
range = { xaxis: { from: '2017-01-01T00:00:00Z', to: '2017-01-01T00:10:00Z' } };
|
||||
fn(range);
|
||||
});
|
||||
|
||||
it('returns brushHandler() that calls $scope.$evalAsync()', () => {
|
||||
expect(evalAsyncStub.calledOnce).to.equal(true);
|
||||
});
|
||||
|
||||
it('returns brushHandler() that updates timefilter', () => {
|
||||
expect(timefilter.time.from).to.equal(moment(range.xaxis.from).toISOString());
|
||||
expect(timefilter.time.to).to.equal(moment(range.xaxis.to).toISOString());
|
||||
|
|
33
src/core_plugins/metrics/public/lib/add_scope.js
Normal file
33
src/core_plugins/metrics/public/lib/add_scope.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
export default function addScope(WrappedComponent, $scope, addToState = []) {
|
||||
return React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
const state = {};
|
||||
addToState.forEach(key => {
|
||||
state[key] = $scope[key];
|
||||
});
|
||||
return state;
|
||||
},
|
||||
|
||||
componentWillMount() {
|
||||
this.unsubs = addToState.map(key => {
|
||||
return $scope.$watchCollection(key, newValue => {
|
||||
const newState = {};
|
||||
newState[key] = newValue;
|
||||
this.setState(newState);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unsubs.forEach(fn => fn());
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<WrappedComponent {...this.state} {...this.props}/>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
import moment from 'moment';
|
||||
export default (timefilter) => ranges => {
|
||||
//$scope.$evalAsync(() => {
|
||||
timefilter.time.from = moment(ranges.xaxis.from).toISOString();
|
||||
timefilter.time.to = moment(ranges.xaxis.to).toISOString();
|
||||
timefilter.time.mode = 'absolute';
|
||||
timefilter.update();
|
||||
//});
|
||||
export default ($scope, timefilter) => ranges => {
|
||||
$scope.$evalAsync(() => {
|
||||
timefilter.time.from = moment(ranges.xaxis.from).toISOString();
|
||||
timefilter.time.to = moment(ranges.xaxis.to).toISOString();
|
||||
timefilter.time.mode = 'absolute';
|
||||
});
|
||||
};
|
||||
|
|
42
src/core_plugins/metrics/public/lib/fetch.js
Normal file
42
src/core_plugins/metrics/public/lib/fetch.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { validateInterval } from './validate_interval';
|
||||
import { dashboardContextProvider } from 'plugins/kibana/dashboard/dashboard_context';
|
||||
export default (
|
||||
timefilter,
|
||||
Private,
|
||||
Notifier,
|
||||
$http,
|
||||
config,
|
||||
) => {
|
||||
const dashboardContext = Private(dashboardContextProvider);
|
||||
const notify = new Notifier({ location: 'Metrics' });
|
||||
return $scope => () => {
|
||||
const panel = $scope.model;
|
||||
if (panel && panel.id) {
|
||||
const params = {
|
||||
timerange: timefilter.getBounds(),
|
||||
filters: [dashboardContext()],
|
||||
panels: [panel]
|
||||
};
|
||||
|
||||
try {
|
||||
const maxBuckets = config.get('metrics:max_buckets');
|
||||
validateInterval(timefilter, panel, maxBuckets);
|
||||
return $http.post('../api/metrics/vis/data', params)
|
||||
.success(resp => {
|
||||
$scope.visData = resp;
|
||||
})
|
||||
.error(resp => {
|
||||
$scope.visData = {};
|
||||
const err = new Error(resp.message);
|
||||
err.stack = resp.stack;
|
||||
notify.error(err);
|
||||
});
|
||||
} catch (e) {
|
||||
notify.error(e);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
};
|
||||
|
|
@ -1,29 +1,25 @@
|
|||
const FetchFieldsProvider = (Notifier, $http) => {
|
||||
export default (
|
||||
Notifier,
|
||||
$http
|
||||
) => {
|
||||
const notify = new Notifier({ location: 'Metrics' });
|
||||
return (indexPatterns = ['*']) => {
|
||||
return $scope => (indexPatterns = ['*']) => {
|
||||
if (!Array.isArray(indexPatterns)) indexPatterns = [indexPatterns];
|
||||
return new Promise((resolve, reject) => {
|
||||
const fields = {};
|
||||
|
||||
Promise.all(indexPatterns.map(pattern => {
|
||||
return $http.get(`../api/metrics/fields?index=${pattern}`)
|
||||
.success(resp => {
|
||||
if (resp.length && pattern) {
|
||||
fields[pattern] = resp;
|
||||
}
|
||||
})
|
||||
.error(resp => {
|
||||
const err = new Error(resp.message);
|
||||
err.stack = resp.stack;
|
||||
notify.error(err);
|
||||
reject(err);
|
||||
});
|
||||
})).then(() => {
|
||||
resolve(fields);
|
||||
});
|
||||
});
|
||||
return Promise.all(indexPatterns.map(pattern => {
|
||||
return $http.get(`../api/metrics/fields?index=${pattern}`)
|
||||
.success(resp => {
|
||||
if (!$scope.fields) $scope.fields = {};
|
||||
if (resp.length && pattern) {
|
||||
$scope.fields[pattern] = resp;
|
||||
}
|
||||
})
|
||||
.error(resp => {
|
||||
$scope.visData = {};
|
||||
const err = new Error(resp.message);
|
||||
err.stack = resp.stack;
|
||||
notify.error(err);
|
||||
});
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
export { FetchFieldsProvider };
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import $ from 'jquery';
|
|||
import L from 'leaflet';
|
||||
import _ from 'lodash';
|
||||
import d3 from 'd3';
|
||||
import { KibanaMapLayer } from '../../tile_map/public/kibana_map_layer';
|
||||
import { KibanaMapLayer } from 'ui/vis_maps/kibana_map_layer';
|
||||
import { truncatedColorMaps } from 'ui/vislib/components/color/truncated_colormaps';
|
||||
|
||||
export default class ChoroplethLayer extends KibanaMapLayer {
|
||||
|
|
|
@ -2,11 +2,12 @@ import { uiModules } from 'ui/modules';
|
|||
import 'plugins/kbn_vislib_vis_types/controls/vislib_basic_options';
|
||||
import _ from 'lodash';
|
||||
import AggConfigResult from 'ui/vis/agg_config_result';
|
||||
import { KibanaMap } from '../../tile_map/public/kibana_map';
|
||||
import { KibanaMap } from 'ui/vis_maps/kibana_map';
|
||||
import ChoroplethLayer from './choropleth_layer';
|
||||
import { truncatedColorMaps } from 'ui/vislib/components/color/truncated_colormaps';
|
||||
import AggResponsePointSeriesTooltipFormatterProvider from './tooltip_formatter';
|
||||
import '../../tile_map/public/lib/service_settings';
|
||||
import { ResizeCheckerProvider } from 'ui/resize_checker';
|
||||
import 'ui/vis_maps/lib/service_settings';
|
||||
|
||||
|
||||
const module = uiModules.get('kibana/region_map', ['kibana']);
|
||||
|
@ -14,18 +15,18 @@ module.controller('KbnRegionMapController', function ($scope, $element, Private,
|
|||
serviceSettings, config) {
|
||||
|
||||
const tooltipFormatter = Private(AggResponsePointSeriesTooltipFormatterProvider);
|
||||
const ResizeChecker = Private(ResizeCheckerProvider);
|
||||
const notify = new Notifier({ location: 'Region map' });
|
||||
|
||||
const resizeChecker = new ResizeChecker($element);
|
||||
|
||||
let kibanaMap = null;
|
||||
let choroplethLayer = null;
|
||||
const kibanaMapReady = makeKibanaMap();
|
||||
|
||||
$scope.$watch('resize', () => {
|
||||
resizeChecker.on('resize', () => {
|
||||
if (kibanaMap) {
|
||||
kibanaMap.resize();
|
||||
}
|
||||
});
|
||||
let choroplethLayer = null;
|
||||
const kibanaMapReady = makeKibanaMap();
|
||||
|
||||
$scope.$watch('esResponse', async function (response) {
|
||||
kibanaMapReady.then(() => {
|
||||
|
|
|
@ -3,29 +3,32 @@ import './region_map_controller';
|
|||
import './region_map_vis_params';
|
||||
import regionTemplate from './region_map_controller.html';
|
||||
import image from './images/icon-vector-map.svg';
|
||||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { TemplateVisTypeProvider } from 'ui/template_vis_type/template_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { truncatedColorMaps } from 'ui/vislib/components/color/truncated_colormaps';
|
||||
|
||||
VisTypesRegistryProvider.register(function RegionMapProvider(Private, regionmapsConfig) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const TemplateVisType = Private(TemplateVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
const vectorLayers = regionmapsConfig.layers;
|
||||
const selectedLayer = vectorLayers[0];
|
||||
const selectedJoinField = selectedLayer ? vectorLayers[0].fields[0] : null;
|
||||
|
||||
return VisFactory.createAngularVisualization({
|
||||
return new TemplateVisType({
|
||||
name: 'region_map',
|
||||
title: 'Region Map',
|
||||
implementsRenderComplete: true,
|
||||
description: 'Show metrics on a thematic map. Use one of the provide base maps, or add your own. ' +
|
||||
'Darker colors represent higher values.',
|
||||
category: CATEGORY.MAP,
|
||||
category: VisType.CATEGORY.MAP,
|
||||
image,
|
||||
visConfig: {
|
||||
template: regionTemplate,
|
||||
params: {
|
||||
defaults: {
|
||||
legendPosition: 'bottomright',
|
||||
addTooltip: true,
|
||||
|
@ -33,51 +36,45 @@ VisTypesRegistryProvider.register(function RegionMapProvider(Private, regionmaps
|
|||
selectedLayer: selectedLayer,
|
||||
selectedJoinField: selectedJoinField
|
||||
},
|
||||
template: regionTemplate,
|
||||
legendPositions: [{
|
||||
value: 'bottomleft',
|
||||
text: 'bottom left',
|
||||
}, {
|
||||
value: 'bottomright',
|
||||
text: 'bottom right',
|
||||
}, {
|
||||
value: 'topleft',
|
||||
text: 'top left',
|
||||
}, {
|
||||
value: 'topright',
|
||||
text: 'top right',
|
||||
}],
|
||||
colorSchemas: Object.keys(truncatedColorMaps),
|
||||
vectorLayers: vectorLayers,
|
||||
editor: '<region_map-vis-params></region_map-vis-params>'
|
||||
},
|
||||
editorConfig: {
|
||||
optionsTemplate: '<region_map-vis-params></region_map-vis-params>',
|
||||
collections: {
|
||||
legendPositions: [{
|
||||
value: 'bottomleft',
|
||||
text: 'bottom left',
|
||||
}, {
|
||||
value: 'bottomright',
|
||||
text: 'bottom right',
|
||||
}, {
|
||||
value: 'topleft',
|
||||
text: 'top left',
|
||||
}, {
|
||||
value: 'topright',
|
||||
text: 'top right',
|
||||
}],
|
||||
colorSchemas: Object.keys(truncatedColorMaps),
|
||||
vectorLayers: vectorLayers,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Value',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality', 'top_hits', 'sum_bucket', 'min_bucket', 'max_bucket', 'avg_bucket'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Value',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality', 'top_hits',
|
||||
'sum_bucket', 'min_bucket', 'max_bucket', 'avg_bucket'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
icon: 'fa fa-globe',
|
||||
title: 'shape field',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['terms']
|
||||
}
|
||||
])
|
||||
}
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
icon: 'fa fa-globe',
|
||||
title: 'shape field',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['terms']
|
||||
}
|
||||
])
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
id="regionMap"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.selectedLayer"
|
||||
ng-options="layer.name for layer in collections.vectorLayers"
|
||||
ng-options="layer.name for layer in vis.type.params.vectorLayers"
|
||||
ng-change="onLayerChange()"
|
||||
ng-init="vis.params.selectedLayer=collections.vectorLayers[0]"
|
||||
ng-init="vis.params.selectedLayer=vis.type.params.vectorLayers[0]"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -51,7 +51,7 @@
|
|||
id="colorSchema"
|
||||
class="kuiSelect kuiSideBarSelect"
|
||||
ng-model="vis.params.colorSchema"
|
||||
ng-options="mode for mode in collections.colorSchemas"
|
||||
ng-options="mode for mode in vis.type.params.colorSchemas"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -13,13 +13,11 @@ uiModules.get('kibana/region_map')
|
|||
template: regionMapVisParamsTemplate,
|
||||
link: function ($scope) {
|
||||
|
||||
$scope.collections = $scope.vis.type.editorConfig.collections;
|
||||
|
||||
$scope.onLayerChange = onLayerChange;
|
||||
serviceSettings.getFileLayers()
|
||||
.then(function (layersFromService) {
|
||||
|
||||
const newVectorLayers = $scope.collections.vectorLayers.slice();
|
||||
const newVectorLayers = $scope.vis.type.params.vectorLayers.slice();
|
||||
for (let i = 0; i < layersFromService.length; i += 1) {
|
||||
const layerFromService = layersFromService[i];
|
||||
const alreadyAdded = newVectorLayers.some((layer) =>_.eq(layerFromService, layer));
|
||||
|
@ -28,10 +26,10 @@ uiModules.get('kibana/region_map')
|
|||
}
|
||||
}
|
||||
|
||||
$scope.collections.vectorLayers = newVectorLayers;
|
||||
$scope.vis.type.params.vectorLayers = newVectorLayers;
|
||||
|
||||
if ($scope.collections.vectorLayers[0] && !$scope.vis.params.selectedLayer) {
|
||||
$scope.vis.params.selectedLayer = $scope.collections.vectorLayers[0];
|
||||
if ($scope.vis.type.params.vectorLayers[0] && !$scope.vis.params.selectedLayer) {
|
||||
$scope.vis.params.selectedLayer = $scope.vis.type.params.vectorLayers[0];
|
||||
onLayerChange();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,16 +15,16 @@ function VisSpyTableProvider(Notifier, $filter, $rootScope, config, Private) {
|
|||
link: function tableLinkFn($scope) {
|
||||
$rootScope.$watchMulti.call($scope, [
|
||||
'vis',
|
||||
'visData'
|
||||
'esResp'
|
||||
], function () {
|
||||
if (!$scope.vis || !$scope.visData) {
|
||||
if (!$scope.vis || !$scope.esResp) {
|
||||
$scope.table = null;
|
||||
} else {
|
||||
if (!$scope.spy.params.spyPerPage) {
|
||||
$scope.spy.params.spyPerPage = PER_PAGE_DEFAULT;
|
||||
}
|
||||
|
||||
$scope.table = tabifyAggResponse($scope.vis, $scope.searchSource.rawResponse, {
|
||||
$scope.table = tabifyAggResponse($scope.vis, $scope.esResp, {
|
||||
canSplit: false,
|
||||
asAggConfigResults: true,
|
||||
partialRows: true
|
||||
|
|
|
@ -29,10 +29,9 @@ describe('Integration', function () {
|
|||
$rootScope.vis = vis;
|
||||
$rootScope.esResponse = esResponse;
|
||||
$rootScope.uiState = require('fixtures/mock_ui_state');
|
||||
$el = $('<visualization vis="vis" vis-data="esResponse" ui-state="uiState">');
|
||||
$el = $('<visualize vis="vis" es-resp="esResponse" ui-state="uiState">');
|
||||
$compile($el)($rootScope);
|
||||
$rootScope.$apply();
|
||||
|
||||
}
|
||||
|
||||
function OneRangeVis(params) {
|
||||
|
@ -90,25 +89,20 @@ describe('Integration', function () {
|
|||
it('passes the table groups to the kbnAggTableGroup directive', function () {
|
||||
init(new OneRangeVis(), fixtures.oneRangeBucket);
|
||||
|
||||
$rootScope.$on('renderComplete', () => {
|
||||
const $atg = $el.find('kbn-agg-table-group').first();
|
||||
expect($atg.size()).to.be(1);
|
||||
expect($atg.attr('group')).to.be('tableGroups');
|
||||
expect($atg.isolateScope().group).to.be($atg.scope().tableGroups);
|
||||
});
|
||||
|
||||
const $atg = $el.find('kbn-agg-table-group').first();
|
||||
expect($atg.size()).to.be(1);
|
||||
expect($atg.attr('group')).to.be('tableGroups');
|
||||
expect($atg.isolateScope().group).to.be($atg.scope().tableGroups);
|
||||
});
|
||||
|
||||
it('displays an error if the search had no hits', function () {
|
||||
init(new OneRangeVis(), { hits: { total: 0, hits: [] } });
|
||||
|
||||
$rootScope.$on('renderComplete', () => {
|
||||
expect($el.find('kbn-agg-table-group').size()).to.be(0);
|
||||
expect($el.find('kbn-agg-table-group').size()).to.be(0);
|
||||
|
||||
const $err = $el.find('.table-vis-error');
|
||||
expect($err.size()).to.be(1);
|
||||
expect($err.text().trim()).to.be('No results found');
|
||||
});
|
||||
const $err = $el.find('.table-vis-error');
|
||||
expect($err.size()).to.be(1);
|
||||
expect($err.text().trim()).to.be('No results found');
|
||||
});
|
||||
|
||||
it('displays an error if the search hits, but didn\'t create any rows', function () {
|
||||
|
@ -127,12 +121,10 @@ describe('Integration', function () {
|
|||
|
||||
init(new ThreeTermVis(visParams), resp);
|
||||
|
||||
$rootScope.$on('renderComplete', () => {
|
||||
expect($el.find('kbn-agg-table-group').size()).to.be(0);
|
||||
expect($el.find('kbn-agg-table-group').size()).to.be(0);
|
||||
|
||||
const $err = $el.find('.table-vis-error');
|
||||
expect($err.size()).to.be(1);
|
||||
expect($err.text().trim()).to.be('No results found');
|
||||
});
|
||||
const $err = $el.find('.table-vis-error');
|
||||
expect($err.size()).to.be(1);
|
||||
expect($err.text().trim()).to.be('No results found');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -58,7 +58,6 @@ describe('Controller', function () {
|
|||
|
||||
$rootScope.vis = vis;
|
||||
$rootScope.uiState = new AppState({ uiState: {} }).makeStateful('uiState');
|
||||
$rootScope.renderComplete = () => {};
|
||||
$rootScope.newScope = function (scope) { $scope = scope; };
|
||||
|
||||
$el = $('<div>')
|
||||
|
|
|
@ -3,9 +3,9 @@ import 'plugins/table_vis/table_vis_controller';
|
|||
import 'plugins/table_vis/table_vis_params';
|
||||
import 'ui/agg_table';
|
||||
import 'ui/agg_table/agg_table_group';
|
||||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { TemplateVisTypeProvider } from 'ui/template_vis_type/template_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import tableVisTemplate from 'plugins/table_vis/table_vis.html';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
import image from './images/icon-table.svg';
|
||||
|
@ -22,7 +22,8 @@ VisTypesRegistryProvider.register(TableVisTypeProvider);
|
|||
|
||||
// define the TableVisType
|
||||
function TableVisTypeProvider(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const TemplateVisType = Private(TemplateVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
// define the TableVisController which is used in the template
|
||||
|
@ -30,14 +31,14 @@ function TableVisTypeProvider(Private) {
|
|||
|
||||
// return the visType object, which kibana will use to display and configure new
|
||||
// Vis object of this type.
|
||||
return VisFactory.createAngularVisualization({
|
||||
type: 'table',
|
||||
return new TemplateVisType({
|
||||
name: 'table',
|
||||
title: 'Data Table',
|
||||
image,
|
||||
description: 'Display values in a table',
|
||||
category: CATEGORY.DATA,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.DATA,
|
||||
template: tableVisTemplate,
|
||||
params: {
|
||||
defaults: {
|
||||
perPage: 10,
|
||||
showPartialRows: false,
|
||||
|
@ -49,36 +50,34 @@ function TableVisTypeProvider(Private) {
|
|||
showTotal: false,
|
||||
totalFunc: 'sum'
|
||||
},
|
||||
template: tableVisTemplate,
|
||||
},
|
||||
editorConfig: {
|
||||
optionsTemplate: '<table-vis-params></table-vis-params>',
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
aggFilter: '!geo_centroid',
|
||||
min: 1,
|
||||
defaults: [
|
||||
{ type: 'count', schema: 'metric' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'bucket',
|
||||
title: 'Split Rows'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Table'
|
||||
}
|
||||
])
|
||||
editor: '<table-vis-params></table-vis-params>'
|
||||
},
|
||||
implementsRenderComplete: true,
|
||||
hierarchicalData: function (vis) {
|
||||
return Boolean(vis.params.showPartialRows || vis.params.showMeticsAtAllLevels);
|
||||
}
|
||||
},
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Metric',
|
||||
aggFilter: '!geo_centroid',
|
||||
min: 1,
|
||||
defaults: [
|
||||
{ type: 'count', schema: 'metric' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'bucket',
|
||||
title: 'Split Rows'
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'split',
|
||||
title: 'Split Table'
|
||||
}
|
||||
])
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ module.controller('KbnTableVisController', function ($scope, $element, Private)
|
|||
return table.rows.length > 0;
|
||||
});
|
||||
|
||||
$scope.renderComplete();
|
||||
$element.trigger('renderComplete');
|
||||
}
|
||||
|
||||
$scope.hasSomeRows = hasSomeRows;
|
||||
|
|
|
@ -20,7 +20,6 @@ module.controller('KbnTagCloudController', function ($scope, $element, Private,
|
|||
const aggConfigResult = new AggConfigResult(aggs[0], false, event, event);
|
||||
clickHandler({ point: { aggConfigResult: aggConfigResult } });
|
||||
});
|
||||
|
||||
tagCloud.on('renderComplete', () => {
|
||||
|
||||
const truncatedMessage = containerNode.querySelector('.tagcloud-truncated-message');
|
||||
|
@ -34,9 +33,13 @@ module.controller('KbnTagCloudController', function ($scope, $element, Private,
|
|||
|
||||
const bucketName = containerNode.querySelector('.tagcloud-custom-label');
|
||||
bucketName.innerHTML = `${$scope.vis.aggs[0].makeLabel()} - ${$scope.vis.aggs[1].makeLabel()}`;
|
||||
|
||||
|
||||
truncatedMessage.style.display = truncated ? 'block' : 'none';
|
||||
|
||||
|
||||
const status = tagCloud.getStatus();
|
||||
|
||||
if (TagCloud.STATUS.COMPLETE === status) {
|
||||
incompleteMessage.style.display = 'none';
|
||||
} else if (TagCloud.STATUS.INCOMPLETE === status) {
|
||||
|
@ -44,7 +47,7 @@ module.controller('KbnTagCloudController', function ($scope, $element, Private,
|
|||
}
|
||||
|
||||
|
||||
$scope.renderComplete();
|
||||
$element.trigger('renderComplete');
|
||||
});
|
||||
|
||||
$scope.$watch('esResponse', async function (response) {
|
||||
|
@ -84,9 +87,14 @@ module.controller('KbnTagCloudController', function ($scope, $element, Private,
|
|||
|
||||
$scope.$watch('vis.params', (options) => tagCloud.setOptions(options));
|
||||
|
||||
$scope.$watch('resize', () => {
|
||||
$scope.$watch(getContainerSize, _.debounce(() => {
|
||||
tagCloud.resize();
|
||||
});
|
||||
}, 1000, { trailing: true }), true);
|
||||
|
||||
|
||||
function getContainerSize() {
|
||||
return { width: $element.width(), height: $element.height() };
|
||||
}
|
||||
|
||||
function getValue(metricsAgg, bucket) {
|
||||
let size = metricsAgg.getValue(bucket);
|
||||
|
|
|
@ -1,62 +1,59 @@
|
|||
import 'plugins/tagcloud/tag_cloud.less';
|
||||
import 'plugins/tagcloud/tag_cloud_controller';
|
||||
import 'plugins/tagcloud/tag_cloud_vis_params';
|
||||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import { TemplateVisTypeProvider } from 'ui/template_vis_type/template_vis_type';
|
||||
import { VisSchemasProvider } from 'ui/vis/schemas';
|
||||
import tagCloudTemplate from 'plugins/tagcloud/tag_cloud_controller.html';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
import image from './images/icon-tagcloud.svg';
|
||||
|
||||
VisTypesRegistryProvider.register(function TagCloudProvider(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const TemplateVisType = Private(TemplateVisTypeProvider);
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
|
||||
return VisFactory.createAngularVisualization({
|
||||
return new TemplateVisType({
|
||||
name: 'tagcloud',
|
||||
title: 'Tag Cloud',
|
||||
image,
|
||||
implementsRenderComplete: true,
|
||||
description: 'A group of words, sized according to their importance',
|
||||
category: CATEGORY.OTHER,
|
||||
visConfig: {
|
||||
category: VisType.CATEGORY.OTHER,
|
||||
template: tagCloudTemplate,
|
||||
params: {
|
||||
defaults: {
|
||||
scale: 'linear',
|
||||
orientation: 'single',
|
||||
minFontSize: 18,
|
||||
maxFontSize: 72
|
||||
},
|
||||
template: tagCloudTemplate,
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
orientations: ['single', 'right angled', 'multiple'],
|
||||
editor: '<tagcloud-vis-params></tagcloud-vis-params>'
|
||||
},
|
||||
responseHandler: 'none',
|
||||
editorConfig: {
|
||||
collections: {
|
||||
scales: ['linear', 'log', 'square root'],
|
||||
orientations: ['single', 'right angled', 'multiple'],
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Tag Size',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['!std_dev', '!percentiles', '!percentile_ranks', '!derivative'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
optionsTemplate: '<tagcloud-vis-params></tagcloud-vis-params>',
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Tag Size',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['!std_dev', '!percentiles', '!percentile_ranks', '!derivative'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
icon: 'fa fa-cloud',
|
||||
title: 'Tags',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['terms']
|
||||
}
|
||||
])
|
||||
}
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
icon: 'fa fa-cloud',
|
||||
title: 'Tags',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['terms']
|
||||
}
|
||||
])
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<div class="form-group">
|
||||
<div class="form-group">
|
||||
<label>Text Scale</label>
|
||||
<select class="form-control" ng-model="vis.params.scale" ng-options="mode for mode in config.collections.scales" ng-change="$parent.stageEditableVis()"></select>
|
||||
<select class="form-control" ng-model="vis.params.scale" ng-options="mode for mode in vis.type.params.scales"></select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Orientations</label>
|
||||
<select class="form-control" ng-model="vis.params.orientation" ng-options="mode for mode in config.collections.orientations" ng-change="$parent.stageEditableVis()"></select>
|
||||
<select class="form-control" ng-model="vis.params.orientation" ng-options="mode for mode in vis.type.params.orientations"></select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Font Size</label>
|
||||
|
|
|
@ -13,7 +13,6 @@ uiModules.get('kibana/table_vis')
|
|||
link: function ($scope, $element) {
|
||||
const sliderContainer = $element[0];
|
||||
const slider = sliderContainer.querySelector('.tag-cloud-fontsize-slider');
|
||||
$scope.config = $scope.vis.type.editorConfig;
|
||||
noUiSlider.create(slider, {
|
||||
start: [$scope.vis.params.minFontSize, $scope.vis.params.maxFontSize],
|
||||
connect: true,
|
||||
|
@ -26,9 +25,7 @@ uiModules.get('kibana/table_vis')
|
|||
const fontSize = slider.noUiSlider.get();
|
||||
$scope.vis.params.minFontSize = parseInt(fontSize[0], 10);
|
||||
$scope.vis.params.maxFontSize = parseInt(fontSize[1], 10);
|
||||
$scope.vis.updateState();
|
||||
$scope.$apply();
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
export default function (kibana) {
|
||||
|
||||
return new kibana.Plugin({
|
||||
uiExports: {
|
||||
visTypes: ['plugins/tile_map/tile_map_vis']
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"name": "tile_map",
|
||||
"version": "kibana"
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="30px" height="46px" viewBox="0 0 30 46" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 42 (36781) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>icon-tilemap</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Visualize" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Visualize-Create-New" transform="translate(-130.000000, -436.000000)" fill="#000000">
|
||||
<g id="maps" transform="translate(74.000000, 361.000000)">
|
||||
<g id="tile-map" transform="translate(2.000000, 45.000000)">
|
||||
<path d="M76.5,45.3333333 C76.5,41.1106771 73.1308594,37.6666667 69,37.6666667 C64.8691406,37.6666667 61.5,41.1106771 61.5,45.3333333 C61.5,49.5559896 64.8691406,53 69,53 C73.1308594,53 76.5,49.5559896 76.5,45.3333333 Z M84,45.3333333 C84,47.1601562 83.7949219,49.046875 83.0332031,50.6940104 L72.3691406,73.8736979 C71.7539062,75.1914062 70.40625,76 69,76 C67.59375,76 66.2460938,75.1914062 65.6601562,73.8736979 L54.9667969,50.6940104 C54.2050781,49.046875 54,47.1601562 54,45.3333333 C54,36.8580729 60.7089844,30 69,30 C77.2910156,30 84,36.8580729 84,45.3333333 Z" id="icon-tilemap"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.3 KiB |
|
@ -1,270 +0,0 @@
|
|||
import 'ui/vislib';
|
||||
import 'plugins/kbn_vislib_vis_types/controls/vislib_basic_options';
|
||||
import $ from 'jquery';
|
||||
import _ from 'lodash';
|
||||
import { KibanaMap } from './kibana_map';
|
||||
import { GeohashLayer } from './geohash_layer';
|
||||
import './lib/service_settings';
|
||||
import './styles/_tilemap.less';
|
||||
|
||||
|
||||
export function MapsVisualizationProvider(serviceSettings, Notifier, getAppState) {
|
||||
|
||||
const notify = new Notifier({ location: 'Coordinate Map' });
|
||||
|
||||
class MapsVisualization {
|
||||
|
||||
constructor(element, vis) {
|
||||
|
||||
this.vis = vis;
|
||||
this.$el = $(element);
|
||||
this._$container = this.$el;
|
||||
this._geohashLayer = null;
|
||||
this._kibanaMap = null;
|
||||
this._kibanaMapReady = this._makeKibanaMap();
|
||||
this._baseLayerDirty = true;
|
||||
this._currentParams = null;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._kibanaMap) {
|
||||
this._kibanaMap.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
async render(esResponse, status) {
|
||||
|
||||
return new Promise(async(resolve) => {
|
||||
|
||||
await this._kibanaMapReady;
|
||||
if (status.params || status.aggs) await this._updateParams();
|
||||
|
||||
if (esResponse && typeof esResponse.geohashGridAgg === 'undefined') {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
if (status.data) this._recreateGeohashLayer(esResponse);
|
||||
if (status.uiState) this._kibanaMap.useUiStateFromVisualization(this.vis);
|
||||
if (status.resize) this._kibanaMap.resize();
|
||||
this._doRenderComplete(resolve);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//**********************************************************************************************************
|
||||
async _makeKibanaMap() {
|
||||
|
||||
try {
|
||||
this._tmsService = await serviceSettings.getTMSService();
|
||||
this._tmsError = null;
|
||||
} catch (e) {
|
||||
this._tmsService = null;
|
||||
this._tmsError = e;
|
||||
notify.warning(e.message);
|
||||
}
|
||||
|
||||
if (this._kibanaMap) {
|
||||
this._kibanaMap.destroy();
|
||||
}
|
||||
const containerElement = $(this._$container)[0];
|
||||
const options = _.clone(this._getMinMaxZoom());
|
||||
const uiState = this.vis.getUiState();
|
||||
const zoomFromUiState = parseInt(uiState.get('mapZoom'));
|
||||
const centerFromUIState = uiState.get('mapCenter');
|
||||
options.zoom = !isNaN(zoomFromUiState) ? zoomFromUiState : this.vis.type.visConfig.defaults.mapZoom;
|
||||
options.center = centerFromUIState ? centerFromUIState : this.vis.type.visConfig.defaults.mapCenter;
|
||||
|
||||
this._kibanaMap = new KibanaMap(containerElement, options);
|
||||
this._kibanaMap.addDrawControl();
|
||||
this._kibanaMap.addFitControl();
|
||||
this._kibanaMap.addLegendControl();
|
||||
this._kibanaMap.persistUiStateForVisualization(this.vis);
|
||||
|
||||
let previousPrecision = this._kibanaMap.getAutoPrecision();
|
||||
let precisionChange = false;
|
||||
this._kibanaMap.on('zoomchange', () => {
|
||||
precisionChange = (previousPrecision !== this._kibanaMap.getAutoPrecision());
|
||||
previousPrecision = this._kibanaMap.getAutoPrecision();
|
||||
this.vis.aggs[1].params.precision = previousPrecision;
|
||||
});
|
||||
this._kibanaMap.on('zoomend', () => {
|
||||
|
||||
const isAutoPrecision = _.get(this._chartData, 'geohashGridAgg.params.autoPrecision', true);
|
||||
if (!isAutoPrecision) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (precisionChange) {
|
||||
this.vis.updateState();
|
||||
} else {
|
||||
this._recreateGeohashLayer(this._chartData);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
this._kibanaMap.on('drawCreated:rectangle', event => {
|
||||
this.addSpatialFilter(_.get(this._chartData, 'geohashGridAgg'), 'geo_bounding_box', event.bounds);
|
||||
});
|
||||
this._kibanaMap.on('drawCreated:polygon', event => {
|
||||
this.addSpatialFilter(_.get(this._chartData, 'geohashGridAgg'), 'geo_polygon', { points: event.points });
|
||||
});
|
||||
this._kibanaMap.on('baseLayer:loaded', () => {
|
||||
this._baseLayerDirty = false;
|
||||
});
|
||||
this._kibanaMap.on('baseLayer:loading', () => {
|
||||
this._baseLayerDirty = true;
|
||||
});
|
||||
}
|
||||
|
||||
_getMinMaxZoom() {
|
||||
const mapParams = this._getMapsParams();
|
||||
if (this._tmsError) {
|
||||
return serviceSettings.getFallbackZoomSettings(mapParams.wms.enabled);
|
||||
} else {
|
||||
return this._tmsService.getMinMaxZoom(mapParams.wms.enabled);
|
||||
}
|
||||
}
|
||||
|
||||
_recreateGeohashLayer(esResponse) {
|
||||
|
||||
if (esResponse === this._chartData) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._chartData = esResponse;
|
||||
|
||||
if (this._geohashLayer) {
|
||||
this._kibanaMap.removeLayer(this._geohashLayer);
|
||||
}
|
||||
if (!this._chartData || !this._chartData.geoJson) {
|
||||
return;
|
||||
}
|
||||
|
||||
const geohashOptions = this._getGeohashOptions();
|
||||
this._geohashLayer = new GeohashLayer(this._chartData.geoJson, geohashOptions, this._kibanaMap.getZoomLevel(), this._kibanaMap);
|
||||
this._kibanaMap.addLayer(this._geohashLayer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* called on options change (vis.params change)
|
||||
*/
|
||||
async _updateParams() {
|
||||
|
||||
const mapParams = this._getMapsParams();
|
||||
if (_.eq(this._currentParams, mapParams)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._currentParams = _.cloneDeep(mapParams);
|
||||
const { minZoom, maxZoom } = this._getMinMaxZoom();
|
||||
|
||||
if (mapParams.wms.enabled) {
|
||||
//Switch to WMS
|
||||
if (maxZoom > this._kibanaMap.getMaxZoomLevel()) {
|
||||
//need to recreate the map with less restrictive zoom
|
||||
this._geohashLayer = null;
|
||||
this._kibanaMapReady = this._makeKibanaMap();
|
||||
await this._kibanaMapReady;
|
||||
}
|
||||
|
||||
this._kibanaMap.setBaseLayer({
|
||||
baseLayerType: 'wms',
|
||||
options: {
|
||||
minZoom: minZoom,
|
||||
maxZoom: maxZoom,
|
||||
url: mapParams.wms.url,
|
||||
...mapParams.wms.options
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
//switch to regular
|
||||
if (maxZoom < this._kibanaMap.getMaxZoomLevel()) {
|
||||
//need to recreate the map with more restrictive zoom level
|
||||
this._geohashLayer = null;
|
||||
this._kibanaMapReady = this._makeKibanaMap();
|
||||
await this._kibanaMapReady;
|
||||
|
||||
if (this._kibanaMap.getZoomLevel() > maxZoom) {
|
||||
this._kibanaMap.setZoomLevel(maxZoom);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._tmsError) {
|
||||
const url = this._tmsService.getUrl();
|
||||
const options = this._tmsService.getTMSOptions();
|
||||
this._kibanaMap.setBaseLayer({
|
||||
baseLayerType: 'tms',
|
||||
options: { url, ...options }
|
||||
});
|
||||
}
|
||||
}
|
||||
const geohashOptions = this._getGeohashOptions();
|
||||
if (!this._geohashLayer || !this._geohashLayer.isReusable(geohashOptions)) {
|
||||
this._recreateGeohashLayer(this._chartData);
|
||||
}
|
||||
this._kibanaMap.setLegendPosition(mapParams.legendPosition);
|
||||
this._kibanaMap.setDesaturateBaseLayer(mapParams.isDesaturated);
|
||||
this._kibanaMap.setShowTooltip(mapParams.addTooltip);
|
||||
this._kibanaMap.useUiStateFromVisualization(this.vis);
|
||||
|
||||
}
|
||||
|
||||
_getMapsParams() {
|
||||
return _.assign(
|
||||
{},
|
||||
this.vis.type.visConfig.defaults,
|
||||
{ type: this.vis.type.name },
|
||||
this.vis.params
|
||||
);
|
||||
}
|
||||
|
||||
_getGeohashOptions() {
|
||||
const newParams = this._getMapsParams();
|
||||
return {
|
||||
valueFormatter: this._chartData ? this._chartData.valueFormatter : null,
|
||||
tooltipFormatter: this._chartData ? this._chartData.tooltipFormatter : null,
|
||||
mapType: newParams.mapType,
|
||||
heatmap: {
|
||||
heatBlur: newParams.heatBlur,
|
||||
heatMaxZoom: newParams.heatMaxZoom,
|
||||
heatMinOpacity: newParams.heatMinOpacity,
|
||||
heatRadius: newParams.heatRadius
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_doRenderComplete(resolve) {
|
||||
if (this._baseLayerDirty) {//as long as the baselayer is dirty, we cannot fire the render complete event
|
||||
setTimeout(() => {
|
||||
this._doRenderComplete(resolve);
|
||||
}, 10);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
addSpatialFilter(agg, filterName, filterData) {
|
||||
if (!agg) {
|
||||
return;
|
||||
}
|
||||
|
||||
const indexPatternName = agg.vis.indexPattern.id;
|
||||
const field = agg.fieldName();
|
||||
const filter = { meta: { negate: false, index: indexPatternName } };
|
||||
filter[filterName] = { ignore_unmapped: true };
|
||||
filter[filterName][field] = filterData;
|
||||
getAppState().filters.push(filter);
|
||||
this.vis.updateState();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return MapsVisualization;
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
import { supports } from 'ui/utils/supports';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { MapsVisualizationProvider } from './maps_visualization';
|
||||
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
|
||||
import { AggResponseGeoJsonProvider } from 'ui/agg_response/geo_json/geo_json';
|
||||
import tileMapTemplate from './editors/tile_map.html';
|
||||
import image from './images/icon-tilemap.svg';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
|
||||
|
||||
VisTypesRegistryProvider.register(function TileMapVisType(Private, getAppState, courier, config) {
|
||||
|
||||
const Schemas = Private(VisSchemasProvider);
|
||||
const geoJsonConverter = Private(AggResponseGeoJsonProvider);
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const MapsVisualization = Private(MapsVisualizationProvider);
|
||||
|
||||
|
||||
return VisFactory.createBaseVisualization({
|
||||
name: 'tile_map',
|
||||
title: 'Coordinate Map',
|
||||
image,
|
||||
description: 'Plot latitude and longitude coordinates on a map',
|
||||
category: CATEGORY.MAP,
|
||||
visConfig: {
|
||||
canDesaturate: true,
|
||||
defaults: {
|
||||
mapType: 'Scaled Circle Markers',
|
||||
isDesaturated: true,
|
||||
addTooltip: true,
|
||||
heatMaxZoom: 0,
|
||||
heatMinOpacity: 0.1,
|
||||
heatRadius: 25,
|
||||
heatBlur: 15,
|
||||
legendPosition: 'bottomright',
|
||||
mapZoom: 2,
|
||||
mapCenter: [0, 0],
|
||||
wms: config.get('visualization:tileMap:WMSdefaults')
|
||||
}
|
||||
},
|
||||
responseConverter: geoJsonConverter,
|
||||
responseHandler: 'basic',
|
||||
implementsRenderComplete: true,
|
||||
visualization: MapsVisualization,
|
||||
editorConfig: {
|
||||
collections: {
|
||||
legendPositions: [{
|
||||
value: 'bottomleft',
|
||||
text: 'bottom left',
|
||||
}, {
|
||||
value: 'bottomright',
|
||||
text: 'bottom right',
|
||||
}, {
|
||||
value: 'topleft',
|
||||
text: 'top left',
|
||||
}, {
|
||||
value: 'topright',
|
||||
text: 'top right',
|
||||
}],
|
||||
mapTypes: [
|
||||
'Scaled Circle Markers',
|
||||
'Shaded Circle Markers',
|
||||
'Shaded Geohash Grid',
|
||||
'Heatmap'
|
||||
],
|
||||
canDesaturate: !!supports.cssFilters
|
||||
},
|
||||
optionsTemplate: tileMapTemplate,
|
||||
schemas: new Schemas([
|
||||
{
|
||||
group: 'metrics',
|
||||
name: 'metric',
|
||||
title: 'Value',
|
||||
min: 1,
|
||||
max: 1,
|
||||
aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality', 'top_hits'],
|
||||
defaults: [
|
||||
{ schema: 'metric', type: 'count' }
|
||||
]
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
name: 'segment',
|
||||
title: 'Geo Coordinates',
|
||||
aggFilter: 'geohash_grid',
|
||||
min: 1,
|
||||
max: 1
|
||||
}
|
||||
])
|
||||
}
|
||||
});
|
||||
|
||||
});
|
|
@ -97,7 +97,7 @@ export default function timechartFn(Private, config, $rootScope, timefilter, $co
|
|||
timefilter.time.from = moment(ranges.xaxis.from);
|
||||
timefilter.time.to = moment(ranges.xaxis.to);
|
||||
timefilter.time.mode = 'absolute';
|
||||
$scope.$apply();
|
||||
$scope.search();
|
||||
});
|
||||
|
||||
$elem.on('mouseleave', function () {
|
||||
|
|
|
@ -1,51 +1,35 @@
|
|||
import { VisFactoryProvider } from 'ui/vis/vis_factory';
|
||||
import { CATEGORY } from 'ui/vis/vis_category';
|
||||
import { VisVisTypeProvider } from 'ui/vis/vis_type';
|
||||
import image from '../images/icon-timelion.svg';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
import { TimelionRequestHandlerProvider } from './timelion_request_handler';
|
||||
import { TemplateVisTypeProvider } from 'ui/template_vis_type';
|
||||
import template from 'plugins/timelion/vis/timelion_vis.html';
|
||||
import editorTemplate from 'plugins/timelion/vis/timelion_vis_params.html';
|
||||
import 'plugins/timelion/vis/timelion_vis_controller';
|
||||
import 'plugins/timelion/vis/timelion_vis_params_controller';
|
||||
import 'plugins/timelion/vis/timelion_vis.less';
|
||||
|
||||
define(function (require) {
|
||||
// we also need to load the controller and directive used by the template
|
||||
require('plugins/timelion/vis/timelion_vis_controller');
|
||||
require('plugins/timelion/directives/timelion_expression_input');
|
||||
// export the provider so that the visType can be required with Private()
|
||||
export default function TimelionVisProvider(Private) {
|
||||
const VisType = Private(VisVisTypeProvider);
|
||||
const TemplateVisType = Private(TemplateVisTypeProvider);
|
||||
|
||||
// Stylin
|
||||
require('plugins/timelion/vis/timelion_vis.less');
|
||||
// return the visType object, which kibana will use to display and configure new
|
||||
// Vis object of this type.
|
||||
return new TemplateVisType({
|
||||
name: 'timelion',
|
||||
title: 'Timelion',
|
||||
image,
|
||||
description: 'Build time-series using functional expressions',
|
||||
category: VisType.CATEGORY.TIME,
|
||||
template,
|
||||
params: {
|
||||
editor: editorTemplate,
|
||||
},
|
||||
requiresSearch: false,
|
||||
requiresTimePicker: true,
|
||||
implementsRenderComplete: true,
|
||||
});
|
||||
}
|
||||
|
||||
// register the provider with the visTypes registry so that other know it exists
|
||||
VisTypesRegistryProvider.register(TimelionVisProvider);
|
||||
|
||||
|
||||
function TimelionVisProvider(Private) {
|
||||
const VisFactory = Private(VisFactoryProvider);
|
||||
const timelionRequestHandler = Private(TimelionRequestHandlerProvider);
|
||||
|
||||
// return the visType object, which kibana will use to display and configure new
|
||||
// Vis object of this type.
|
||||
return VisFactory.createAngularVisualization({
|
||||
name: 'timelion',
|
||||
title: 'Timelion',
|
||||
image,
|
||||
description: 'Build time-series using functional expressions',
|
||||
category: CATEGORY.TIME,
|
||||
visConfig: {
|
||||
defaults: {
|
||||
expression: '.es(*)',
|
||||
interval: 'auto'
|
||||
},
|
||||
template: require('plugins/timelion/vis/timelion_vis.html'),
|
||||
},
|
||||
editorConfig: {
|
||||
optionsTemplate: require('plugins/timelion/vis/timelion_vis_params.html')
|
||||
},
|
||||
requestHandler: timelionRequestHandler.handler,
|
||||
responseHandler: 'none',
|
||||
options: {
|
||||
showIndexSelection: false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// export the provider so that the visType can be required with Private()
|
||||
return TimelionVisProvider;
|
||||
});
|
||||
// register the provider with the visTypes registry so that other know it exists
|
||||
VisTypesRegistryProvider.register(TimelionVisProvider);
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
import _ from 'lodash';
|
||||
import { dashboardContextProvider } from 'plugins/kibana/dashboard/dashboard_context';
|
||||
|
||||
const TimelionRequestHandlerProvider = function (Private, Notifier, $http, $rootScope, timefilter) {
|
||||
const timezone = Private(require('plugins/timelion/services/timezone'))();
|
||||
const dashboardContext = Private(dashboardContextProvider);
|
||||
|
||||
const notify = new Notifier({
|
||||
location: 'Timelion'
|
||||
});
|
||||
|
||||
return {
|
||||
name: 'timelion',
|
||||
handler: function (vis /*, appState, uiState */) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('[timelion] get');
|
||||
|
||||
const expression = vis.params.expression;
|
||||
if (!expression) return;
|
||||
|
||||
$http.post('../api/timelion/run', {
|
||||
sheet: [expression],
|
||||
extended: {
|
||||
es: {
|
||||
filter: dashboardContext()
|
||||
}
|
||||
},
|
||||
time: _.extend(timefilter.time, {
|
||||
interval: vis.params.interval,
|
||||
timezone: timezone
|
||||
}),
|
||||
})
|
||||
.success(function (resp) {
|
||||
resolve(resp);
|
||||
})
|
||||
.error(function (resp) {
|
||||
const err = new Error(resp.message);
|
||||
err.stack = resp.stack;
|
||||
notify.error(err);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { TimelionRequestHandlerProvider };
|
|
@ -1,3 +1,3 @@
|
|||
<div ng-controller="TimelionVisController" class="timelion-vis">
|
||||
<div chart="esResponse.sheet[0]" interval="vis.params.interval"></div>
|
||||
<div chart="sheet[0]" interval="vis.params.interval"></div>
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,69 @@
|
|||
define(function (require) {
|
||||
require('plugins/timelion/directives/chart/chart');
|
||||
require('plugins/timelion/directives/timelion_interval/timelion_interval');
|
||||
require('ui/state_management/app_state');
|
||||
import _ from 'lodash';
|
||||
import { FilterBarQueryFilterProvider } from 'ui/filter_bar/query_filter';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import timezoneProvider from 'plugins/timelion/services/timezone';
|
||||
import { dashboardContextProvider } from 'plugins/kibana/dashboard/dashboard_context';
|
||||
import 'plugins/timelion/directives/chart/chart';
|
||||
import 'plugins/timelion/directives/timelion_interval/timelion_interval';
|
||||
import 'ui/state_management/app_state';
|
||||
|
||||
const module = require('ui/modules').get('kibana/timelion_vis', ['kibana']);
|
||||
module.controller('TimelionVisController', function ($scope) {
|
||||
const module = uiModules.get('kibana/timelion_vis', ['kibana']);
|
||||
|
||||
$scope.$on('renderComplete', event => {
|
||||
event.stopPropagation();
|
||||
$scope.renderComplete();
|
||||
module.controller('TimelionVisController', function ($scope, $element, Private, Notifier, $http, $rootScope, timefilter) {
|
||||
const queryFilter = Private(FilterBarQueryFilterProvider);
|
||||
const timezone = Private(timezoneProvider)();
|
||||
const dashboardContext = Private(dashboardContextProvider);
|
||||
|
||||
const notify = new Notifier({
|
||||
location: 'Timelion'
|
||||
});
|
||||
|
||||
$scope.search = function run() {
|
||||
const expression = $scope.vis.params.expression;
|
||||
if (!expression) return;
|
||||
|
||||
$http.post('../api/timelion/run', {
|
||||
sheet: [expression],
|
||||
extended: {
|
||||
es: {
|
||||
filter: dashboardContext()
|
||||
}
|
||||
},
|
||||
time: _.extend(timefilter.time, {
|
||||
interval: $scope.vis.params.interval,
|
||||
timezone: timezone
|
||||
}),
|
||||
})
|
||||
// data, status, headers, config
|
||||
.success(function (resp) {
|
||||
$scope.sheet = resp.sheet;
|
||||
})
|
||||
.error(function (resp) {
|
||||
$scope.sheet = [];
|
||||
const err = new Error(resp.message);
|
||||
err.stack = resp.stack;
|
||||
notify.error(err);
|
||||
});
|
||||
};
|
||||
|
||||
// This is bad, there should be a single event that triggers a refresh of data.
|
||||
|
||||
// When the expression updates
|
||||
$scope.$watchMulti(['vis.params.expression', 'vis.params.interval'], $scope.search);
|
||||
|
||||
// When the time filter changes
|
||||
$scope.$listen(timefilter, 'fetch', $scope.search);
|
||||
|
||||
// When a filter is added to the filter bar?
|
||||
$scope.$listen(queryFilter, 'fetch', $scope.search);
|
||||
|
||||
// When auto refresh happens
|
||||
$scope.$on('courier:searchRefresh', $scope.search);
|
||||
|
||||
$scope.$on('fetch', $scope.search);
|
||||
|
||||
$scope.$on('renderComplete', event => {
|
||||
event.stopPropagation();
|
||||
$element.trigger('renderComplete');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div>
|
||||
<div ng-controller="TimelionVisParamsController">
|
||||
<div class="form-group">
|
||||
<label>Interval</label>
|
||||
<div class="form-group">
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import { uiModules } from 'ui/modules';
|
||||
import 'plugins/timelion/directives/timelion_expression_input';
|
||||
|
||||
const module = uiModules.get('kibana/timelion_vis', ['kibana']);
|
||||
module.controller('TimelionVisParamsController', function ($scope, $rootScope) {
|
||||
$scope.vis.params.expression = $scope.vis.params.expression || '.es(*)';
|
||||
$scope.vis.params.interval = $scope.vis.params.interval || '1m';
|
||||
|
||||
$scope.search = function () {
|
||||
$rootScope.$broadcast('courier:searchRefresh');
|
||||
};
|
||||
});
|
|
@ -3,7 +3,6 @@ import { VisProvider } from 'ui/vis';
|
|||
import { AggTypesIndexProvider } from 'ui/agg_types/index';
|
||||
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
|
||||
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
|
||||
import { VisAggConfigProvider } from 'ui/vis/agg_config';
|
||||
|
||||
// eslint-disable-next-line kibana-custom/no-default-export
|
||||
export default function AggParamWriterHelper(Private) {
|
||||
|
@ -11,7 +10,6 @@ export default function AggParamWriterHelper(Private) {
|
|||
const aggTypes = Private(AggTypesIndexProvider);
|
||||
const visTypes = Private(VisTypesRegistryProvider);
|
||||
const stubbedLogstashIndexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
|
||||
const AggConfig = Private(VisAggConfigProvider);
|
||||
|
||||
/**
|
||||
* Helper object for writing aggParams. Specify an aggType and it will find a vis & schema, and
|
||||
|
@ -68,7 +66,7 @@ export default function AggParamWriterHelper(Private) {
|
|||
}
|
||||
|
||||
self.vis = new Vis(self.indexPattern, {
|
||||
type: self.visType.name
|
||||
type: self.visType
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -81,26 +79,17 @@ export default function AggParamWriterHelper(Private) {
|
|||
if (self.aggType.type === 'metrics') {
|
||||
paramValues.field = _.sample(self.indexPattern.fields.byType.number);
|
||||
} else {
|
||||
const type = self.aggType.params.byName.field.filterFieldTypes || 'string';
|
||||
let field;
|
||||
do {
|
||||
field = _.sample(self.indexPattern.fields.byType[type]);
|
||||
} while (!field.aggregatable);
|
||||
paramValues.field = field.name;
|
||||
paramValues.field = _.sample(self.indexPattern.fields.byType.string);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const agg = new AggConfig(self.vis, {
|
||||
id: 1,
|
||||
schema: self.visAggSchema.name,
|
||||
type: self.aggType.name,
|
||||
params: paramValues
|
||||
});
|
||||
|
||||
self.vis.setState({
|
||||
type: self.vis.type.name,
|
||||
aggs: [agg.toJSON()]
|
||||
aggs: [{
|
||||
type: self.aggType,
|
||||
schema: self.visAggSchema,
|
||||
params: paramValues
|
||||
}]
|
||||
});
|
||||
|
||||
const aggConfig = _.find(self.vis.aggs, function (aggConfig) {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue