mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Move Lens attribute builder to a package (#163422)
closes [#163491](https://github.com/elastic/kibana/issues/163491) ## Summary This PR creates a new package that contains a utility API that helps to generate the JSON with the attributes required to render a Lens chart with the `EmbeddableComponent`. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
6e241a8b02
commit
281cc224c9
50 changed files with 786 additions and 477 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
@ -460,6 +460,7 @@ src/plugins/kibana_usage_collection @elastic/kibana-core
|
|||
src/plugins/kibana_utils @elastic/kibana-app-services
|
||||
x-pack/plugins/kubernetes_security @elastic/sec-cloudnative-integrations
|
||||
packages/kbn-language-documentation-popover @elastic/kibana-visualizations
|
||||
packages/kbn-lens-embeddable-utils @elastic/infra-monitoring-ui
|
||||
x-pack/plugins/lens @elastic/kibana-visualizations
|
||||
x-pack/plugins/license_api_guard @elastic/platform-deployment-management
|
||||
x-pack/plugins/license_management @elastic/platform-deployment-management
|
||||
|
|
|
@ -481,6 +481,7 @@
|
|||
"@kbn/kibana-utils-plugin": "link:src/plugins/kibana_utils",
|
||||
"@kbn/kubernetes-security-plugin": "link:x-pack/plugins/kubernetes_security",
|
||||
"@kbn/language-documentation-popover": "link:packages/kbn-language-documentation-popover",
|
||||
"@kbn/lens-embeddable-utils": "link:packages/kbn-lens-embeddable-utils",
|
||||
"@kbn/lens-plugin": "link:x-pack/plugins/lens",
|
||||
"@kbn/license-api-guard-plugin": "link:x-pack/plugins/license_api_guard",
|
||||
"@kbn/license-management-plugin": "link:x-pack/plugins/license_management",
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
|
||||
# Lens Attributes Builder
|
||||
# @kbn/lens-embeddable-utils
|
||||
|
||||
The Lens Attributes Builder is a utility for creating JSON objects used to render charts with Lens. It simplifies the process of configuring and building the necessary attributes for different chart types.
|
||||
## Lens Attributes Builder
|
||||
|
||||
## Usage
|
||||
The Lens Attributes Builder is a utility for creating JSON objects used to render charts with Lens. It simplifies the process of configuring and building the necessary attributes for different chart types.
|
||||
|
||||
### Creating a Metric Chart
|
||||
**Notes**:
|
||||
|
||||
This utililty is primarily used by Infra Observability UI and not meant to be used as an official solution provided by the Lens team.
|
||||
|
||||
- The tool has partial support of Lens charts, currently limited to XY and Metric charts.
|
||||
- XY Bucket and Breakdown dimensions are limited respectively to Date Histogram and Top values.
|
||||
|
||||
### Usage
|
||||
|
||||
#### Creating a Metric Chart
|
||||
|
||||
To create a metric chart, use the `MetricChart` class and provide the required configuration. Here's an example:
|
||||
|
||||
|
@ -22,13 +31,13 @@ const metricChart = new MetricChart({
|
|||
},
|
||||
},
|
||||
},
|
||||
formulaAPI,
|
||||
}),
|
||||
dataView,
|
||||
formulaAPI
|
||||
});
|
||||
```
|
||||
|
||||
### Creating an XY Chart
|
||||
#### Creating an XY Chart
|
||||
|
||||
To create an XY chart, use the `XYChart` class and provide the required configuration. Here's an example:
|
||||
|
||||
|
@ -45,13 +54,72 @@ const xyChart = new XYChart({
|
|||
},
|
||||
},
|
||||
}],
|
||||
formulaAPI,
|
||||
options: {
|
||||
buckets: {type: 'date_histogram'},
|
||||
},
|
||||
})],
|
||||
dataView,
|
||||
formulaAPI
|
||||
});
|
||||
```
|
||||
|
||||
### Adding Multiple Layers to an XY Chart
|
||||
#### Variations of the XY Chart
|
||||
|
||||
XYChart has different series type variations. Here is an example of how to build a line (default) and area charts
|
||||
|
||||
#### Line chart
|
||||
|
||||
```ts
|
||||
const xyChart = new XYChart({
|
||||
layers: [new XYDataLayer({
|
||||
data: [{
|
||||
label: 'Inbound (RX)',
|
||||
value: "average(system.load.1) / max(system.load.cores)",
|
||||
format: {
|
||||
id: 'percent',
|
||||
params: {
|
||||
decimals: 1,
|
||||
},
|
||||
},
|
||||
|
||||
}],
|
||||
options: {
|
||||
buckets: {type: 'date_histogram'},
|
||||
seriesType: 'line' // default. it doesn't need to be informed.
|
||||
}
|
||||
})],
|
||||
dataView,
|
||||
formulaAPI
|
||||
});
|
||||
```
|
||||
|
||||
#### Area chart
|
||||
|
||||
```ts
|
||||
const xyChart = new XYChart({
|
||||
layers: [new XYDataLayer({
|
||||
data: [{
|
||||
label: 'Inbound (RX)',
|
||||
value: "average(system.load.1) / max(system.load.cores)",
|
||||
format: {
|
||||
id: 'percent',
|
||||
params: {
|
||||
decimals: 1,
|
||||
},
|
||||
},
|
||||
|
||||
}],
|
||||
options: {
|
||||
buckets: {type: 'date_histogram'},
|
||||
seriesType: 'area'
|
||||
}
|
||||
})],
|
||||
dataView,
|
||||
formulaAPI
|
||||
});
|
||||
```
|
||||
|
||||
#### Adding Multiple Layers to an XY Chart
|
||||
|
||||
An XY chart can have multiple layers. Here's an example of containing a Reference Line Layer:
|
||||
|
||||
|
@ -69,10 +137,13 @@ const xyChart = new XYChart({
|
|||
},
|
||||
},
|
||||
}],
|
||||
formulaAPI,
|
||||
options: {
|
||||
buckets: {type: 'date_histogram'},
|
||||
},
|
||||
}),
|
||||
new XYReferenceLineLayer({
|
||||
data: [{
|
||||
|
||||
value: "1",
|
||||
format: {
|
||||
id: 'percent',
|
||||
|
@ -84,10 +155,11 @@ const xyChart = new XYChart({
|
|||
}),
|
||||
],
|
||||
dataView,
|
||||
formulaAPI
|
||||
});
|
||||
```
|
||||
|
||||
### Adding Multiple Data Sources in the Same Layer
|
||||
#### Adding Multiple Data Sources in the Same Layer
|
||||
|
||||
In an XY chart, it's possible to define multiple data sources within the same layer.
|
||||
|
||||
|
@ -115,13 +187,16 @@ const xyChart = new XYChart({
|
|||
},
|
||||
},
|
||||
}],
|
||||
formulaAPI,
|
||||
options: {
|
||||
buckets: {type: 'date_histogram'},
|
||||
},
|
||||
}),
|
||||
dataView,
|
||||
formulaAPI
|
||||
});
|
||||
```
|
||||
|
||||
### Building Lens Chart Attributes
|
||||
#### Building Lens Chart Attributes
|
||||
|
||||
The `LensAttributesBuilder` is responsible for creating the full JSON object that combines the attributes returned by the chart classes. Here's an example:
|
||||
|
||||
|
@ -150,10 +225,10 @@ const builder = new LensAttributesBuilder({
|
|||
},
|
||||
},
|
||||
},
|
||||
formulaAPI,
|
||||
}),
|
||||
dataView,
|
||||
})
|
||||
formulaAPI
|
||||
}),
|
||||
});
|
||||
|
||||
const lensAttributes = builder.build();
|
||||
|
@ -163,4 +238,4 @@ const lensAttributes = builder.build();
|
|||
viewMode={ViewMode.VIEW}
|
||||
...
|
||||
/>
|
||||
```
|
||||
```
|
|
@ -1,13 +1,14 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { DataViewSpec, DataView } from '@kbn/data-plugin/common';
|
||||
|
||||
export const DEFAULT_AD_HOC_DATA_VIEW_ID = 'infra_lens_ad_hoc_default';
|
||||
export const DEFAULT_AD_HOC_DATA_VIEW_ID = 'lens_ad_hoc_default';
|
||||
|
||||
export class DataViewCache {
|
||||
private static instance: DataViewCache;
|
|
@ -1,8 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import 'jest-canvas-mock';
|
||||
|
@ -19,7 +20,7 @@ import {
|
|||
} from './visualization_types';
|
||||
import type { FormulaPublicApi, GenericIndexPatternColumn } from '@kbn/lens-plugin/public';
|
||||
import { ReferenceBasedIndexPatternColumn } from '@kbn/lens-plugin/public/datasources/form_based/operations/definitions/column_types';
|
||||
import type { FormulaConfig } from '../types';
|
||||
import type { FormulaValueConfig } from './types';
|
||||
|
||||
const mockDataView = {
|
||||
id: 'mock-id',
|
||||
|
@ -85,7 +86,7 @@ const REFERENCE_LINE_LAYER: ReferenceBasedIndexPatternColumn = {
|
|||
scale: 'ratio',
|
||||
};
|
||||
|
||||
const getFormula = (value: string): FormulaConfig => ({
|
||||
const getFormula = (value: string): FormulaValueConfig => ({
|
||||
value,
|
||||
format: {
|
||||
id: 'percent',
|
||||
|
@ -106,10 +107,10 @@ describe('lens_attributes_builder', () => {
|
|||
const metriChart = new MetricChart({
|
||||
layers: new MetricLayer({
|
||||
data: getFormula(AVERAGE_CPU_USER_FORMULA),
|
||||
formulaAPI,
|
||||
}),
|
||||
|
||||
dataView: mockDataView,
|
||||
formulaAPI,
|
||||
});
|
||||
const builder = new LensAttributesBuilder({ visualization: metriChart });
|
||||
const {
|
||||
|
@ -148,10 +149,10 @@ describe('lens_attributes_builder', () => {
|
|||
options: {
|
||||
showTrendLine: true,
|
||||
},
|
||||
formulaAPI,
|
||||
}),
|
||||
|
||||
dataView: mockDataView,
|
||||
formulaAPI,
|
||||
});
|
||||
const builder = new LensAttributesBuilder({ visualization: metriChart });
|
||||
const {
|
||||
|
@ -204,10 +205,13 @@ describe('lens_attributes_builder', () => {
|
|||
layers: [
|
||||
new XYDataLayer({
|
||||
data: [getFormula(AVERAGE_CPU_USER_FORMULA)],
|
||||
formulaAPI,
|
||||
options: {
|
||||
buckets: { type: 'date_histogram' },
|
||||
},
|
||||
}),
|
||||
],
|
||||
dataView: mockDataView,
|
||||
formulaAPI,
|
||||
});
|
||||
const builder = new LensAttributesBuilder({ visualization: xyChart });
|
||||
const {
|
||||
|
@ -248,13 +252,23 @@ describe('lens_attributes_builder', () => {
|
|||
layers: [
|
||||
new XYDataLayer({
|
||||
data: [getFormula(AVERAGE_CPU_USER_FORMULA)],
|
||||
formulaAPI,
|
||||
options: {
|
||||
buckets: { type: 'date_histogram' },
|
||||
},
|
||||
}),
|
||||
new XYReferenceLinesLayer({
|
||||
data: [getFormula('1')],
|
||||
data: [
|
||||
{
|
||||
value: '1',
|
||||
format: {
|
||||
id: 'percent',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
dataView: mockDataView,
|
||||
formulaAPI,
|
||||
});
|
||||
const builder = new LensAttributesBuilder({ visualization: xyChart });
|
||||
const {
|
||||
|
@ -316,10 +330,13 @@ describe('lens_attributes_builder', () => {
|
|||
layers: [
|
||||
new XYDataLayer({
|
||||
data: [getFormula(AVERAGE_CPU_USER_FORMULA), getFormula(AVERAGE_CPU_SYSTEM_FORMULA)],
|
||||
formulaAPI,
|
||||
options: {
|
||||
buckets: { type: 'date_histogram' },
|
||||
},
|
||||
}),
|
||||
],
|
||||
dataView: mockDataView,
|
||||
formulaAPI,
|
||||
});
|
||||
const builder = new LensAttributesBuilder({ visualization: xyChart });
|
||||
const {
|
|
@ -1,15 +1,17 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type {
|
||||
LensAttributes,
|
||||
LensVisualizationState,
|
||||
Chart,
|
||||
VisualizationAttributesBuilder,
|
||||
} from '../types';
|
||||
} from './types';
|
||||
import { DataViewCache } from './data_view_cache';
|
||||
import { getAdhocDataView } from './utils';
|
||||
|
||||
|
@ -17,12 +19,12 @@ export class LensAttributesBuilder<T extends Chart<LensVisualizationState>>
|
|||
implements VisualizationAttributesBuilder
|
||||
{
|
||||
private dataViewCache: DataViewCache;
|
||||
constructor(private state: { visualization: T }) {
|
||||
constructor(private lens: { visualization: T }) {
|
||||
this.dataViewCache = DataViewCache.getInstance();
|
||||
}
|
||||
|
||||
build(): LensAttributes {
|
||||
const { visualization } = this.state;
|
||||
const { visualization } = this.lens;
|
||||
return {
|
||||
title: visualization.getTitle(),
|
||||
visualizationType: visualization.getVisualizationType(),
|
||||
|
@ -34,10 +36,17 @@ export class LensAttributesBuilder<T extends Chart<LensVisualizationState>>
|
|||
},
|
||||
},
|
||||
internalReferences: visualization.getReferences(),
|
||||
// EmbeddableComponent receive filters.
|
||||
filters: [],
|
||||
// EmbeddableComponent receive query.
|
||||
query: { language: 'kuery', query: '' },
|
||||
visualization: visualization.getVisualizationState(),
|
||||
adHocDataViews: getAdhocDataView(this.dataViewCache.getSpec(visualization.getDataView())),
|
||||
// Getting the spec from a data view is a heavy operation, that's why the result is cached.
|
||||
adHocDataViews: getAdhocDataView(
|
||||
visualization
|
||||
.getDataViews()
|
||||
.reduce((acc, curr) => ({ ...acc, ...this.dataViewCache.getSpec(curr) }), {})
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { SavedObjectReference } from '@kbn/core/server';
|
||||
import type { DataView } from '@kbn/data-views-plugin/common';
|
||||
import type {
|
||||
FormBasedPersistedState,
|
||||
MetricVisualizationState,
|
||||
PersistedIndexPatternLayer,
|
||||
TypedLensByValueInput,
|
||||
XYState,
|
||||
FormulaPublicApi,
|
||||
XYLayerConfig,
|
||||
} from '@kbn/lens-plugin/public';
|
||||
export type LensAttributes = TypedLensByValueInput['attributes'];
|
||||
|
||||
// Attributes
|
||||
export type LensVisualizationState = XYState | MetricVisualizationState;
|
||||
|
||||
export interface VisualizationAttributesBuilder {
|
||||
build(): LensAttributes;
|
||||
}
|
||||
|
||||
// Column
|
||||
export interface BaseChartColumn<TValueConfig extends StaticValueConfig | FormulaValueConfig> {
|
||||
getValueConfig(): TValueConfig;
|
||||
}
|
||||
|
||||
export interface ChartColumn extends BaseChartColumn<FormulaValueConfig> {
|
||||
getData(
|
||||
id: string,
|
||||
baseLayer: PersistedIndexPatternLayer,
|
||||
dataView: DataView,
|
||||
formulaAPI: FormulaPublicApi
|
||||
): PersistedIndexPatternLayer;
|
||||
}
|
||||
|
||||
export interface StaticChartColumn extends BaseChartColumn<StaticValueConfig> {
|
||||
getData(id: string, baseLayer: PersistedIndexPatternLayer): PersistedIndexPatternLayer;
|
||||
}
|
||||
|
||||
// Layer
|
||||
export type LensLayerConfig = XYLayerConfig | MetricVisualizationState;
|
||||
|
||||
export interface ChartLayer<TLayerConfig extends LensLayerConfig> {
|
||||
getName(): string | undefined;
|
||||
getLayer(
|
||||
layerId: string,
|
||||
accessorId: string,
|
||||
dataView: DataView,
|
||||
formulaAPI: FormulaPublicApi
|
||||
): FormBasedPersistedState['layers'];
|
||||
getReference(layerId: string, dataView: DataView): SavedObjectReference[];
|
||||
getLayerConfig(layerId: string, acessorId: string): TLayerConfig;
|
||||
getDataView(): DataView | undefined;
|
||||
}
|
||||
|
||||
// Chart
|
||||
export interface Chart<TVisualizationState extends LensVisualizationState> {
|
||||
getTitle(): string;
|
||||
getVisualizationType(): string;
|
||||
getLayers(): FormBasedPersistedState['layers'];
|
||||
getVisualizationState(): TVisualizationState;
|
||||
getReferences(): SavedObjectReference[];
|
||||
getDataViews(): DataView[];
|
||||
}
|
||||
export interface ChartConfig<
|
||||
TLayer extends ChartLayer<LensLayerConfig> | Array<ChartLayer<LensLayerConfig>>
|
||||
> {
|
||||
formulaAPI: FormulaPublicApi;
|
||||
dataView: DataView;
|
||||
layers: TLayer;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
// Formula
|
||||
type LensFormula = Parameters<FormulaPublicApi['insertOrReplaceFormulaColumn']>[1];
|
||||
export type FormulaValueConfig = Omit<LensFormula, 'formula'> & {
|
||||
color?: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type StaticValueConfig = Omit<LensFormula, 'formula'> & {
|
||||
color?: string;
|
||||
value: string;
|
||||
};
|
|
@ -1,10 +1,12 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import {
|
||||
|
||||
import type {
|
||||
DateHistogramIndexPatternColumn,
|
||||
PersistedIndexPatternLayer,
|
||||
TermsIndexPatternColumn,
|
||||
|
@ -17,12 +19,27 @@ export const DEFAULT_AD_HOC_DATA_VIEW_ID = 'infra_lens_ad_hoc_default';
|
|||
|
||||
const DEFAULT_BREAKDOWN_SIZE = 10;
|
||||
|
||||
export function nonNullable<T>(v: T): v is NonNullable<T> {
|
||||
return v != null;
|
||||
}
|
||||
|
||||
export type DateHistogramColumnParams = DateHistogramIndexPatternColumn['params'];
|
||||
|
||||
export type TopValuesColumnParams = Pick<
|
||||
TermsIndexPatternColumn['params'],
|
||||
'size' | 'orderDirection' | 'orderBy'
|
||||
>;
|
||||
|
||||
export const getHistogramColumn = ({
|
||||
columnName,
|
||||
overrides,
|
||||
options,
|
||||
}: {
|
||||
columnName: string;
|
||||
overrides?: Partial<Pick<DateHistogramIndexPatternColumn, 'sourceField' | 'params'>>;
|
||||
options?: Partial<
|
||||
Pick<DateHistogramIndexPatternColumn, 'sourceField'> & {
|
||||
params: DateHistogramColumnParams;
|
||||
}
|
||||
>;
|
||||
}) => {
|
||||
return {
|
||||
[columnName]: {
|
||||
|
@ -32,32 +49,32 @@ export const getHistogramColumn = ({
|
|||
operationType: 'date_histogram',
|
||||
scale: 'interval',
|
||||
sourceField: '@timestamp',
|
||||
...overrides,
|
||||
params: { interval: 'auto', ...overrides?.params },
|
||||
...options,
|
||||
params: { interval: 'auto', ...options?.params },
|
||||
} as DateHistogramIndexPatternColumn,
|
||||
};
|
||||
};
|
||||
|
||||
export const getTopValuesColumn = ({
|
||||
columnName,
|
||||
overrides,
|
||||
field,
|
||||
options,
|
||||
}: {
|
||||
columnName: string;
|
||||
overrides?: Partial<Pick<TermsIndexPatternColumn, 'sourceField'>> & {
|
||||
breakdownSize?: number;
|
||||
};
|
||||
field: string;
|
||||
options?: Partial<TopValuesColumnParams>;
|
||||
}): PersistedIndexPatternLayer['columns'] => {
|
||||
const { breakdownSize = DEFAULT_BREAKDOWN_SIZE, sourceField } = overrides ?? {};
|
||||
const { size = DEFAULT_BREAKDOWN_SIZE, ...params } = options ?? {};
|
||||
return {
|
||||
[columnName]: {
|
||||
label: `Top ${breakdownSize} values of ${sourceField}`,
|
||||
label: `Top ${size} values of ${field}`,
|
||||
dataType: 'string',
|
||||
operationType: 'terms',
|
||||
scale: 'ordinal',
|
||||
sourceField,
|
||||
sourceField: field,
|
||||
isBucketed: true,
|
||||
params: {
|
||||
size: breakdownSize,
|
||||
size,
|
||||
orderBy: {
|
||||
type: 'alphabetical',
|
||||
fallback: false,
|
||||
|
@ -72,6 +89,7 @@ export const getTopValuesColumn = ({
|
|||
exclude: [],
|
||||
includeIsRegex: false,
|
||||
excludeIsRegex: false,
|
||||
...params,
|
||||
},
|
||||
} as TermsIndexPatternColumn,
|
||||
};
|
|
@ -1,8 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { XYChart, type XYVisualOptions } from './xy_chart';
|
|
@ -1,28 +1,30 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { FormulaPublicApi, PersistedIndexPatternLayer } from '@kbn/lens-plugin/public';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { FormulaConfig, ChartColumn } from '../../../../types';
|
||||
import type { FormulaValueConfig, ChartColumn } from '../../../types';
|
||||
|
||||
export class FormulaColumn implements ChartColumn {
|
||||
constructor(private formulaConfig: FormulaConfig, private formulaAPI: FormulaPublicApi) {}
|
||||
constructor(private valueConfig: FormulaValueConfig) {}
|
||||
|
||||
getFormulaConfig(): FormulaConfig {
|
||||
return this.formulaConfig;
|
||||
getValueConfig(): FormulaValueConfig {
|
||||
return this.valueConfig;
|
||||
}
|
||||
|
||||
getData(
|
||||
id: string,
|
||||
baseLayer: PersistedIndexPatternLayer,
|
||||
dataView: DataView
|
||||
dataView: DataView,
|
||||
formulaAPI: FormulaPublicApi
|
||||
): PersistedIndexPatternLayer {
|
||||
const { value, ...rest } = this.getFormulaConfig();
|
||||
const formulaLayer = this.formulaAPI.insertOrReplaceFormulaColumn(
|
||||
const { value, ...rest } = this.getValueConfig();
|
||||
const formulaLayer = formulaAPI.insertOrReplaceFormulaColumn(
|
||||
id,
|
||||
{ formula: value, ...rest },
|
||||
baseLayer,
|
|
@ -1,23 +1,24 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { PersistedIndexPatternLayer } from '@kbn/lens-plugin/public';
|
||||
import type { ReferenceBasedIndexPatternColumn } from '@kbn/lens-plugin/public/datasources/form_based/operations/definitions/column_types';
|
||||
import type { FormulaConfig, ChartColumn } from '../../../../types';
|
||||
import type { StaticChartColumn, StaticValueConfig } from '../../../types';
|
||||
|
||||
export class ReferenceLineColumn implements ChartColumn {
|
||||
constructor(private formulaConfig: FormulaConfig) {}
|
||||
export class ReferenceLineColumn implements StaticChartColumn {
|
||||
constructor(private valueConfig: StaticValueConfig) {}
|
||||
|
||||
getFormulaConfig(): FormulaConfig {
|
||||
return this.formulaConfig;
|
||||
getValueConfig(): StaticValueConfig {
|
||||
return this.valueConfig;
|
||||
}
|
||||
|
||||
getData(id: string, baseLayer: PersistedIndexPatternLayer): PersistedIndexPatternLayer {
|
||||
const { label, ...params } = this.getFormulaConfig();
|
||||
const { label, ...params } = this.getValueConfig();
|
||||
return {
|
||||
linkToLayers: [],
|
||||
columnOrder: [...baseLayer.columnOrder, id],
|
|
@ -1,13 +1,14 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { MetricLayer, type MetricLayerOptions } from './metric_layer';
|
||||
export { XYDataLayer, type XYLayerOptions } from './xy_data_layer';
|
||||
export { XYReferenceLinesLayer } from './xy_reference_lines_layer';
|
||||
|
||||
export { FormulaColumn as FormulaDataColumn } from './column/formula';
|
||||
export { ReferenceLineColumn } from './column/reference_line';
|
||||
export { FormulaColumn as FormulaDataColumn } from './columns/formula';
|
||||
export { ReferenceLineColumn } from './columns/reference_line';
|
|
@ -1,8 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { SavedObjectReference } from '@kbn/core/server';
|
||||
|
@ -13,9 +14,9 @@ import type {
|
|||
MetricVisualizationState,
|
||||
PersistedIndexPatternLayer,
|
||||
} from '@kbn/lens-plugin/public';
|
||||
import type { ChartColumn, ChartLayer, FormulaConfig } from '../../../types';
|
||||
import type { ChartColumn, ChartLayer, FormulaValueConfig } from '../../types';
|
||||
import { getDefaultReferences, getHistogramColumn } from '../../utils';
|
||||
import { FormulaColumn } from './column/formula';
|
||||
import { FormulaColumn } from './columns/formula';
|
||||
|
||||
const HISTOGRAM_COLUMN_NAME = 'x_date_histogram';
|
||||
|
||||
|
@ -27,28 +28,32 @@ export interface MetricLayerOptions {
|
|||
}
|
||||
|
||||
interface MetricLayerConfig {
|
||||
data: FormulaConfig;
|
||||
data: FormulaValueConfig;
|
||||
options?: MetricLayerOptions;
|
||||
formulaAPI: FormulaPublicApi;
|
||||
/**
|
||||
* It is possible to define a specific dataView for the layer. It will override the global chart one
|
||||
**/
|
||||
dataView?: DataView;
|
||||
}
|
||||
|
||||
export class MetricLayer implements ChartLayer<MetricVisualizationState> {
|
||||
private column: ChartColumn;
|
||||
constructor(private layerConfig: MetricLayerConfig) {
|
||||
this.column = new FormulaColumn(layerConfig.data, layerConfig.formulaAPI);
|
||||
this.column = new FormulaColumn(layerConfig.data);
|
||||
}
|
||||
|
||||
getLayer(
|
||||
layerId: string,
|
||||
accessorId: string,
|
||||
dataView: DataView
|
||||
chartDataView: DataView,
|
||||
formulaAPI: FormulaPublicApi
|
||||
): FormBasedPersistedState['layers'] {
|
||||
const baseLayer: PersistedIndexPatternLayer = {
|
||||
columnOrder: [HISTOGRAM_COLUMN_NAME],
|
||||
columns: getHistogramColumn({
|
||||
columnName: HISTOGRAM_COLUMN_NAME,
|
||||
overrides: {
|
||||
sourceField: dataView.timeFieldName,
|
||||
options: {
|
||||
sourceField: (this.layerConfig.dataView ?? chartDataView).timeFieldName,
|
||||
params: {
|
||||
interval: 'auto',
|
||||
includeEmptyRows: true,
|
||||
|
@ -66,23 +71,29 @@ export class MetricLayer implements ChartLayer<MetricVisualizationState> {
|
|||
columnOrder: [],
|
||||
columns: {},
|
||||
},
|
||||
dataView
|
||||
this.layerConfig.dataView ?? chartDataView,
|
||||
formulaAPI
|
||||
),
|
||||
},
|
||||
...(this.layerConfig.options?.showTrendLine
|
||||
? {
|
||||
[`${layerId}_trendline`]: {
|
||||
linkToLayers: [layerId],
|
||||
...this.column.getData(`${accessorId}_trendline`, baseLayer, dataView),
|
||||
...this.column.getData(
|
||||
`${accessorId}_trendline`,
|
||||
baseLayer,
|
||||
this.layerConfig.dataView ?? chartDataView,
|
||||
formulaAPI
|
||||
),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
getReference(layerId: string, dataView: DataView): SavedObjectReference[] {
|
||||
getReference(layerId: string, chartDataView: DataView): SavedObjectReference[] {
|
||||
return [
|
||||
...getDefaultReferences(dataView, layerId),
|
||||
...getDefaultReferences(dataView, `${layerId}_trendline`),
|
||||
...getDefaultReferences(this.layerConfig.dataView ?? chartDataView, layerId),
|
||||
...getDefaultReferences(this.layerConfig.dataView ?? chartDataView, `${layerId}_trendline`),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -107,6 +118,10 @@ export class MetricLayer implements ChartLayer<MetricVisualizationState> {
|
|||
};
|
||||
}
|
||||
getName(): string | undefined {
|
||||
return this.column.getFormulaConfig().label;
|
||||
return this.column.getValueConfig().label;
|
||||
}
|
||||
|
||||
getDataView(): DataView | undefined {
|
||||
return this.layerConfig.dataView;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { SavedObjectReference } from '@kbn/core/server';
|
||||
import type { DataView } from '@kbn/data-views-plugin/common';
|
||||
import type {
|
||||
FormulaPublicApi,
|
||||
FormBasedPersistedState,
|
||||
PersistedIndexPatternLayer,
|
||||
XYDataLayerConfig,
|
||||
SeriesType,
|
||||
TermsIndexPatternColumn,
|
||||
DateHistogramIndexPatternColumn,
|
||||
} from '@kbn/lens-plugin/public';
|
||||
import type { ChartColumn, ChartLayer, FormulaValueConfig } from '../../types';
|
||||
import {
|
||||
getDefaultReferences,
|
||||
getHistogramColumn,
|
||||
getTopValuesColumn,
|
||||
nonNullable,
|
||||
type TopValuesColumnParams,
|
||||
type DateHistogramColumnParams,
|
||||
} from '../../utils';
|
||||
import { FormulaColumn } from './columns/formula';
|
||||
|
||||
const BREAKDOWN_COLUMN_NAME = 'aggs_breakdown';
|
||||
const HISTOGRAM_COLUMN_NAME = 'x_date_histogram';
|
||||
|
||||
interface TopValuesBucketedColumn {
|
||||
type: 'top_values';
|
||||
field: TermsIndexPatternColumn['sourceField'];
|
||||
params?: Partial<TopValuesColumnParams>;
|
||||
}
|
||||
interface DateHistogramBucketedColumn {
|
||||
type: 'date_histogram';
|
||||
field?: DateHistogramIndexPatternColumn['sourceField'];
|
||||
params?: Partial<DateHistogramColumnParams>;
|
||||
}
|
||||
|
||||
export interface XYLayerOptions {
|
||||
// Add more types as support for them is implemented
|
||||
breakdown?: TopValuesBucketedColumn;
|
||||
// Add more types as support for them is implemented
|
||||
buckets?: DateHistogramBucketedColumn;
|
||||
seriesType?: SeriesType;
|
||||
}
|
||||
|
||||
interface XYLayerConfig {
|
||||
data: FormulaValueConfig[];
|
||||
options?: XYLayerOptions;
|
||||
/**
|
||||
* It is possible to define a specific dataView for the layer. It will override the global chart one
|
||||
**/
|
||||
dataView?: DataView;
|
||||
}
|
||||
|
||||
export class XYDataLayer implements ChartLayer<XYDataLayerConfig> {
|
||||
private column: ChartColumn[];
|
||||
private layerConfig: XYLayerConfig;
|
||||
constructor(layerConfig: XYLayerConfig) {
|
||||
this.column = layerConfig.data.map((dataItem) => new FormulaColumn(dataItem));
|
||||
this.layerConfig = {
|
||||
...layerConfig,
|
||||
options: {
|
||||
...layerConfig.options,
|
||||
buckets: {
|
||||
type: 'date_histogram',
|
||||
...layerConfig.options?.buckets,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
getName(): string | undefined {
|
||||
return this.column[0].getValueConfig().label;
|
||||
}
|
||||
|
||||
getBaseLayer(dataView: DataView, options: XYLayerOptions) {
|
||||
return {
|
||||
...(options.buckets?.type === 'date_histogram'
|
||||
? getHistogramColumn({
|
||||
columnName: HISTOGRAM_COLUMN_NAME,
|
||||
options: {
|
||||
...options.buckets.params,
|
||||
sourceField: options.buckets.field ?? dataView.timeFieldName,
|
||||
},
|
||||
})
|
||||
: {}),
|
||||
...(options.breakdown?.type === 'top_values'
|
||||
? {
|
||||
...getTopValuesColumn({
|
||||
columnName: BREAKDOWN_COLUMN_NAME,
|
||||
field: options?.breakdown.field,
|
||||
options: {
|
||||
...options.breakdown.params,
|
||||
},
|
||||
}),
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
getLayer(
|
||||
layerId: string,
|
||||
accessorId: string,
|
||||
chartDataView: DataView,
|
||||
formulaAPI: FormulaPublicApi
|
||||
): FormBasedPersistedState['layers'] {
|
||||
const columnOrder: string[] = [];
|
||||
if (this.layerConfig.options?.breakdown?.type === 'top_values') {
|
||||
columnOrder.push(BREAKDOWN_COLUMN_NAME);
|
||||
}
|
||||
if (this.layerConfig.options?.buckets?.type === 'date_histogram') {
|
||||
columnOrder.push(HISTOGRAM_COLUMN_NAME);
|
||||
}
|
||||
|
||||
const baseLayer: PersistedIndexPatternLayer = {
|
||||
columnOrder,
|
||||
columns: {
|
||||
...this.getBaseLayer(
|
||||
this.layerConfig.dataView ?? chartDataView,
|
||||
this.layerConfig.options ?? {}
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
[layerId]: this.column.reduce(
|
||||
(acc, curr, index) => ({
|
||||
...acc,
|
||||
...curr.getData(
|
||||
`${accessorId}_${index}`,
|
||||
acc,
|
||||
this.layerConfig.dataView ?? chartDataView,
|
||||
formulaAPI
|
||||
),
|
||||
}),
|
||||
baseLayer
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
getReference(layerId: string, chartDataView: DataView): SavedObjectReference[] {
|
||||
return getDefaultReferences(this.layerConfig.dataView ?? chartDataView, layerId);
|
||||
}
|
||||
|
||||
getLayerConfig(layerId: string, accessorId: string): XYDataLayerConfig {
|
||||
return {
|
||||
layerId,
|
||||
seriesType: this.layerConfig.options?.seriesType ?? 'line',
|
||||
accessors: this.column.map((_, index) => `${accessorId}_${index}`),
|
||||
yConfig: this.layerConfig.data
|
||||
.map(({ color }, index) =>
|
||||
color ? { forAccessor: `${accessorId}_${index}`, color } : undefined
|
||||
)
|
||||
.filter(nonNullable),
|
||||
layerType: 'data',
|
||||
xAccessor:
|
||||
this.layerConfig.options?.buckets?.type === 'date_histogram'
|
||||
? HISTOGRAM_COLUMN_NAME
|
||||
: undefined,
|
||||
splitAccessor:
|
||||
this.layerConfig.options?.breakdown?.type === 'top_values'
|
||||
? BREAKDOWN_COLUMN_NAME
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
getDataView(): DataView | undefined {
|
||||
return this.layerConfig.dataView;
|
||||
}
|
||||
}
|
|
@ -1,8 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { SavedObjectReference } from '@kbn/core/server';
|
||||
|
@ -12,42 +13,42 @@ import type {
|
|||
PersistedIndexPatternLayer,
|
||||
XYReferenceLineLayerConfig,
|
||||
} from '@kbn/lens-plugin/public';
|
||||
import type { ChartColumn, ChartLayer, FormulaConfig } from '../../../types';
|
||||
import type { ChartLayer, StaticValueConfig, StaticChartColumn } from '../../types';
|
||||
import { getDefaultReferences } from '../../utils';
|
||||
import { ReferenceLineColumn } from './column/reference_line';
|
||||
import { ReferenceLineColumn } from './columns/reference_line';
|
||||
|
||||
interface XYReferenceLinesLayerConfig {
|
||||
data: FormulaConfig[];
|
||||
data: StaticValueConfig[];
|
||||
/**
|
||||
* It is possible to define a specific dataView for the layer. It will override the global chart one
|
||||
**/
|
||||
dataView?: DataView;
|
||||
}
|
||||
|
||||
export class XYReferenceLinesLayer implements ChartLayer<XYReferenceLineLayerConfig> {
|
||||
private column: ChartColumn[];
|
||||
constructor(layerConfig: XYReferenceLinesLayerConfig) {
|
||||
private column: StaticChartColumn[];
|
||||
constructor(private layerConfig: XYReferenceLinesLayerConfig) {
|
||||
this.column = layerConfig.data.map((p) => new ReferenceLineColumn(p));
|
||||
}
|
||||
|
||||
getName(): string | undefined {
|
||||
return this.column[0].getFormulaConfig().label;
|
||||
return this.column[0].getValueConfig().label;
|
||||
}
|
||||
|
||||
getLayer(
|
||||
layerId: string,
|
||||
accessorId: string,
|
||||
dataView: DataView
|
||||
): FormBasedPersistedState['layers'] {
|
||||
getLayer(layerId: string, accessorId: string): FormBasedPersistedState['layers'] {
|
||||
const baseLayer = { columnOrder: [], columns: {} } as PersistedIndexPatternLayer;
|
||||
return {
|
||||
[`${layerId}_reference`]: this.column.reduce((acc, curr, index) => {
|
||||
return {
|
||||
...acc,
|
||||
...curr.getData(`${accessorId}_${index}_reference_column`, acc, dataView),
|
||||
...curr.getData(`${accessorId}_${index}_reference_column`, acc),
|
||||
};
|
||||
}, baseLayer),
|
||||
};
|
||||
}
|
||||
|
||||
getReference(layerId: string, dataView: DataView): SavedObjectReference[] {
|
||||
return getDefaultReferences(dataView, `${layerId}_reference`);
|
||||
getReference(layerId: string, chartDataView: DataView): SavedObjectReference[] {
|
||||
return getDefaultReferences(this.layerConfig.dataView ?? chartDataView, `${layerId}_reference`);
|
||||
}
|
||||
|
||||
getLayerConfig(layerId: string, accessorId: string): XYReferenceLineLayerConfig {
|
||||
|
@ -56,10 +57,14 @@ export class XYReferenceLinesLayer implements ChartLayer<XYReferenceLineLayerCon
|
|||
layerType: 'referenceLine',
|
||||
accessors: this.column.map((_, index) => `${accessorId}_${index}_reference_column`),
|
||||
yConfig: this.column.map((layer, index) => ({
|
||||
color: layer.getFormulaConfig().color,
|
||||
color: layer.getValueConfig().color,
|
||||
forAccessor: `${accessorId}_${index}_reference_column`,
|
||||
axisMode: 'left',
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
getDataView(): DataView | undefined {
|
||||
return this.layerConfig.dataView;
|
||||
}
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { FormBasedPersistedState, MetricVisualizationState } from '@kbn/lens-plugin/public';
|
||||
import type { SavedObjectReference } from '@kbn/core/server';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { Chart, ChartConfig, ChartLayer } from '../types';
|
||||
import { DEFAULT_LAYER_ID } from '../utils';
|
||||
|
||||
import type { Chart, ChartConfig, ChartLayer } from '../../types';
|
||||
|
||||
const ACCESSOR = 'metric_formula_accessor';
|
||||
|
||||
export class MetricChart implements Chart<MetricVisualizationState> {
|
||||
|
@ -22,7 +22,12 @@ export class MetricChart implements Chart<MetricVisualizationState> {
|
|||
}
|
||||
|
||||
getLayers(): FormBasedPersistedState['layers'] {
|
||||
return this.chartConfig.layers.getLayer(DEFAULT_LAYER_ID, ACCESSOR, this.chartConfig.dataView);
|
||||
return this.chartConfig.layers.getLayer(
|
||||
DEFAULT_LAYER_ID,
|
||||
ACCESSOR,
|
||||
this.chartConfig.dataView,
|
||||
this.chartConfig.formulaAPI
|
||||
);
|
||||
}
|
||||
|
||||
getVisualizationState(): MetricVisualizationState {
|
||||
|
@ -33,8 +38,10 @@ export class MetricChart implements Chart<MetricVisualizationState> {
|
|||
return this.chartConfig.layers.getReference(DEFAULT_LAYER_ID, this.chartConfig.dataView);
|
||||
}
|
||||
|
||||
getDataView(): DataView {
|
||||
return this.chartConfig.dataView;
|
||||
getDataViews(): DataView[] {
|
||||
return [this.chartConfig.dataView, this.chartConfig.layers.getDataView()].filter(
|
||||
(x): x is DataView => !!x
|
||||
);
|
||||
}
|
||||
|
||||
getTitle(): string {
|
|
@ -1,8 +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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type {
|
||||
|
@ -13,8 +14,8 @@ import type {
|
|||
} from '@kbn/lens-plugin/public';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { SavedObjectReference } from '@kbn/core/server';
|
||||
import type { Chart, ChartConfig, ChartLayer } from '../types';
|
||||
import { DEFAULT_LAYER_ID } from '../utils';
|
||||
import type { Chart, ChartConfig, ChartLayer } from '../../types';
|
||||
|
||||
const ACCESSOR = 'formula_accessor';
|
||||
|
||||
|
@ -27,6 +28,7 @@ export interface XYVisualOptions {
|
|||
}
|
||||
|
||||
export class XYChart implements Chart<XYState> {
|
||||
private _layers: Array<ChartLayer<XYLayerConfig>> | null = null;
|
||||
constructor(
|
||||
private chartConfig: ChartConfig<Array<ChartLayer<XYLayerConfig>>> & {
|
||||
visualOptions?: XYVisualOptions;
|
||||
|
@ -37,13 +39,28 @@ export class XYChart implements Chart<XYState> {
|
|||
return 'lnsXY';
|
||||
}
|
||||
|
||||
private get layers() {
|
||||
if (!this._layers) {
|
||||
this._layers = Array.isArray(this.chartConfig.layers)
|
||||
? this.chartConfig.layers
|
||||
: [this.chartConfig.layers];
|
||||
}
|
||||
|
||||
return this._layers;
|
||||
}
|
||||
|
||||
getLayers(): FormBasedPersistedState['layers'] {
|
||||
return this.chartConfig.layers.reduce((acc, curr, index) => {
|
||||
return this.layers.reduce((acc, curr, index) => {
|
||||
const layerId = `${DEFAULT_LAYER_ID}_${index}`;
|
||||
const accessorId = `${ACCESSOR}_${index}`;
|
||||
return {
|
||||
...acc,
|
||||
...curr.getLayer(layerId, accessorId, this.chartConfig.dataView),
|
||||
...curr.getLayer(
|
||||
layerId,
|
||||
accessorId,
|
||||
this.chartConfig.dataView,
|
||||
this.chartConfig.formulaAPI
|
||||
),
|
||||
};
|
||||
}, {});
|
||||
}
|
||||
|
@ -59,26 +76,29 @@ export class XYChart implements Chart<XYState> {
|
|||
}),
|
||||
],
|
||||
}),
|
||||
fittingFunction: this.chartConfig.visualOptions?.missingValues ?? 'Zero',
|
||||
fittingFunction: this.chartConfig.visualOptions?.missingValues ?? 'None',
|
||||
endValue: this.chartConfig.visualOptions?.endValues,
|
||||
curveType: this.chartConfig.visualOptions?.lineInterpolation ?? 'LINEAR',
|
||||
curveType: this.chartConfig.visualOptions?.lineInterpolation,
|
||||
emphasizeFitting: !this.chartConfig.visualOptions?.showDottedLine,
|
||||
};
|
||||
}
|
||||
|
||||
getReferences(): SavedObjectReference[] {
|
||||
return this.chartConfig.layers.flatMap((p, index) => {
|
||||
return this.layers.flatMap((p, index) => {
|
||||
const layerId = `${DEFAULT_LAYER_ID}_${index}`;
|
||||
return p.getReference(layerId, this.chartConfig.dataView);
|
||||
});
|
||||
}
|
||||
|
||||
getDataView(): DataView {
|
||||
return this.chartConfig.dataView;
|
||||
getDataViews(): DataView[] {
|
||||
return [
|
||||
this.chartConfig.dataView,
|
||||
...this.chartConfig.layers.map((p) => p.getDataView()).filter((x): x is DataView => !!x),
|
||||
];
|
||||
}
|
||||
|
||||
getTitle(): string {
|
||||
return this.chartConfig.title ?? this.chartConfig.layers[0].getName() ?? '';
|
||||
return this.chartConfig.title ?? this.layers[0].getName() ?? '';
|
||||
}
|
||||
}
|
||||
|
27
packages/kbn-lens-embeddable-utils/index.ts
Normal file
27
packages/kbn-lens-embeddable-utils/index.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export * from './attribute_builder/types';
|
||||
|
||||
export type {
|
||||
MetricLayerOptions,
|
||||
XYLayerOptions,
|
||||
XYVisualOptions,
|
||||
} from './attribute_builder/visualization_types';
|
||||
|
||||
export {
|
||||
FormulaDataColumn,
|
||||
MetricChart,
|
||||
MetricLayer,
|
||||
ReferenceLineColumn,
|
||||
XYChart,
|
||||
XYDataLayer,
|
||||
XYReferenceLinesLayer,
|
||||
} from './attribute_builder/visualization_types';
|
||||
|
||||
export { LensAttributesBuilder } from './attribute_builder/lens_attributes_builder';
|
14
packages/kbn-lens-embeddable-utils/jest.config.js
Normal file
14
packages/kbn-lens-embeddable-utils/jest.config.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../..',
|
||||
roots: ['<rootDir>/packages/kbn-lens-embeddable-utils'],
|
||||
setupFiles: ['jest-canvas-mock'],
|
||||
};
|
5
packages/kbn-lens-embeddable-utils/kibana.jsonc
Normal file
5
packages/kbn-lens-embeddable-utils/kibana.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type": "shared-browser",
|
||||
"id": "@kbn/lens-embeddable-utils",
|
||||
"owner": "@elastic/infra-monitoring-ui"
|
||||
}
|
6
packages/kbn-lens-embeddable-utils/package.json
Normal file
6
packages/kbn-lens-embeddable-utils/package.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "@kbn/lens-embeddable-utils",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
10
packages/kbn-lens-embeddable-utils/tsconfig.json
Normal file
10
packages/kbn-lens-embeddable-utils/tsconfig.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "target/types",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["target/**/*"],
|
||||
"kbn_references": ["@kbn/core", "@kbn/data-plugin", "@kbn/data-views-plugin", "@kbn/lens-plugin"]
|
||||
}
|
|
@ -914,6 +914,8 @@
|
|||
"@kbn/kubernetes-security-plugin/*": ["x-pack/plugins/kubernetes_security/*"],
|
||||
"@kbn/language-documentation-popover": ["packages/kbn-language-documentation-popover"],
|
||||
"@kbn/language-documentation-popover/*": ["packages/kbn-language-documentation-popover/*"],
|
||||
"@kbn/lens-embeddable-utils": ["packages/kbn-lens-embeddable-utils"],
|
||||
"@kbn/lens-embeddable-utils/*": ["packages/kbn-lens-embeddable-utils/*"],
|
||||
"@kbn/lens-plugin": ["x-pack/plugins/lens"],
|
||||
"@kbn/lens-plugin/*": ["x-pack/plugins/lens/*"],
|
||||
"@kbn/license-api-guard-plugin": ["x-pack/plugins/license_api_guard"],
|
||||
|
|
|
@ -9,14 +9,6 @@ export type {
|
|||
HostsLensFormulas,
|
||||
HostsLensMetricChartFormulas,
|
||||
HostsLensLineChartFormulas,
|
||||
LensAttributes,
|
||||
FormulaConfig,
|
||||
Chart,
|
||||
LensVisualizationState,
|
||||
} from './types';
|
||||
|
||||
export { hostLensFormulas } from './constants';
|
||||
|
||||
export * from './lens/visualization_types';
|
||||
|
||||
export { LensAttributesBuilder } from './lens/lens_attributes_builder';
|
||||
|
|
|
@ -7,13 +7,10 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { TypedLensByValueInput } from '@kbn/lens-plugin/public';
|
||||
import type { Layer } from '../../../../../hooks/use_lens_attributes';
|
||||
import { UseLensAttributesMetricLayerConfig } from '../../../../../hooks/use_lens_attributes';
|
||||
import { hostLensFormulas } from '../../../constants';
|
||||
import { TOOLTIP } from './translations';
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { MetricLayerOptions } from '../../visualization_types';
|
||||
|
||||
export const KPI_CHART_HEIGHT = 150;
|
||||
export const AVERAGE_SUBTITLE = i18n.translate(
|
||||
'xpack.infra.assetDetailsEmbeddable.overview.kpi.subtitle.average',
|
||||
|
@ -23,7 +20,7 @@ export const AVERAGE_SUBTITLE = i18n.translate(
|
|||
);
|
||||
|
||||
export interface KPIChartProps extends Pick<TypedLensByValueInput, 'id' | 'title' | 'overrides'> {
|
||||
layers: Layer<MetricLayerOptions, FormulaConfig, 'data'>;
|
||||
layers: UseLensAttributesMetricLayerConfig;
|
||||
toolTip: string;
|
||||
}
|
||||
|
||||
|
@ -36,12 +33,14 @@ export const KPI_CHARTS: KPIChartProps[] = [
|
|||
layers: {
|
||||
data: {
|
||||
...hostLensFormulas.cpuUsage,
|
||||
format: {
|
||||
...hostLensFormulas.cpuUsage.format,
|
||||
params: {
|
||||
decimals: 1,
|
||||
},
|
||||
},
|
||||
format: hostLensFormulas.cpuUsage.format
|
||||
? {
|
||||
...hostLensFormulas.cpuUsage.format,
|
||||
params: {
|
||||
decimals: 1,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
layerType: 'data',
|
||||
options: {
|
||||
|
@ -62,12 +61,14 @@ export const KPI_CHARTS: KPIChartProps[] = [
|
|||
layers: {
|
||||
data: {
|
||||
...hostLensFormulas.normalizedLoad1m,
|
||||
format: {
|
||||
...hostLensFormulas.normalizedLoad1m.format,
|
||||
params: {
|
||||
decimals: 1,
|
||||
},
|
||||
},
|
||||
format: hostLensFormulas.normalizedLoad1m.format
|
||||
? {
|
||||
...hostLensFormulas.normalizedLoad1m.format,
|
||||
params: {
|
||||
decimals: 1,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
layerType: 'data',
|
||||
options: {
|
||||
|
@ -85,12 +86,14 @@ export const KPI_CHARTS: KPIChartProps[] = [
|
|||
layers: {
|
||||
data: {
|
||||
...hostLensFormulas.memoryUsage,
|
||||
format: {
|
||||
...hostLensFormulas.memoryUsage.format,
|
||||
params: {
|
||||
decimals: 1,
|
||||
},
|
||||
},
|
||||
format: hostLensFormulas.memoryUsage.format
|
||||
? {
|
||||
...hostLensFormulas.memoryUsage.format,
|
||||
params: {
|
||||
decimals: 1,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
layerType: 'data',
|
||||
options: {
|
||||
|
@ -108,12 +111,14 @@ export const KPI_CHARTS: KPIChartProps[] = [
|
|||
layers: {
|
||||
data: {
|
||||
...hostLensFormulas.diskSpaceUsage,
|
||||
format: {
|
||||
...hostLensFormulas.diskSpaceUsage.format,
|
||||
params: {
|
||||
decimals: 1,
|
||||
},
|
||||
},
|
||||
format: hostLensFormulas.diskSpaceUsage.format
|
||||
? {
|
||||
...hostLensFormulas.diskSpaceUsage.format,
|
||||
params: {
|
||||
decimals: 1,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
layerType: 'data',
|
||||
options: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const cpuUsage: FormulaConfig = {
|
||||
export const cpuUsage: FormulaValueConfig = {
|
||||
label: 'CPU Usage',
|
||||
value: '(average(system.cpu.user.pct) + average(system.cpu.system.pct)) / max(system.cpu.cores)',
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const diskIORead: FormulaConfig = {
|
||||
export const diskIORead: FormulaValueConfig = {
|
||||
label: 'Disk Read IOPS',
|
||||
value: "counter_rate(max(system.diskio.read.count), kql='system.diskio.read.count: *')",
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const diskReadThroughput: FormulaConfig = {
|
||||
export const diskReadThroughput: FormulaValueConfig = {
|
||||
label: 'Disk Read Throughput',
|
||||
value: "counter_rate(max(system.diskio.read.bytes), kql='system.diskio.read.bytes: *')",
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const diskSpaceAvailability: FormulaConfig = {
|
||||
export const diskSpaceAvailability: FormulaValueConfig = {
|
||||
label: 'Disk Space Availability',
|
||||
value: '1 - average(system.filesystem.used.pct)',
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const diskSpaceAvailable: FormulaConfig = {
|
||||
export const diskSpaceAvailable: FormulaValueConfig = {
|
||||
label: 'Disk Space Available',
|
||||
value: 'average(system.filesystem.free)',
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const diskSpaceUsage: FormulaConfig = {
|
||||
export const diskSpaceUsage: FormulaValueConfig = {
|
||||
label: 'Disk Space Usage',
|
||||
value: 'average(system.filesystem.used.pct)',
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const diskIOWrite: FormulaConfig = {
|
||||
export const diskIOWrite: FormulaValueConfig = {
|
||||
label: 'Disk Write IOPS',
|
||||
value: "counter_rate(max(system.diskio.write.count), kql='system.diskio.write.count: *')",
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const diskWriteThroughput: FormulaConfig = {
|
||||
export const diskWriteThroughput: FormulaValueConfig = {
|
||||
label: 'Disk Write Throughput',
|
||||
value: "counter_rate(max(system.diskio.write.bytes), kql='system.diskio.write.bytes: *')",
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const hostCount: FormulaConfig = {
|
||||
export const hostCount: FormulaValueConfig = {
|
||||
label: 'Hosts',
|
||||
value: 'unique_count(host.name)',
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const logRate: FormulaConfig = {
|
||||
export const logRate: FormulaValueConfig = {
|
||||
label: 'Log Rate',
|
||||
value: 'differences(cumulative_sum(count()))',
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const memoryFree: FormulaConfig = {
|
||||
export const memoryFree: FormulaValueConfig = {
|
||||
label: 'Memory Free',
|
||||
value: 'max(system.memory.total) - average(system.memory.actual.used.bytes)',
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const memoryUsage: FormulaConfig = {
|
||||
export const memoryUsage: FormulaValueConfig = {
|
||||
label: 'Memory Usage',
|
||||
value: 'average(system.memory.actual.used.pct)',
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const normalizedLoad1m: FormulaConfig = {
|
||||
export const normalizedLoad1m: FormulaValueConfig = {
|
||||
label: 'Normalized Load',
|
||||
value: 'average(system.load.1) / max(system.load.cores)',
|
||||
format: {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const rx: FormulaConfig = {
|
||||
export const rx: FormulaValueConfig = {
|
||||
label: 'Network Inbound (RX)',
|
||||
value:
|
||||
"average(host.network.ingress.bytes) * 8 / (max(metricset.period, kql='host.network.ingress.bytes: *') / 1000)",
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { FormulaConfig } from '../../../types';
|
||||
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
|
||||
|
||||
export const tx: FormulaConfig = {
|
||||
export const tx: FormulaValueConfig = {
|
||||
label: 'Network Outbound (TX)',
|
||||
value:
|
||||
"average(host.network.egress.bytes) * 8 / (max(metricset.period, kql='host.network.egress.bytes: *') / 1000)",
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { SavedObjectReference } from '@kbn/core/server';
|
||||
import type { DataView } from '@kbn/data-views-plugin/common';
|
||||
import type {
|
||||
FormulaPublicApi,
|
||||
FormBasedPersistedState,
|
||||
PersistedIndexPatternLayer,
|
||||
XYDataLayerConfig,
|
||||
SeriesType,
|
||||
} from '@kbn/lens-plugin/public';
|
||||
import type { ChartColumn, ChartLayer, FormulaConfig } from '../../../types';
|
||||
import { getDefaultReferences, getHistogramColumn, getTopValuesColumn } from '../../utils';
|
||||
import { FormulaColumn } from './column/formula';
|
||||
|
||||
const BREAKDOWN_COLUMN_NAME = 'aggs_breakdown';
|
||||
const HISTOGRAM_COLUMN_NAME = 'x_date_histogram';
|
||||
|
||||
export interface XYLayerOptions {
|
||||
breakdown?: {
|
||||
size: number;
|
||||
sourceField: string;
|
||||
};
|
||||
seriesType?: SeriesType;
|
||||
}
|
||||
|
||||
interface XYLayerConfig {
|
||||
data: FormulaConfig[];
|
||||
options?: XYLayerOptions;
|
||||
formulaAPI: FormulaPublicApi;
|
||||
}
|
||||
|
||||
export class XYDataLayer implements ChartLayer<XYDataLayerConfig> {
|
||||
private column: ChartColumn[];
|
||||
constructor(private layerConfig: XYLayerConfig) {
|
||||
this.column = layerConfig.data.map((p) => new FormulaColumn(p, layerConfig.formulaAPI));
|
||||
}
|
||||
|
||||
getName(): string | undefined {
|
||||
return this.column[0].getFormulaConfig().label;
|
||||
}
|
||||
|
||||
getBaseLayer(dataView: DataView, options?: XYLayerOptions) {
|
||||
return {
|
||||
...getHistogramColumn({
|
||||
columnName: HISTOGRAM_COLUMN_NAME,
|
||||
overrides: {
|
||||
sourceField: dataView.timeFieldName,
|
||||
},
|
||||
}),
|
||||
...(options?.breakdown
|
||||
? {
|
||||
...getTopValuesColumn({
|
||||
columnName: BREAKDOWN_COLUMN_NAME,
|
||||
overrides: {
|
||||
sourceField: options?.breakdown.sourceField,
|
||||
breakdownSize: options?.breakdown.size,
|
||||
},
|
||||
}),
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
getLayer(
|
||||
layerId: string,
|
||||
accessorId: string,
|
||||
dataView: DataView
|
||||
): FormBasedPersistedState['layers'] {
|
||||
const baseLayer: PersistedIndexPatternLayer = {
|
||||
columnOrder: [BREAKDOWN_COLUMN_NAME, HISTOGRAM_COLUMN_NAME],
|
||||
columns: {
|
||||
...this.getBaseLayer(dataView, this.layerConfig.options),
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
[layerId]: this.column.reduce(
|
||||
(acc, curr, index) => ({
|
||||
...acc,
|
||||
...curr.getData(`${accessorId}_${index}`, acc, dataView),
|
||||
}),
|
||||
baseLayer
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
getReference(layerId: string, dataView: DataView): SavedObjectReference[] {
|
||||
return getDefaultReferences(dataView, layerId);
|
||||
}
|
||||
|
||||
getLayerConfig(layerId: string, accessorId: string): XYDataLayerConfig {
|
||||
return {
|
||||
layerId,
|
||||
seriesType: this.layerConfig.options?.seriesType ?? 'line',
|
||||
accessors: this.column.map((_, index) => `${accessorId}_${index}`),
|
||||
yConfig: [],
|
||||
layerType: 'data',
|
||||
xAccessor: HISTOGRAM_COLUMN_NAME,
|
||||
splitAccessor: this.layerConfig.options?.breakdown ? BREAKDOWN_COLUMN_NAME : undefined,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -5,75 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { SavedObjectReference } from '@kbn/core/server';
|
||||
import type { DataView } from '@kbn/data-views-plugin/common';
|
||||
import type {
|
||||
FormBasedPersistedState,
|
||||
MetricVisualizationState,
|
||||
PersistedIndexPatternLayer,
|
||||
TypedLensByValueInput,
|
||||
XYState,
|
||||
FormulaPublicApi,
|
||||
XYLayerConfig,
|
||||
} from '@kbn/lens-plugin/public';
|
||||
import { hostLensFormulas } from './constants';
|
||||
export type LensAttributes = TypedLensByValueInput['attributes'];
|
||||
|
||||
// Attributes
|
||||
export type LensVisualizationState = XYState | MetricVisualizationState;
|
||||
|
||||
export interface VisualizationAttributesBuilder {
|
||||
build(): LensAttributes;
|
||||
}
|
||||
|
||||
// Column
|
||||
export interface ChartColumn {
|
||||
getData(
|
||||
id: string,
|
||||
baseLayer: PersistedIndexPatternLayer,
|
||||
dataView: DataView
|
||||
): PersistedIndexPatternLayer;
|
||||
getFormulaConfig(): FormulaConfig;
|
||||
}
|
||||
|
||||
// Layer
|
||||
export type LensLayerConfig = XYLayerConfig | MetricVisualizationState;
|
||||
|
||||
export interface ChartLayer<TLayerConfig extends LensLayerConfig> {
|
||||
getName(): string | undefined;
|
||||
getLayer(
|
||||
layerId: string,
|
||||
accessorId: string,
|
||||
dataView: DataView
|
||||
): FormBasedPersistedState['layers'];
|
||||
getReference(layerId: string, dataView: DataView): SavedObjectReference[];
|
||||
getLayerConfig(layerId: string, acessorId: string): TLayerConfig;
|
||||
}
|
||||
|
||||
// Chart
|
||||
export interface Chart<TVisualizationState extends LensVisualizationState> {
|
||||
getTitle(): string;
|
||||
getVisualizationType(): string;
|
||||
getLayers(): FormBasedPersistedState['layers'];
|
||||
getVisualizationState(): TVisualizationState;
|
||||
getReferences(): SavedObjectReference[];
|
||||
getDataView(): DataView;
|
||||
}
|
||||
export interface ChartConfig<
|
||||
TLayer extends ChartLayer<LensLayerConfig> | Array<ChartLayer<LensLayerConfig>>
|
||||
> {
|
||||
dataView: DataView;
|
||||
layers: TLayer;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
// Formula
|
||||
type LensFormula = Parameters<FormulaPublicApi['insertOrReplaceFormulaColumn']>[1];
|
||||
export type FormulaConfig = Omit<LensFormula, 'format' | 'formula'> & {
|
||||
color?: string;
|
||||
format: NonNullable<LensFormula['format']>;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type HostsLensFormulas = keyof typeof hostLensFormulas;
|
||||
export type HostsLensMetricChartFormulas = Exclude<HostsLensFormulas, 'diskIORead' | 'diskIOWrite'>;
|
||||
|
|
|
@ -11,22 +11,17 @@ import { i18n } from '@kbn/i18n';
|
|||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { HostMetricsExplanationContent } from '../../../../lens/metric_explanation/host_metrics_explanation_content';
|
||||
import type { XYVisualOptions } from '@kbn/lens-embeddable-utils';
|
||||
import { UseLensAttributesXYLayerConfig } from '../../../../../hooks/use_lens_attributes';
|
||||
import { buildCombinedHostsFilter } from '../../../../../utils/filters/build';
|
||||
import type { Layer } from '../../../../../hooks/use_lens_attributes';
|
||||
import { LensChart, type LensChartProps } from '../../../../lens';
|
||||
import {
|
||||
type FormulaConfig,
|
||||
hostLensFormulas,
|
||||
type XYLayerOptions,
|
||||
type XYVisualOptions,
|
||||
} from '../../../../../common/visualizations';
|
||||
import { LensChart, type LensChartProps, HostMetricsExplanationContent } from '../../../../lens';
|
||||
import { hostLensFormulas } from '../../../../../common/visualizations';
|
||||
import { METRIC_CHART_HEIGHT } from '../../../constants';
|
||||
import { Popover } from '../../common/popover';
|
||||
|
||||
type DataViewOrigin = 'logs' | 'metrics';
|
||||
interface MetricChartConfig extends Pick<LensChartProps, 'id' | 'title' | 'overrides'> {
|
||||
layers: Array<Layer<XYLayerOptions, FormulaConfig[]>>;
|
||||
layers: UseLensAttributesXYLayerConfig;
|
||||
toolTip: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@ import type { TimeRange } from '@kbn/es-query';
|
|||
import { TypedLensByValueInput } from '@kbn/lens-plugin/public';
|
||||
import { css } from '@emotion/react';
|
||||
import { useEuiTheme } from '@elastic/eui';
|
||||
import { LensAttributes } from '@kbn/lens-embeddable-utils';
|
||||
import { useKibanaContextForPlugin } from '../../hooks/use_kibana';
|
||||
import { ChartLoadingProgress, ChartPlaceholder } from './chart_placeholder';
|
||||
import { parseDateRange } from '../../utils/datemath';
|
||||
import { LensAttributes } from '../../common/visualizations';
|
||||
|
||||
export type LensWrapperProps = Omit<
|
||||
TypedLensByValueInput,
|
||||
|
|
|
@ -57,9 +57,15 @@ describe('useHostTable hook', () => {
|
|||
data: [normalizedLoad1m],
|
||||
layerType: 'data',
|
||||
options: {
|
||||
buckets: {
|
||||
type: 'date_histogram',
|
||||
},
|
||||
breakdown: {
|
||||
size: 10,
|
||||
sourceField: 'host.name',
|
||||
field: 'host.name',
|
||||
type: 'top_values',
|
||||
params: {
|
||||
size: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -12,13 +12,14 @@ import { useKibana } from '@kbn/kibana-react-plugin/public';
|
|||
import type { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { FormulaPublicApi, LayerType as LensLayerType } from '@kbn/lens-plugin/public';
|
||||
import { InfraClientSetupDeps } from '../types';
|
||||
import { FormulaPublicApi } from '@kbn/lens-plugin/public';
|
||||
import {
|
||||
type XYLayerOptions,
|
||||
type MetricLayerOptions,
|
||||
type FormulaConfig,
|
||||
type FormulaValueConfig,
|
||||
type LensAttributes,
|
||||
type StaticValueConfig,
|
||||
type LensVisualizationState,
|
||||
type XYVisualOptions,
|
||||
type Chart,
|
||||
LensAttributesBuilder,
|
||||
|
@ -27,48 +28,48 @@ import {
|
|||
XYChart,
|
||||
MetricChart,
|
||||
XYReferenceLinesLayer,
|
||||
LensVisualizationState,
|
||||
} from '../common/visualizations';
|
||||
} from '@kbn/lens-embeddable-utils';
|
||||
|
||||
import { InfraClientSetupDeps } from '../types';
|
||||
import { useLazyRef } from './use_lazy_ref';
|
||||
|
||||
type LayerOptions = XYLayerOptions | MetricLayerOptions;
|
||||
type ChartType = 'lnsXY' | 'lnsMetric';
|
||||
type VisualOptions = XYVisualOptions;
|
||||
export type LayerType = Exclude<LensLayerType, 'annotations' | 'metricTrendline'>;
|
||||
type Options = XYLayerOptions | MetricLayerOptions;
|
||||
|
||||
export interface Layer<
|
||||
TLayerOptions extends LayerOptions,
|
||||
TFormulaConfig extends FormulaConfig | FormulaConfig[],
|
||||
TLayerType extends LayerType = LayerType
|
||||
> {
|
||||
layerType: TLayerType;
|
||||
data: TFormulaConfig;
|
||||
options?: TLayerOptions;
|
||||
interface StaticValueLayer {
|
||||
data: StaticValueConfig[];
|
||||
layerType: 'referenceLine';
|
||||
}
|
||||
|
||||
interface UseLensAttributesBaseParams<
|
||||
TOptions extends LayerOptions,
|
||||
TLayers extends Array<Layer<TOptions, FormulaConfig[]>> | Layer<TOptions, FormulaConfig>
|
||||
interface FormulaValueLayer<
|
||||
TOptions extends Options,
|
||||
TData extends FormulaValueConfig[] | FormulaValueConfig
|
||||
> {
|
||||
options?: TOptions;
|
||||
data: TData;
|
||||
layerType: 'data';
|
||||
}
|
||||
|
||||
type XYLayerConfig = StaticValueLayer | FormulaValueLayer<XYLayerOptions, FormulaValueConfig[]>;
|
||||
|
||||
export type UseLensAttributesXYLayerConfig = XYLayerConfig | XYLayerConfig[];
|
||||
export type UseLensAttributesMetricLayerConfig = FormulaValueLayer<
|
||||
MetricLayerOptions,
|
||||
FormulaValueConfig
|
||||
>;
|
||||
|
||||
interface UseLensAttributesBaseParams {
|
||||
dataView?: DataView;
|
||||
layers: TLayers;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
interface UseLensAttributesXYChartParams
|
||||
extends UseLensAttributesBaseParams<
|
||||
XYLayerOptions,
|
||||
Array<Layer<XYLayerOptions, FormulaConfig[], 'data' | 'referenceLine'>>
|
||||
> {
|
||||
interface UseLensAttributesXYChartParams extends UseLensAttributesBaseParams {
|
||||
layers: UseLensAttributesXYLayerConfig;
|
||||
visualizationType: 'lnsXY';
|
||||
visualOptions?: XYVisualOptions;
|
||||
}
|
||||
|
||||
interface UseLensAttributesMetricChartParams
|
||||
extends UseLensAttributesBaseParams<
|
||||
MetricLayerOptions,
|
||||
Layer<MetricLayerOptions, FormulaConfig, 'data'>
|
||||
> {
|
||||
interface UseLensAttributesMetricChartParams extends UseLensAttributesBaseParams {
|
||||
layers: UseLensAttributesMetricLayerConfig;
|
||||
visualizationType: 'lnsMetric';
|
||||
}
|
||||
|
||||
|
@ -76,13 +77,7 @@ export type UseLensAttributesParams =
|
|||
| UseLensAttributesXYChartParams
|
||||
| UseLensAttributesMetricChartParams;
|
||||
|
||||
export const useLensAttributes = ({
|
||||
dataView,
|
||||
layers,
|
||||
title,
|
||||
visualizationType,
|
||||
...extraParams
|
||||
}: UseLensAttributesParams) => {
|
||||
export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesParams) => {
|
||||
const {
|
||||
services: { lens },
|
||||
} = useKibana<InfraClientSetupDeps>();
|
||||
|
@ -99,10 +94,7 @@ export const useLensAttributes = ({
|
|||
visualization: chartFactory({
|
||||
dataView,
|
||||
formulaAPI,
|
||||
layers,
|
||||
title,
|
||||
visualizationType,
|
||||
...extraParams,
|
||||
...params,
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -163,9 +155,9 @@ export const useLensAttributes = ({
|
|||
);
|
||||
|
||||
const getFormula = () => {
|
||||
const firstDataLayer = [...(Array.isArray(layers) ? layers : [layers])].find(
|
||||
(p) => p.layerType === 'data'
|
||||
);
|
||||
const firstDataLayer = [
|
||||
...(Array.isArray(params.layers) ? params.layers : [params.layers]),
|
||||
].find((p) => p.layerType === 'data');
|
||||
|
||||
if (!firstDataLayer) {
|
||||
return '';
|
||||
|
@ -181,80 +173,70 @@ export const useLensAttributes = ({
|
|||
return { formula: getFormula(), attributes: attributes.current, getExtraActions, error };
|
||||
};
|
||||
|
||||
const chartFactory = <
|
||||
TOptions,
|
||||
TLayers extends Array<Layer<TOptions, FormulaConfig[]>> | Layer<TOptions, FormulaConfig>
|
||||
>({
|
||||
const chartFactory = ({
|
||||
dataView,
|
||||
formulaAPI,
|
||||
layers,
|
||||
title,
|
||||
visualizationType,
|
||||
visualOptions,
|
||||
...params
|
||||
}: {
|
||||
dataView: DataView;
|
||||
formulaAPI: FormulaPublicApi;
|
||||
visualizationType: ChartType;
|
||||
layers: TLayers;
|
||||
title?: string;
|
||||
visualOptions?: VisualOptions;
|
||||
}): Chart<LensVisualizationState> => {
|
||||
switch (visualizationType) {
|
||||
} & UseLensAttributesParams): Chart<LensVisualizationState> => {
|
||||
switch (params.visualizationType) {
|
||||
case 'lnsXY':
|
||||
if (!Array.isArray(layers)) {
|
||||
if (!Array.isArray(params.layers)) {
|
||||
throw new Error(`Invalid layers type. Expected an array of layers.`);
|
||||
}
|
||||
|
||||
const getLayerClass = (layerType: LayerType) => {
|
||||
switch (layerType) {
|
||||
const xyLayerFactory = (layer: XYLayerConfig) => {
|
||||
switch (layer.layerType) {
|
||||
case 'data': {
|
||||
return XYDataLayer;
|
||||
return new XYDataLayer({
|
||||
data: layer.data,
|
||||
options: layer.options,
|
||||
});
|
||||
}
|
||||
case 'referenceLine': {
|
||||
return XYReferenceLinesLayer;
|
||||
return new XYReferenceLinesLayer({
|
||||
data: layer.data,
|
||||
});
|
||||
}
|
||||
default:
|
||||
throw new Error(`Invalid layerType: ${layerType}`);
|
||||
throw new Error(`Invalid layerType`);
|
||||
}
|
||||
};
|
||||
|
||||
return new XYChart({
|
||||
dataView,
|
||||
layers: layers.map((layerItem) => {
|
||||
const Layer = getLayerClass(layerItem.layerType);
|
||||
return new Layer({
|
||||
data: layerItem.data,
|
||||
formulaAPI,
|
||||
options: layerItem.options,
|
||||
});
|
||||
formulaAPI,
|
||||
layers: params.layers.map((layerItem) => {
|
||||
return xyLayerFactory(layerItem);
|
||||
}),
|
||||
title,
|
||||
visualOptions,
|
||||
title: params.title,
|
||||
visualOptions: params.visualOptions,
|
||||
});
|
||||
|
||||
case 'lnsMetric':
|
||||
if (Array.isArray(layers)) {
|
||||
if (Array.isArray(params.layers)) {
|
||||
throw new Error(`Invalid layers type. Expected a single layer object.`);
|
||||
}
|
||||
|
||||
return new MetricChart({
|
||||
dataView,
|
||||
formulaAPI,
|
||||
layers: new MetricLayer({
|
||||
data: layers.data,
|
||||
formulaAPI,
|
||||
options: layers.options,
|
||||
data: params.layers.data,
|
||||
options: params.layers.options,
|
||||
}),
|
||||
title,
|
||||
title: params.title,
|
||||
});
|
||||
default:
|
||||
throw new Error(`Unsupported chart type: ${visualizationType}`);
|
||||
throw new Error(`Unsupported chart type`);
|
||||
}
|
||||
};
|
||||
|
||||
const getOpenInLensAction = (onExecute: () => void): Action => {
|
||||
return {
|
||||
id: 'openInLens',
|
||||
|
||||
getDisplayName(_context: ActionExecutionContext): string {
|
||||
return i18n.translate('xpack.infra.hostsViewPage.tabs.metricsCharts.actions.openInLines', {
|
||||
defaultMessage: 'Open in Lens',
|
||||
|
|
|
@ -6,15 +6,11 @@
|
|||
*/
|
||||
import React, { useMemo } from 'react';
|
||||
import type { TypedLensByValueInput } from '@kbn/lens-plugin/public';
|
||||
import type { XYVisualOptions } from '@kbn/lens-embeddable-utils';
|
||||
import { LensChart } from '../../../../../../components/lens';
|
||||
import type { Layer } from '../../../../../../hooks/use_lens_attributes';
|
||||
import type { UseLensAttributesXYLayerConfig } from '../../../../../../hooks/use_lens_attributes';
|
||||
import { useMetricsDataViewContext } from '../../../hooks/use_data_view';
|
||||
import { useUnifiedSearchContext } from '../../../hooks/use_unified_search';
|
||||
import type {
|
||||
FormulaConfig,
|
||||
XYLayerOptions,
|
||||
XYVisualOptions,
|
||||
} from '../../../../../../common/visualizations';
|
||||
import { useHostsViewContext } from '../../../hooks/use_hosts_view';
|
||||
import { buildCombinedHostsFilter } from '../../../../../../utils/filters/build';
|
||||
import { useHostsTableContext } from '../../../hooks/use_hosts_table';
|
||||
|
@ -23,7 +19,7 @@ import { METRIC_CHART_HEIGHT } from '../../../constants';
|
|||
|
||||
export interface MetricChartProps extends Pick<TypedLensByValueInput, 'id' | 'overrides'> {
|
||||
title: string;
|
||||
layers: Array<Layer<XYLayerOptions, FormulaConfig[]>>;
|
||||
layers: UseLensAttributesXYLayerConfig;
|
||||
visualOptions?: XYVisualOptions;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,15 +6,10 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
|
||||
import { EuiFlexGrid, EuiFlexItem, EuiText } from '@elastic/eui';
|
||||
import { EuiFlexGrid, EuiFlexItem, EuiText, EuiFlexGroup, EuiSpacer } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { EuiFlexGroup } from '@elastic/eui';
|
||||
import {
|
||||
hostLensFormulas,
|
||||
type XYVisualOptions,
|
||||
type XYLayerOptions,
|
||||
} from '../../../../../../common/visualizations';
|
||||
import type { XYLayerOptions, XYVisualOptions } from '@kbn/lens-embeddable-utils';
|
||||
import { hostLensFormulas } from '../../../../../../common/visualizations';
|
||||
import { HostMetricsExplanationContent } from '../../../../../../components/lens';
|
||||
import { MetricChart, MetricChartProps } from './metric_chart';
|
||||
import { Popover } from '../../table/popover';
|
||||
|
@ -22,8 +17,11 @@ import { Popover } from '../../table/popover';
|
|||
const DEFAULT_BREAKDOWN_SIZE = 20;
|
||||
const XY_LAYER_OPTIONS: XYLayerOptions = {
|
||||
breakdown: {
|
||||
size: DEFAULT_BREAKDOWN_SIZE,
|
||||
sourceField: 'host.name',
|
||||
type: 'top_values',
|
||||
field: 'host.name',
|
||||
params: {
|
||||
size: DEFAULT_BREAKDOWN_SIZE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
"@kbn/logs-shared-plugin",
|
||||
"@kbn/licensing-plugin",
|
||||
"@kbn/aiops-utils",
|
||||
"@kbn/lens-embeddable-utils"
|
||||
],
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
|
@ -5984,6 +5984,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/lens-embeddable-utils@link:packages/kbn-lens-embeddable-utils":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/visualizations-plugin@link:src/plugins/visualizations":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue