mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Data table] Add telemetry for table vis split mode (#88604)
* Add telemetry for table vis * Update telemetry schema * Add unit tests * Update license * Use soClient instead of esClient, update tests Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
2ff523556d
commit
72ef3b105a
30 changed files with 398 additions and 56 deletions
|
@ -5247,6 +5247,36 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"vis_type_table": {
|
||||||
|
"properties": {
|
||||||
|
"total": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
|
"total_split": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
|
"split_columns": {
|
||||||
|
"properties": {
|
||||||
|
"total": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "long"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"split_rows": {
|
||||||
|
"properties": {
|
||||||
|
"total": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"type": "long"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"vis_type_vega": {
|
"vis_type_vega": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"vega_lib_specs_total": {
|
"vega_lib_specs_total": {
|
||||||
|
|
9
src/plugins/vis_type_table/common/index.ts
Normal file
9
src/plugins/vis_type_table/common/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* and the Server Side Public License, v 1; you may not use this file except in
|
||||||
|
* compliance with, at your election, the Elastic License or the Server Side
|
||||||
|
* Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export * from './types';
|
28
src/plugins/vis_type_table/common/types.ts
Normal file
28
src/plugins/vis_type_table/common/types.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* and the Server Side Public License, v 1; you may not use this file except in
|
||||||
|
* compliance with, at your election, the Elastic License or the Server Side
|
||||||
|
* Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const VIS_TYPE_TABLE = 'table';
|
||||||
|
|
||||||
|
export enum AggTypes {
|
||||||
|
SUM = 'sum',
|
||||||
|
AVG = 'avg',
|
||||||
|
MIN = 'min',
|
||||||
|
MAX = 'max',
|
||||||
|
COUNT = 'count',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TableVisParams {
|
||||||
|
perPage: number | '';
|
||||||
|
showPartialRows: boolean;
|
||||||
|
showMetricsAtAllLevels: boolean;
|
||||||
|
showToolbar: boolean;
|
||||||
|
showTotal: boolean;
|
||||||
|
totalFunc: AggTypes;
|
||||||
|
percentageCol: string;
|
||||||
|
row?: boolean;
|
||||||
|
}
|
|
@ -11,4 +11,5 @@ module.exports = {
|
||||||
rootDir: '../../..',
|
rootDir: '../../..',
|
||||||
roots: ['<rootDir>/src/plugins/vis_type_table'],
|
roots: ['<rootDir>/src/plugins/vis_type_table'],
|
||||||
testRunner: 'jasmine2',
|
testRunner: 'jasmine2',
|
||||||
|
collectCoverageFrom: ['<rootDir>/src/plugins/vis_type_table/**/*.{js,ts,tsx}'],
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {
|
||||||
NumberInputOption,
|
NumberInputOption,
|
||||||
VisOptionsProps,
|
VisOptionsProps,
|
||||||
} from '../../../vis_default_editor/public';
|
} from '../../../vis_default_editor/public';
|
||||||
import { TableVisParams } from '../types';
|
import { TableVisParams } from '../../common';
|
||||||
import { totalAggregations } from './utils';
|
import { totalAggregations } from './utils';
|
||||||
|
|
||||||
const { tabifyGetColumns } = search;
|
const { tabifyGetColumns } = search;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import React, { lazy, Suspense } from 'react';
|
import React, { lazy, Suspense } from 'react';
|
||||||
import { EuiLoadingSpinner } from '@elastic/eui';
|
import { EuiLoadingSpinner } from '@elastic/eui';
|
||||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||||
import { TableVisParams } from '../types';
|
import { TableVisParams } from '../../common';
|
||||||
|
|
||||||
const TableOptionsComponent = lazy(() => import('./table_vis_options'));
|
const TableOptionsComponent = lazy(() => import('./table_vis_options'));
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { AggTypes } from '../types';
|
import { AggTypes } from '../../common';
|
||||||
|
|
||||||
const totalAggregations = [
|
const totalAggregations = [
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n';
|
||||||
import { ExpressionFunctionDefinition, Datatable, Render } from 'src/plugins/expressions/public';
|
import { ExpressionFunctionDefinition, Datatable, Render } from 'src/plugins/expressions/public';
|
||||||
import { tableVisLegacyResponseHandler, TableContext } from './table_vis_legacy_response_handler';
|
import { tableVisLegacyResponseHandler, TableContext } from './table_vis_legacy_response_handler';
|
||||||
import { TableVisConfig } from '../types';
|
import { TableVisConfig } from '../types';
|
||||||
|
import { VIS_TYPE_TABLE } from '../../common';
|
||||||
|
|
||||||
export type Input = Datatable;
|
export type Input = Datatable;
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ interface Arguments {
|
||||||
|
|
||||||
export interface TableVisRenderValue {
|
export interface TableVisRenderValue {
|
||||||
visData: TableContext;
|
visData: TableContext;
|
||||||
visType: 'table';
|
visType: typeof VIS_TYPE_TABLE;
|
||||||
visConfig: TableVisConfig;
|
visConfig: TableVisConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ export const createTableVisLegacyFn = (): TableExpressionFunctionDefinition => (
|
||||||
as: 'table_vis',
|
as: 'table_vis',
|
||||||
value: {
|
value: {
|
||||||
visData: convertedData,
|
visData: convertedData,
|
||||||
visType: 'table',
|
visType: VIS_TYPE_TABLE,
|
||||||
visConfig,
|
visConfig,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,11 +12,11 @@ import { BaseVisTypeOptions } from '../../../visualizations/public';
|
||||||
|
|
||||||
import { TableOptions } from '../components/table_vis_options_lazy';
|
import { TableOptions } from '../components/table_vis_options_lazy';
|
||||||
import { VIS_EVENT_TO_TRIGGER } from '../../../visualizations/public';
|
import { VIS_EVENT_TO_TRIGGER } from '../../../visualizations/public';
|
||||||
|
import { TableVisParams, VIS_TYPE_TABLE } from '../../common';
|
||||||
import { toExpressionAst } from '../to_ast';
|
import { toExpressionAst } from '../to_ast';
|
||||||
import { TableVisParams } from '../types';
|
|
||||||
|
|
||||||
export const tableVisLegacyTypeDefinition: BaseVisTypeOptions<TableVisParams> = {
|
export const tableVisLegacyTypeDefinition: BaseVisTypeOptions<TableVisParams> = {
|
||||||
name: 'table',
|
name: VIS_TYPE_TABLE,
|
||||||
title: i18n.translate('visTypeTable.tableVisTitle', {
|
title: i18n.translate('visTypeTable.tableVisTitle', {
|
||||||
defaultMessage: 'Data table',
|
defaultMessage: 'Data table',
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n';
|
||||||
import { tableVisResponseHandler, TableContext } from './table_vis_response_handler';
|
import { tableVisResponseHandler, TableContext } from './table_vis_response_handler';
|
||||||
import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressions/public';
|
import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressions/public';
|
||||||
import { TableVisConfig } from './types';
|
import { TableVisConfig } from './types';
|
||||||
|
import { VIS_TYPE_TABLE } from '../common';
|
||||||
|
|
||||||
export type Input = Datatable;
|
export type Input = Datatable;
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ interface Arguments {
|
||||||
|
|
||||||
export interface TableVisRenderValue {
|
export interface TableVisRenderValue {
|
||||||
visData: TableContext;
|
visData: TableContext;
|
||||||
visType: 'table';
|
visType: typeof VIS_TYPE_TABLE;
|
||||||
visConfig: TableVisConfig;
|
visConfig: TableVisConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ export const createTableVisFn = (): TableExpressionFunctionDefinition => ({
|
||||||
as: 'table_vis',
|
as: 'table_vis',
|
||||||
value: {
|
value: {
|
||||||
visData: convertedData,
|
visData: convertedData,
|
||||||
visType: 'table',
|
visType: VIS_TYPE_TABLE,
|
||||||
visConfig,
|
visConfig,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,13 +10,13 @@ import { i18n } from '@kbn/i18n';
|
||||||
import { AggGroupNames } from '../../data/public';
|
import { AggGroupNames } from '../../data/public';
|
||||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||||
|
|
||||||
|
import { TableVisParams, VIS_TYPE_TABLE } from '../common';
|
||||||
import { TableOptions } from './components/table_vis_options_lazy';
|
import { TableOptions } from './components/table_vis_options_lazy';
|
||||||
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||||
import { toExpressionAst } from './to_ast';
|
import { toExpressionAst } from './to_ast';
|
||||||
import { TableVisParams } from './types';
|
|
||||||
|
|
||||||
export const tableVisTypeDefinition: BaseVisTypeOptions<TableVisParams> = {
|
export const tableVisTypeDefinition: BaseVisTypeOptions<TableVisParams> = {
|
||||||
name: 'table',
|
name: VIS_TYPE_TABLE,
|
||||||
title: i18n.translate('visTypeTable.tableVisTitle', {
|
title: i18n.translate('visTypeTable.tableVisTitle', {
|
||||||
defaultMessage: 'Data table',
|
defaultMessage: 'Data table',
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import { Vis } from 'src/plugins/visualizations/public';
|
import { Vis } from 'src/plugins/visualizations/public';
|
||||||
import { toExpressionAst } from './to_ast';
|
import { toExpressionAst } from './to_ast';
|
||||||
import { AggTypes, TableVisParams } from './types';
|
import { AggTypes, TableVisParams } from '../common';
|
||||||
|
|
||||||
const mockSchemas = {
|
const mockSchemas = {
|
||||||
metric: [{ accessor: 1, format: { id: 'number' }, params: {}, label: 'Count', aggType: 'count' }],
|
metric: [{ accessor: 1, format: { id: 'number' }, params: {}, label: 'Count', aggType: 'count' }],
|
||||||
|
|
|
@ -12,8 +12,9 @@ import {
|
||||||
} from '../../data/public';
|
} from '../../data/public';
|
||||||
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
||||||
import { getVisSchemas, Vis, BuildPipelineParams } from '../../visualizations/public';
|
import { getVisSchemas, Vis, BuildPipelineParams } from '../../visualizations/public';
|
||||||
|
import { TableVisParams } from '../common';
|
||||||
import { TableExpressionFunctionDefinition } from './table_vis_fn';
|
import { TableExpressionFunctionDefinition } from './table_vis_fn';
|
||||||
import { TableVisConfig, TableVisParams } from './types';
|
import { TableVisConfig } from './types';
|
||||||
|
|
||||||
const buildTableVisConfig = (
|
const buildTableVisConfig = (
|
||||||
schemas: ReturnType<typeof getVisSchemas>,
|
schemas: ReturnType<typeof getVisSchemas>,
|
||||||
|
|
|
@ -8,14 +8,7 @@
|
||||||
|
|
||||||
import { IFieldFormat } from 'src/plugins/data/public';
|
import { IFieldFormat } from 'src/plugins/data/public';
|
||||||
import { SchemaConfig } from 'src/plugins/visualizations/public';
|
import { SchemaConfig } from 'src/plugins/visualizations/public';
|
||||||
|
import { TableVisParams } from '../common';
|
||||||
export enum AggTypes {
|
|
||||||
SUM = 'sum',
|
|
||||||
AVG = 'avg',
|
|
||||||
MIN = 'min',
|
|
||||||
MAX = 'max',
|
|
||||||
COUNT = 'count',
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Dimensions {
|
export interface Dimensions {
|
||||||
buckets: SchemaConfig[];
|
buckets: SchemaConfig[];
|
||||||
|
@ -44,16 +37,6 @@ export interface TableVisUseUiStateProps {
|
||||||
setColumnsWidth: (column: ColumnWidthData) => void;
|
setColumnsWidth: (column: ColumnWidthData) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableVisParams {
|
|
||||||
perPage: number | '';
|
|
||||||
showPartialRows: boolean;
|
|
||||||
showMetricsAtAllLevels: boolean;
|
|
||||||
showToolbar: boolean;
|
|
||||||
showTotal: boolean;
|
|
||||||
totalFunc: AggTypes;
|
|
||||||
percentageCol: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TableVisConfig extends TableVisParams {
|
export interface TableVisConfig extends TableVisParams {
|
||||||
title: string;
|
title: string;
|
||||||
dimensions: Dimensions;
|
dimensions: Dimensions;
|
||||||
|
|
|
@ -9,8 +9,9 @@
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { chain, findIndex } from 'lodash';
|
import { chain, findIndex } from 'lodash';
|
||||||
|
|
||||||
|
import { AggTypes } from '../../../common';
|
||||||
import { Table } from '../../table_vis_response_handler';
|
import { Table } from '../../table_vis_response_handler';
|
||||||
import { FormattedColumn, TableVisConfig, AggTypes } from '../../types';
|
import { FormattedColumn, TableVisConfig } from '../../types';
|
||||||
import { getFormatService } from '../../services';
|
import { getFormatService } from '../../services';
|
||||||
import { addPercentageColumn } from '../add_percentage_column';
|
import { addPercentageColumn } from '../add_percentage_column';
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { TableVisParams } from '../../types';
|
import { TableVisParams } from '../../../common';
|
||||||
|
|
||||||
export const usePagination = (visParams: TableVisParams, rowCount: number) => {
|
export const usePagination = (visParams: TableVisParams, rowCount: number) => {
|
||||||
const [pagination, setPagination] = useState({
|
const [pagination, setPagination] = useState({
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
* Public License, v 1.
|
* Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PluginConfigDescriptor } from 'kibana/server';
|
import { CoreSetup, PluginConfigDescriptor } from 'kibana/server';
|
||||||
|
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||||
|
|
||||||
import { configSchema, ConfigSchema } from '../config';
|
import { configSchema, ConfigSchema } from '../config';
|
||||||
|
import { registerVisTypeTableUsageCollector } from './usage_collector';
|
||||||
|
|
||||||
export const config: PluginConfigDescriptor<ConfigSchema> = {
|
export const config: PluginConfigDescriptor<ConfigSchema> = {
|
||||||
exposeToBrowser: {
|
exposeToBrowser: {
|
||||||
|
@ -21,6 +23,10 @@ export const config: PluginConfigDescriptor<ConfigSchema> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const plugin = () => ({
|
export const plugin = () => ({
|
||||||
setup() {},
|
setup(core: CoreSetup, plugins: { usageCollection?: UsageCollectionSetup }) {
|
||||||
|
if (plugins.usageCollection) {
|
||||||
|
registerVisTypeTableUsageCollector(plugins.usageCollection);
|
||||||
|
}
|
||||||
|
},
|
||||||
start() {},
|
start() {},
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* and the Server Side Public License, v 1; you may not use this file except in
|
||||||
|
* compliance with, at your election, the Elastic License or the Server Side
|
||||||
|
* Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { SavedObjectsClientContract } from 'kibana/server';
|
||||||
|
import { getStats } from './get_stats';
|
||||||
|
|
||||||
|
const mockVisualizations = {
|
||||||
|
saved_objects: [
|
||||||
|
{
|
||||||
|
attributes: {
|
||||||
|
visState:
|
||||||
|
'{"type": "table","aggs": [{ "schema": "metric" }, { "schema": "bucket" }, { "schema": "split", "enabled": true }], "params": { "row": true }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attributes: {
|
||||||
|
visState:
|
||||||
|
'{"type": "table","aggs": [{ "schema": "metric" }, { "schema": "bucket" }, { "schema": "split", "enabled": false }], "params": { "row": true }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attributes: {
|
||||||
|
visState:
|
||||||
|
'{"type": "table","aggs": [{ "schema": "metric" }, { "schema": "split", "enabled": true }], "params": { "row": false }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attributes: {
|
||||||
|
visState: '{"type": "table","aggs": [{ "schema": "metric" }, { "schema": "bucket" }]}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
attributes: { visState: '{"type": "histogram"}' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('vis_type_table getStats', () => {
|
||||||
|
const mockSoClient = ({
|
||||||
|
find: jest.fn().mockResolvedValue(mockVisualizations),
|
||||||
|
} as unknown) as SavedObjectsClientContract;
|
||||||
|
|
||||||
|
test('Returns stats from saved objects for table vis only', async () => {
|
||||||
|
const result = await getStats(mockSoClient);
|
||||||
|
expect(mockSoClient.find).toHaveBeenCalledWith({
|
||||||
|
type: 'visualization',
|
||||||
|
perPage: 10000,
|
||||||
|
});
|
||||||
|
expect(result).toEqual({
|
||||||
|
total: 4,
|
||||||
|
total_split: 3,
|
||||||
|
split_columns: {
|
||||||
|
total: 1,
|
||||||
|
enabled: 1,
|
||||||
|
},
|
||||||
|
split_rows: {
|
||||||
|
total: 2,
|
||||||
|
enabled: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* and the Server Side Public License, v 1; you may not use this file except in
|
||||||
|
* compliance with, at your election, the Elastic License or the Server Side
|
||||||
|
* Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ISavedObjectsRepository, SavedObjectsClientContract } from 'kibana/server';
|
||||||
|
import {
|
||||||
|
SavedVisState,
|
||||||
|
VisualizationSavedObjectAttributes,
|
||||||
|
} from 'src/plugins/visualizations/common';
|
||||||
|
import { TableVisParams, VIS_TYPE_TABLE } from '../../common';
|
||||||
|
|
||||||
|
export interface VisTypeTableUsage {
|
||||||
|
/**
|
||||||
|
* Total number of table type visualizations
|
||||||
|
*/
|
||||||
|
total: number;
|
||||||
|
/**
|
||||||
|
* Total number of table visualizations, using "Split table" agg
|
||||||
|
*/
|
||||||
|
total_split: number;
|
||||||
|
/**
|
||||||
|
* Split table by columns stats
|
||||||
|
*/
|
||||||
|
split_columns: {
|
||||||
|
total: number;
|
||||||
|
enabled: number;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Split table by rows stats
|
||||||
|
*/
|
||||||
|
split_rows: {
|
||||||
|
total: number;
|
||||||
|
enabled: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the response data into telemetry payload
|
||||||
|
*/
|
||||||
|
export async function getStats(
|
||||||
|
soClient: SavedObjectsClientContract | ISavedObjectsRepository
|
||||||
|
): Promise<VisTypeTableUsage | undefined> {
|
||||||
|
const visualizations = await soClient.find<VisualizationSavedObjectAttributes>({
|
||||||
|
type: 'visualization',
|
||||||
|
perPage: 10000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableVisualizations = visualizations.saved_objects
|
||||||
|
.map<SavedVisState<TableVisParams>>(({ attributes }) => JSON.parse(attributes.visState))
|
||||||
|
.filter(({ type }) => type === VIS_TYPE_TABLE);
|
||||||
|
|
||||||
|
const defaultStats = {
|
||||||
|
total: tableVisualizations.length,
|
||||||
|
total_split: 0,
|
||||||
|
split_columns: {
|
||||||
|
total: 0,
|
||||||
|
enabled: 0,
|
||||||
|
},
|
||||||
|
split_rows: {
|
||||||
|
total: 0,
|
||||||
|
enabled: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return tableVisualizations.reduce((acc, { aggs, params }) => {
|
||||||
|
const hasSplitAgg = aggs.find((agg) => agg.schema === 'split');
|
||||||
|
|
||||||
|
if (hasSplitAgg) {
|
||||||
|
acc.total_split += 1;
|
||||||
|
|
||||||
|
const isSplitRow = params.row;
|
||||||
|
const isSplitEnabled = hasSplitAgg.enabled;
|
||||||
|
|
||||||
|
const container = isSplitRow ? acc.split_rows : acc.split_columns;
|
||||||
|
container.total += 1;
|
||||||
|
container.enabled = isSplitEnabled ? container.enabled + 1 : container.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, defaultStats);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* and the Server Side Public License, v 1; you may not use this file except in
|
||||||
|
* compliance with, at your election, the Elastic License or the Server Side
|
||||||
|
* Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { registerVisTypeTableUsageCollector } from './register_usage_collector';
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* and the Server Side Public License, v 1; you may not use this file except in
|
||||||
|
* compliance with, at your election, the Elastic License or the Server Side
|
||||||
|
* Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
jest.mock('./get_stats', () => ({
|
||||||
|
getStats: jest.fn().mockResolvedValue({ somestat: 1 }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { createUsageCollectionSetupMock } from 'src/plugins/usage_collection/server/usage_collection.mock';
|
||||||
|
import { createCollectorFetchContextMock } from 'src/plugins/usage_collection/server/mocks';
|
||||||
|
|
||||||
|
import { registerVisTypeTableUsageCollector } from './register_usage_collector';
|
||||||
|
import { getStats } from './get_stats';
|
||||||
|
|
||||||
|
describe('registerVisTypeTableUsageCollector', () => {
|
||||||
|
it('Usage collector configs fit the shape', () => {
|
||||||
|
const mockCollectorSet = createUsageCollectionSetupMock();
|
||||||
|
registerVisTypeTableUsageCollector(mockCollectorSet);
|
||||||
|
expect(mockCollectorSet.makeUsageCollector).toBeCalledTimes(1);
|
||||||
|
expect(mockCollectorSet.registerCollector).toBeCalledTimes(1);
|
||||||
|
expect(mockCollectorSet.makeUsageCollector).toHaveBeenCalledWith({
|
||||||
|
type: 'vis_type_table',
|
||||||
|
isReady: expect.any(Function),
|
||||||
|
fetch: expect.any(Function),
|
||||||
|
schema: {
|
||||||
|
total: { type: 'long' },
|
||||||
|
total_split: { type: 'long' },
|
||||||
|
split_columns: {
|
||||||
|
total: { type: 'long' },
|
||||||
|
enabled: { type: 'long' },
|
||||||
|
},
|
||||||
|
split_rows: {
|
||||||
|
total: { type: 'long' },
|
||||||
|
enabled: { type: 'long' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const usageCollectorConfig = mockCollectorSet.makeUsageCollector.mock.calls[0][0];
|
||||||
|
expect(usageCollectorConfig.isReady()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Usage collector config.fetch calls getStats', async () => {
|
||||||
|
const mockCollectorSet = createUsageCollectionSetupMock();
|
||||||
|
registerVisTypeTableUsageCollector(mockCollectorSet);
|
||||||
|
const usageCollector = mockCollectorSet.makeUsageCollector.mock.results[0].value;
|
||||||
|
const mockCollectorFetchContext = createCollectorFetchContextMock();
|
||||||
|
const fetchResult = await usageCollector.fetch(mockCollectorFetchContext);
|
||||||
|
expect(getStats).toBeCalledTimes(1);
|
||||||
|
expect(getStats).toBeCalledWith(mockCollectorFetchContext.soClient);
|
||||||
|
expect(fetchResult).toEqual({ somestat: 1 });
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* and the Server Side Public License, v 1; you may not use this file except in
|
||||||
|
* compliance with, at your election, the Elastic License or the Server Side
|
||||||
|
* Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
|
||||||
|
|
||||||
|
import { getStats, VisTypeTableUsage } from './get_stats';
|
||||||
|
|
||||||
|
export function registerVisTypeTableUsageCollector(collectorSet: UsageCollectionSetup) {
|
||||||
|
const collector = collectorSet.makeUsageCollector<VisTypeTableUsage | undefined>({
|
||||||
|
type: 'vis_type_table',
|
||||||
|
isReady: () => true,
|
||||||
|
schema: {
|
||||||
|
total: { type: 'long' },
|
||||||
|
total_split: { type: 'long' },
|
||||||
|
split_columns: {
|
||||||
|
total: { type: 'long' },
|
||||||
|
enabled: { type: 'long' },
|
||||||
|
},
|
||||||
|
split_rows: {
|
||||||
|
total: { type: 'long' },
|
||||||
|
enabled: { type: 'long' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: ({ soClient }) => getStats(soClient),
|
||||||
|
});
|
||||||
|
collectorSet.registerCollector(collector);
|
||||||
|
}
|
|
@ -8,6 +8,7 @@
|
||||||
"declarationMap": true
|
"declarationMap": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
"common/**/*",
|
||||||
"public/**/*",
|
"public/**/*",
|
||||||
"server/**/*",
|
"server/**/*",
|
||||||
"*.ts"
|
"*.ts"
|
||||||
|
|
10
src/plugins/visualizations/common/index.ts
Normal file
10
src/plugins/visualizations/common/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* and the Server Side Public License, v 1; you may not use this file except in
|
||||||
|
* compliance with, at your election, the Elastic License or the Server Side
|
||||||
|
* Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @public types */
|
||||||
|
export * from './types';
|
32
src/plugins/visualizations/common/types.ts
Normal file
32
src/plugins/visualizations/common/types.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* and the Server Side Public License, v 1; you may not use this file except in
|
||||||
|
* compliance with, at your election, the Elastic License or the Server Side
|
||||||
|
* Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { SavedObjectAttributes } from 'kibana/server';
|
||||||
|
import { AggConfigOptions } from 'src/plugins/data/common';
|
||||||
|
|
||||||
|
export interface VisParams {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SavedVisState<TVisParams = VisParams> {
|
||||||
|
title: string;
|
||||||
|
type: string;
|
||||||
|
params: TVisParams;
|
||||||
|
aggs: AggConfigOptions[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VisualizationSavedObjectAttributes extends SavedObjectAttributes {
|
||||||
|
description: string;
|
||||||
|
kibanaSavedObjectMeta: {
|
||||||
|
searchSourceJSON: string;
|
||||||
|
};
|
||||||
|
title: string;
|
||||||
|
version: number;
|
||||||
|
visState: string;
|
||||||
|
uiStateJSON: string;
|
||||||
|
}
|
|
@ -34,7 +34,7 @@ export type {
|
||||||
Schema,
|
Schema,
|
||||||
ISchemas,
|
ISchemas,
|
||||||
} from './vis_types';
|
} from './vis_types';
|
||||||
export { VisParams, SerializedVis, SerializedVisData, VisData } from './vis';
|
export { SerializedVis, SerializedVisData, VisData } from './vis';
|
||||||
export type VisualizeEmbeddableFactoryContract = PublicContract<VisualizeEmbeddableFactory>;
|
export type VisualizeEmbeddableFactoryContract = PublicContract<VisualizeEmbeddableFactory>;
|
||||||
export type VisualizeEmbeddableContract = PublicContract<VisualizeEmbeddable>;
|
export type VisualizeEmbeddableContract = PublicContract<VisualizeEmbeddable>;
|
||||||
export { VisualizeInput } from './embeddable';
|
export { VisualizeInput } from './embeddable';
|
||||||
|
@ -46,12 +46,13 @@ export { PersistedState } from './persisted_state';
|
||||||
export {
|
export {
|
||||||
VisualizationControllerConstructor,
|
VisualizationControllerConstructor,
|
||||||
VisualizationController,
|
VisualizationController,
|
||||||
SavedVisState,
|
|
||||||
ISavedVis,
|
ISavedVis,
|
||||||
VisSavedObject,
|
VisSavedObject,
|
||||||
VisResponseValue,
|
VisResponseValue,
|
||||||
VisToExpressionAst,
|
VisToExpressionAst,
|
||||||
|
VisParams,
|
||||||
} from './types';
|
} from './types';
|
||||||
export { ExprVisAPIEvents } from './expressions/vis';
|
export { ExprVisAPIEvents } from './expressions/vis';
|
||||||
export { VisualizationListItem, VisualizationStage } from './vis_types/vis_type_alias_registry';
|
export { VisualizationListItem, VisualizationStage } from './vis_types/vis_type_alias_registry';
|
||||||
export { VISUALIZE_ENABLE_LABS_SETTING } from '../common/constants';
|
export { VISUALIZE_ENABLE_LABS_SETTING } from '../common/constants';
|
||||||
|
export { SavedVisState } from '../common';
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Public License, v 1.
|
* Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SavedVisState } from '../types';
|
import { SavedVisState } from '../../common';
|
||||||
|
|
||||||
declare function updateOldState(oldState: unknown): SavedVisState;
|
declare function updateOldState(oldState: unknown): SavedVisState;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { extractReferences, injectReferences } from './saved_visualization_references';
|
import { extractReferences, injectReferences } from './saved_visualization_references';
|
||||||
import { VisSavedObject, SavedVisState } from '../types';
|
import { VisSavedObject } from '../types';
|
||||||
|
import { SavedVisState } from '../../common';
|
||||||
|
|
||||||
describe('extractReferences', () => {
|
describe('extractReferences', () => {
|
||||||
test('extracts nothing if savedSearchId is empty', () => {
|
test('extracts nothing if savedSearchId is empty', () => {
|
||||||
|
|
|
@ -7,15 +7,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SavedObject } from '../../../plugins/saved_objects/public';
|
import { SavedObject } from '../../../plugins/saved_objects/public';
|
||||||
import {
|
import { SearchSourceFields, TimefilterContract } from '../../../plugins/data/public';
|
||||||
AggConfigOptions,
|
|
||||||
SearchSourceFields,
|
|
||||||
TimefilterContract,
|
|
||||||
} from '../../../plugins/data/public';
|
|
||||||
import { ExpressionAstExpression } from '../../expressions/public';
|
import { ExpressionAstExpression } from '../../expressions/public';
|
||||||
|
|
||||||
import { SerializedVis, Vis, VisParams } from './vis';
|
import { SerializedVis, Vis } from './vis';
|
||||||
import { ExprVis } from './expressions/vis';
|
import { ExprVis } from './expressions/vis';
|
||||||
|
import { SavedVisState, VisParams } from '../common/types';
|
||||||
|
|
||||||
export { Vis, SerializedVis, VisParams };
|
export { Vis, SerializedVis, VisParams };
|
||||||
|
|
||||||
|
@ -30,13 +27,6 @@ export type VisualizationControllerConstructor = new (
|
||||||
vis: ExprVis
|
vis: ExprVis
|
||||||
) => VisualizationController;
|
) => VisualizationController;
|
||||||
|
|
||||||
export interface SavedVisState {
|
|
||||||
title: string;
|
|
||||||
type: string;
|
|
||||||
params: VisParams;
|
|
||||||
aggs: AggConfigOptions[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ISavedVis {
|
export interface ISavedVis {
|
||||||
id?: string;
|
id?: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
@ -30,6 +30,7 @@ import {
|
||||||
AggConfigOptions,
|
AggConfigOptions,
|
||||||
SearchSourceFields,
|
SearchSourceFields,
|
||||||
} from '../../../plugins/data/public';
|
} from '../../../plugins/data/public';
|
||||||
|
import { VisParams } from '../common/types';
|
||||||
|
|
||||||
export interface SerializedVisData {
|
export interface SerializedVisData {
|
||||||
expression?: string;
|
expression?: string;
|
||||||
|
@ -56,10 +57,6 @@ export interface VisData {
|
||||||
savedSearchId?: string;
|
savedSearchId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VisParams {
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?: string) => {
|
const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?: string) => {
|
||||||
const searchSource = inputSearchSource.createCopy();
|
const searchSource = inputSearchSource.createCopy();
|
||||||
if (savedSearchId) {
|
if (savedSearchId) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue