[Exploratory view] Update types names (#103214)

This commit is contained in:
Shahzad 2021-06-28 15:55:53 +02:00 committed by GitHub
parent 2ff2a6fa50
commit 4f45535c90
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 548 additions and 705 deletions

View file

@ -1,53 +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 { ConfigProps, DataSeries } from '../../types';
import { FieldLabels } from '../constants';
import { buildPhraseFilter } from '../utils';
import { TRANSACTION_DURATION } from '../constants/elasticsearch_fieldnames';
export function getServiceLatencyLensConfig({ indexPattern }: ConfigProps): DataSeries {
return {
reportType: 'kpi-over-time',
defaultSeriesType: 'line',
seriesTypes: ['line', 'bar'],
xAxisColumn: {
sourceField: '@timestamp',
},
yAxisColumns: [
{
operationType: 'average',
sourceField: 'transaction.duration.us',
label: 'Latency',
},
],
hasOperationType: true,
defaultFilters: [
'user_agent.name',
'user_agent.os.name',
'client.geo.country_name',
'user_agent.device.name',
],
breakdowns: [
'user_agent.name',
'user_agent.os.name',
'client.geo.country_name',
'user_agent.device.name',
],
filters: buildPhraseFilter('transaction.type', 'request', indexPattern),
labels: { ...FieldLabels, [TRANSACTION_DURATION]: 'Latency' },
reportDefinitions: [
{
field: 'service.name',
required: true,
},
{
field: 'service.environment',
},
],
};
}

View file

@ -96,3 +96,5 @@ export const USE_BREAK_DOWN_COLUMN = 'USE_BREAK_DOWN_COLUMN';
export const FILTER_RECORDS = 'FILTER_RECORDS';
export const TERMS_COLUMN = 'TERMS_COLUMN';
export const OPERATION_COLUMN = 'operation';
export const REPORT_METRIC_FIELD = 'REPORT_METRIC_FIELD';

View file

@ -13,4 +13,5 @@ export enum URL_KEYS {
BREAK_DOWN = 'bd',
FILTERS = 'ft',
REPORT_DEFINITIONS = 'rdf',
SELECTED_METRIC = 'mt',
}

View file

@ -9,8 +9,14 @@ import { LayerConfig, LensAttributes } from './lens_attributes';
import { mockAppIndexPattern, mockIndexPattern } from '../rtl_helpers';
import { getDefaultConfigs } from './default_configs';
import { sampleAttribute } from './test_data/sample_attribute';
import { LCP_FIELD, USER_AGENT_NAME } from './constants/elasticsearch_fieldnames';
import {
LCP_FIELD,
TRANSACTION_DURATION,
USER_AGENT_NAME,
} from './constants/elasticsearch_fieldnames';
import { buildExistsFilter, buildPhrasesFilter } from './utils';
import { sampleAttributeKpi } from './test_data/sample_attribute_kpi';
import { REPORT_METRIC_FIELD } from './constants';
describe('Lens Attribute', () => {
mockAppIndexPattern();
@ -21,12 +27,12 @@ describe('Lens Attribute', () => {
indexPattern: mockIndexPattern,
});
reportViewConfig.filters?.push(...buildExistsFilter('transaction.type', mockIndexPattern));
reportViewConfig.baseFilters?.push(...buildExistsFilter('transaction.type', mockIndexPattern));
let lnsAttr: LensAttributes;
const layerConfig: LayerConfig = {
reportConfig: reportViewConfig,
seriesConfig: reportViewConfig,
seriesType: 'line',
operationType: 'count',
indexPattern: mockIndexPattern,
@ -42,6 +48,27 @@ describe('Lens Attribute', () => {
expect(lnsAttr.getJSON()).toEqual(sampleAttribute);
});
it('should return expected json for kpi report type', function () {
const seriesConfigKpi = getDefaultConfigs({
reportType: 'kpi-over-time',
dataType: 'ux',
indexPattern: mockIndexPattern,
});
const lnsAttrKpi = new LensAttributes([
{
seriesConfig: seriesConfigKpi,
seriesType: 'line',
operationType: 'count',
indexPattern: mockIndexPattern,
reportDefinitions: { 'service.name': ['elastic-co'] },
time: { from: 'now-15m', to: 'now' },
},
]);
expect(lnsAttrKpi.getJSON()).toEqual(sampleAttributeKpi);
});
it('should return main y axis', function () {
expect(lnsAttr.getMainYAxis(layerConfig)).toEqual({
dataType: 'number',
@ -72,7 +99,7 @@ describe('Lens Attribute', () => {
});
it('should return expected field type for custom field with default value', function () {
expect(JSON.stringify(lnsAttr.getFieldMeta('performance.metric', layerConfig))).toEqual(
expect(JSON.stringify(lnsAttr.getFieldMeta(REPORT_METRIC_FIELD, layerConfig))).toEqual(
JSON.stringify({
fieldMeta: {
count: 0,
@ -92,7 +119,7 @@ describe('Lens Attribute', () => {
it('should return expected field type for custom field with passed value', function () {
const layerConfig1: LayerConfig = {
reportConfig: reportViewConfig,
seriesConfig: reportViewConfig,
seriesType: 'line',
operationType: 'count',
indexPattern: mockIndexPattern,
@ -102,20 +129,20 @@ describe('Lens Attribute', () => {
lnsAttr = new LensAttributes([layerConfig1]);
expect(JSON.stringify(lnsAttr.getFieldMeta('performance.metric', layerConfig1))).toEqual(
expect(JSON.stringify(lnsAttr.getFieldMeta(REPORT_METRIC_FIELD, layerConfig1))).toEqual(
JSON.stringify({
fieldMeta: {
count: 0,
name: LCP_FIELD,
name: TRANSACTION_DURATION,
type: 'number',
esTypes: ['scaled_float'],
esTypes: ['long'],
scripted: false,
searchable: true,
aggregatable: true,
readFromDocValues: true,
},
fieldName: LCP_FIELD,
columnLabel: 'Largest contentful paint',
fieldName: TRANSACTION_DURATION,
columnLabel: 'Page load time',
})
);
});
@ -269,7 +296,7 @@ describe('Lens Attribute', () => {
describe('Layer breakdowns', function () {
it('should return breakdown column', function () {
const layerConfig1: LayerConfig = {
reportConfig: reportViewConfig,
seriesConfig: reportViewConfig,
seriesType: 'line',
operationType: 'count',
indexPattern: mockIndexPattern,
@ -322,7 +349,7 @@ describe('Lens Attribute', () => {
'x-axis-column-layer0': {
dataType: 'number',
isBucketed: true,
label: 'Largest contentful paint',
label: 'Page load time',
operationType: 'range',
params: {
maxBars: 'auto',
@ -330,7 +357,7 @@ describe('Lens Attribute', () => {
type: 'histogram',
},
scale: 'interval',
sourceField: 'transaction.marks.agent.largestContentfulPaint',
sourceField: 'transaction.duration.us',
},
'y-axis-column-layer0': {
dataType: 'number',
@ -353,12 +380,12 @@ describe('Lens Attribute', () => {
describe('Layer Filters', function () {
it('should return expected filters', function () {
reportViewConfig.filters?.push(
reportViewConfig.baseFilters?.push(
...buildPhrasesFilter('service.name', ['elastic', 'kibana'], mockIndexPattern)
);
const layerConfig1: LayerConfig = {
reportConfig: reportViewConfig,
seriesConfig: reportViewConfig,
seriesType: 'line',
operationType: 'count',
indexPattern: mockIndexPattern,

View file

@ -29,8 +29,14 @@ import {
} from '../../../../../../lens/public';
import { urlFiltersToKueryString } from '../utils/stringify_kueries';
import { ExistsFilter, IndexPattern } from '../../../../../../../../src/plugins/data/common';
import { FieldLabels, FILTER_RECORDS, USE_BREAK_DOWN_COLUMN, TERMS_COLUMN } from './constants';
import { ColumnFilter, DataSeries, UrlFilter, URLReportDefinition } from '../types';
import {
FieldLabels,
FILTER_RECORDS,
USE_BREAK_DOWN_COLUMN,
TERMS_COLUMN,
REPORT_METRIC_FIELD,
} from './constants';
import { ColumnFilter, SeriesConfig, UrlFilter, URLReportDefinition } from '../types';
import { PersistableFilter } from '../../../../../../lens/common';
import { parseAbsoluteDate } from '../series_date_picker/date_range_picker';
@ -47,54 +53,47 @@ function buildNumberColumn(sourceField: string) {
};
}
export const parseCustomFieldName = (
sourceField: string,
reportViewConfig: DataSeries,
selectedDefinitions: URLReportDefinition
) => {
let fieldName = sourceField;
export const parseCustomFieldName = (seriesConfig: SeriesConfig, selectedMetricField?: string) => {
let columnType;
let columnFilters;
let timeScale;
let columnLabel;
const rdf = reportViewConfig.reportDefinitions ?? [];
const metricOptions = seriesConfig.metricOptions ?? [];
const customField = rdf.find(({ field }) => field === fieldName);
if (customField) {
if (selectedDefinitions[fieldName]) {
fieldName = selectedDefinitions[fieldName][0];
if (customField?.options) {
const currField = customField?.options?.find(
({ field, id }) => field === fieldName || id === fieldName
);
columnType = currField?.columnType;
columnFilters = currField?.columnFilters;
timeScale = currField?.timeScale;
columnLabel = currField?.label;
}
} else if (customField.options?.[0].field || customField.options?.[0].id) {
fieldName = customField.options?.[0].field || customField.options?.[0].id;
columnType = customField.options?.[0].columnType;
columnFilters = customField.options?.[0].columnFilters;
timeScale = customField.options?.[0].timeScale;
columnLabel = customField.options?.[0].label;
if (selectedMetricField) {
if (metricOptions) {
const currField = metricOptions.find(
({ field, id }) => field === selectedMetricField || id === selectedMetricField
);
columnType = currField?.columnType;
columnFilters = currField?.columnFilters;
timeScale = currField?.timeScale;
columnLabel = currField?.label;
}
} else if (metricOptions?.[0].field || metricOptions?.[0].id) {
const firstMetricOption = metricOptions?.[0];
selectedMetricField = firstMetricOption.field || firstMetricOption.id;
columnType = firstMetricOption.columnType;
columnFilters = firstMetricOption.columnFilters;
timeScale = firstMetricOption.timeScale;
columnLabel = firstMetricOption.label;
}
return { fieldName, columnType, columnFilters, timeScale, columnLabel };
return { fieldName: selectedMetricField!, columnType, columnFilters, timeScale, columnLabel };
};
export interface LayerConfig {
filters?: UrlFilter[];
reportConfig: DataSeries;
seriesConfig: SeriesConfig;
breakdown?: string;
seriesType?: SeriesType;
operationType?: OperationType;
reportDefinitions: URLReportDefinition;
time: { to: string; from: string };
indexPattern: IndexPattern;
selectedMetricField?: string;
}
export class LensAttributes {
@ -105,9 +104,9 @@ export class LensAttributes {
constructor(layerConfigs: LayerConfig[]) {
this.layers = {};
layerConfigs.forEach(({ reportConfig, operationType }) => {
layerConfigs.forEach(({ seriesConfig, operationType }) => {
if (operationType) {
reportConfig.yAxisColumns.forEach((yAxisColumn) => {
seriesConfig.yAxisColumns.forEach((yAxisColumn) => {
if (typeof yAxisColumn.operationType !== undefined) {
yAxisColumn.operationType = operationType as FieldBasedIndexPatternColumn['operationType'];
}
@ -150,12 +149,12 @@ export class LensAttributes {
getNumberRangeColumn(
sourceField: string,
reportViewConfig: DataSeries,
seriesConfig: SeriesConfig,
label?: string
): RangeIndexPatternColumn {
return {
sourceField,
label: reportViewConfig.labels[sourceField] ?? label,
label: seriesConfig.labels[sourceField] ?? label,
dataType: 'number',
operationType: 'range',
isBucketed: true,
@ -171,22 +170,22 @@ export class LensAttributes {
getCardinalityColumn({
sourceField,
label,
reportViewConfig,
seriesConfig,
}: {
sourceField: string;
label?: string;
reportViewConfig: DataSeries;
seriesConfig: SeriesConfig;
}) {
return this.getNumberOperationColumn({
sourceField,
operationType: 'unique_count',
label,
reportViewConfig,
seriesConfig,
});
}
getNumberColumn({
reportViewConfig,
seriesConfig,
label,
sourceField,
columnType,
@ -196,7 +195,7 @@ export class LensAttributes {
columnType?: string;
operationType?: string;
label?: string;
reportViewConfig: DataSeries;
seriesConfig: SeriesConfig;
}) {
if (columnType === 'operation' || operationType) {
if (
@ -209,26 +208,26 @@ export class LensAttributes {
sourceField,
operationType,
label,
reportViewConfig,
seriesConfig,
});
}
if (operationType?.includes('th')) {
return this.getPercentileNumberColumn(sourceField, operationType, reportViewConfig!);
return this.getPercentileNumberColumn(sourceField, operationType, seriesConfig!);
}
}
return this.getNumberRangeColumn(sourceField, reportViewConfig!, label);
return this.getNumberRangeColumn(sourceField, seriesConfig!, label);
}
getNumberOperationColumn({
sourceField,
label,
reportViewConfig,
seriesConfig,
operationType,
}: {
sourceField: string;
operationType: 'average' | 'median' | 'sum' | 'unique_count';
label?: string;
reportViewConfig: DataSeries;
seriesConfig: SeriesConfig;
}):
| AvgIndexPatternColumn
| MedianIndexPatternColumn
@ -239,7 +238,7 @@ export class LensAttributes {
label: i18n.translate('xpack.observability.expView.columns.operation.label', {
defaultMessage: '{operationType} of {sourceField}',
values: {
sourceField: label || reportViewConfig.labels[sourceField],
sourceField: label || seriesConfig.labels[sourceField],
operationType: capitalize(operationType),
},
}),
@ -250,13 +249,13 @@ export class LensAttributes {
getPercentileNumberColumn(
sourceField: string,
percentileValue: string,
reportViewConfig: DataSeries
seriesConfig: SeriesConfig
): PercentileIndexPatternColumn {
return {
...buildNumberColumn(sourceField),
label: i18n.translate('xpack.observability.expView.columns.label', {
defaultMessage: '{percentileValue} percentile of {sourceField}',
values: { sourceField: reportViewConfig.labels[sourceField], percentileValue },
values: { sourceField: seriesConfig.labels[sourceField], percentileValue },
}),
operationType: 'percentile',
params: { percentile: Number(percentileValue.split('th')[0]) },
@ -295,13 +294,13 @@ export class LensAttributes {
}
getXAxis(layerConfig: LayerConfig, layerId: string) {
const { xAxisColumn } = layerConfig.reportConfig;
const { xAxisColumn } = layerConfig.seriesConfig;
if (xAxisColumn?.sourceField === USE_BREAK_DOWN_COLUMN) {
return this.getBreakdownColumn({
layerId,
indexPattern: layerConfig.indexPattern,
sourceField: layerConfig.breakdown || layerConfig.reportConfig.breakdowns[0],
sourceField: layerConfig.breakdown || layerConfig.seriesConfig.breakdownFields[0],
});
}
@ -333,6 +332,7 @@ export class LensAttributes {
timeScale,
columnFilters,
} = this.getFieldMeta(sourceField, layerConfig);
const { type: fieldType } = fieldMeta ?? {};
if (columnType === TERMS_COLUMN) {
@ -356,14 +356,14 @@ export class LensAttributes {
columnType,
operationType,
label: columnLabel || label,
reportViewConfig: layerConfig.reportConfig,
seriesConfig: layerConfig.seriesConfig,
});
}
if (operationType === 'unique_count') {
return this.getCardinalityColumn({
sourceField: fieldName,
label: columnLabel || label,
reportViewConfig: layerConfig.reportConfig,
seriesConfig: layerConfig.seriesConfig,
});
}
@ -378,32 +378,26 @@ export class LensAttributes {
sourceField: string;
layerConfig: LayerConfig;
}) {
return parseCustomFieldName(
sourceField,
layerConfig.reportConfig,
layerConfig.reportDefinitions
);
return parseCustomFieldName(layerConfig.seriesConfig, sourceField);
}
getFieldMeta(sourceField: string, layerConfig: LayerConfig) {
const {
fieldName,
columnType,
columnLabel,
columnFilters,
timeScale,
} = this.getCustomFieldName({
sourceField,
layerConfig,
});
if (sourceField === REPORT_METRIC_FIELD) {
const { fieldName, columnType, columnLabel, columnFilters, timeScale } = parseCustomFieldName(
layerConfig.seriesConfig,
layerConfig.selectedMetricField
);
const fieldMeta = layerConfig.indexPattern.getFieldByName(fieldName!);
return { fieldMeta, fieldName, columnType, columnLabel, columnFilters, timeScale };
} else {
const fieldMeta = layerConfig.indexPattern.getFieldByName(sourceField);
const fieldMeta = layerConfig.indexPattern.getFieldByName(fieldName);
return { fieldMeta, fieldName, columnType, columnLabel, columnFilters, timeScale };
return { fieldMeta, fieldName: sourceField };
}
}
getMainYAxis(layerConfig: LayerConfig) {
const { sourceField, operationType, label } = layerConfig.reportConfig.yAxisColumns[0];
const { sourceField, operationType, label } = layerConfig.seriesConfig.yAxisColumns[0];
if (sourceField === 'Records' || !sourceField) {
return this.getRecordsColumn(label);
@ -420,7 +414,7 @@ export class LensAttributes {
getChildYAxises(layerConfig: LayerConfig) {
const lensColumns: Record<string, FieldBasedIndexPatternColumn | SumIndexPatternColumn> = {};
const yAxisColumns = layerConfig.reportConfig.yAxisColumns;
const yAxisColumns = layerConfig.seriesConfig.yAxisColumns;
// 1 means there is only main y axis
if (yAxisColumns.length === 1) {
return lensColumns;
@ -460,7 +454,7 @@ export class LensAttributes {
const {
filters,
time: { from, to },
reportConfig: { filters: layerFilters, reportType },
seriesConfig: { baseFilters: layerFilters, reportType },
} = layerConfig;
let baseFilters = '';
if (reportType !== 'kpi-over-time' && totalLayers > 1) {
@ -522,7 +516,7 @@ export class LensAttributes {
}
getTimeShift(mainLayerConfig: LayerConfig, layerConfig: LayerConfig, index: number) {
if (index === 0 || mainLayerConfig.reportConfig.reportType !== 'kpi-over-time') {
if (index === 0 || mainLayerConfig.seriesConfig.reportType !== 'kpi-over-time') {
return null;
}
@ -603,16 +597,16 @@ export class LensAttributes {
...Object.keys(this.getChildYAxises(layerConfig)),
],
layerId: `layer${index}`,
seriesType: layerConfig.seriesType || layerConfig.reportConfig.defaultSeriesType,
palette: layerConfig.reportConfig.palette,
yConfig: layerConfig.reportConfig.yConfig || [
seriesType: layerConfig.seriesType || layerConfig.seriesConfig.defaultSeriesType,
palette: layerConfig.seriesConfig.palette,
yConfig: layerConfig.seriesConfig.yConfig || [
{ forAccessor: `y-axis-column-layer${index}` },
],
xAccessor: `x-axis-column-layer${index}`,
...(layerConfig.breakdown ? { splitAccessor: `breakdown-column-layer${index}` } : {}),
})),
...(this.layerConfigs[0].reportConfig.yTitle
? { yTitle: this.layerConfigs[0].reportConfig.yTitle }
...(this.layerConfigs[0].seriesConfig.yTitle
? { yTitle: this.layerConfigs[0].seriesConfig.yTitle }
: {}),
};
}

View file

@ -1,38 +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 { DataSeries, ConfigProps } from '../../types';
import { FieldLabels } from '../constants';
export function getCPUUsageLensConfig({}: ConfigProps): DataSeries {
return {
reportType: 'kpi-over-time',
defaultSeriesType: 'line',
seriesTypes: ['line', 'bar'],
xAxisColumn: {
sourceField: '@timestamp',
},
yAxisColumns: [
{
operationType: 'average',
sourceField: 'system.cpu.user.pct',
label: 'CPU Usage %',
},
],
hasOperationType: true,
defaultFilters: [],
breakdowns: ['host.hostname'],
filters: [],
labels: { ...FieldLabels, 'host.hostname': 'Host name' },
reportDefinitions: [
{
field: 'agent.hostname',
required: true,
},
],
};
}

View file

@ -1,38 +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 { DataSeries, ConfigProps } from '../../types';
import { FieldLabels } from '../constants';
export function getMemoryUsageLensConfig({}: ConfigProps): DataSeries {
return {
reportType: 'kpi-over-time',
defaultSeriesType: 'line',
seriesTypes: ['line', 'bar'],
xAxisColumn: {
sourceField: '@timestamp',
},
yAxisColumns: [
{
operationType: 'average',
sourceField: 'system.memory.used.pct',
label: 'Memory Usage %',
},
],
hasOperationType: true,
defaultFilters: [],
breakdowns: ['host.hostname'],
filters: [],
labels: { ...FieldLabels, 'host.hostname': 'Host name' },
reportDefinitions: [
{
field: 'host.hostname',
required: true,
},
],
};
}

View file

@ -1,37 +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 { DataSeries, ConfigProps } from '../../types';
import { FieldLabels } from '../constants';
export function getNetworkActivityLensConfig({}: ConfigProps): DataSeries {
return {
reportType: 'kpi-over-time',
defaultSeriesType: 'line',
seriesTypes: ['line', 'bar'],
xAxisColumn: {
sourceField: '@timestamp',
},
yAxisColumns: [
{
operationType: 'average',
sourceField: 'system.memory.used.pct',
},
],
hasOperationType: true,
defaultFilters: [],
breakdowns: ['host.hostname'],
filters: [],
labels: { ...FieldLabels, 'host.hostname': 'Host name' },
reportDefinitions: [
{
field: 'host.hostname',
required: true,
},
],
};
}

View file

@ -5,14 +5,14 @@
* 2.0.
*/
import { ConfigProps, DataSeries } from '../../types';
import { ConfigProps, SeriesConfig } from '../../types';
import { FieldLabels, USE_BREAK_DOWN_COLUMN } from '../constants';
import { buildPhraseFilter } from '../utils';
import { SERVICE_NAME } from '../constants/elasticsearch_fieldnames';
import { MOBILE_APP, NUMBER_OF_DEVICES } from '../constants/labels';
import { MobileFields } from './mobile_fields';
export function getMobileDeviceDistributionConfig({ indexPattern }: ConfigProps): DataSeries {
export function getMobileDeviceDistributionConfig({ indexPattern }: ConfigProps): SeriesConfig {
return {
reportType: 'device-data-distribution',
defaultSeriesType: 'bar',
@ -28,9 +28,9 @@ export function getMobileDeviceDistributionConfig({ indexPattern }: ConfigProps)
},
],
hasOperationType: false,
defaultFilters: Object.keys(MobileFields),
breakdowns: Object.keys(MobileFields),
filters: [
filterFields: Object.keys(MobileFields),
breakdownFields: Object.keys(MobileFields),
baseFilters: [
...buildPhraseFilter('agent.name', 'iOS/swift', indexPattern),
...buildPhraseFilter('processor.event', 'transaction', indexPattern),
],
@ -39,11 +39,6 @@ export function getMobileDeviceDistributionConfig({ indexPattern }: ConfigProps)
...MobileFields,
[SERVICE_NAME]: MOBILE_APP,
},
reportDefinitions: [
{
field: SERVICE_NAME,
required: true,
},
],
definitionFields: [SERVICE_NAME],
};
}

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import { ConfigProps, DataSeries } from '../../types';
import { FieldLabels, OPERATION_COLUMN, RECORDS_FIELD } from '../constants';
import { ConfigProps, SeriesConfig } from '../../types';
import { FieldLabels, OPERATION_COLUMN, RECORDS_FIELD, REPORT_METRIC_FIELD } from '../constants';
import { buildPhrasesFilter } from '../utils';
import {
METRIC_SYSTEM_CPU_USAGE,
@ -19,13 +19,13 @@ import {
import { CPU_USAGE, MEMORY_USAGE, MOBILE_APP, RESPONSE_LATENCY } from '../constants/labels';
import { MobileFields } from './mobile_fields';
export function getMobileKPIDistributionConfig({ indexPattern }: ConfigProps): DataSeries {
export function getMobileKPIDistributionConfig({ indexPattern }: ConfigProps): SeriesConfig {
return {
reportType: 'data-distribution',
defaultSeriesType: 'bar',
seriesTypes: ['line', 'bar'],
xAxisColumn: {
sourceField: 'performance.metric',
sourceField: REPORT_METRIC_FIELD,
},
yAxisColumns: [
{
@ -33,9 +33,9 @@ export function getMobileKPIDistributionConfig({ indexPattern }: ConfigProps): D
},
],
hasOperationType: false,
defaultFilters: Object.keys(MobileFields),
breakdowns: Object.keys(MobileFields),
filters: [
filterFields: Object.keys(MobileFields),
breakdownFields: Object.keys(MobileFields),
baseFilters: [
...buildPhrasesFilter('agent.name', ['iOS/swift', 'open-telemetry/swift'], indexPattern),
],
labels: {
@ -43,38 +43,25 @@ export function getMobileKPIDistributionConfig({ indexPattern }: ConfigProps): D
...MobileFields,
[SERVICE_NAME]: MOBILE_APP,
},
reportDefinitions: [
definitionFields: [SERVICE_NAME, SERVICE_ENVIRONMENT],
metricOptions: [
{
field: SERVICE_NAME,
required: true,
label: RESPONSE_LATENCY,
field: TRANSACTION_DURATION,
id: TRANSACTION_DURATION,
columnType: OPERATION_COLUMN,
},
{
field: SERVICE_ENVIRONMENT,
required: true,
label: MEMORY_USAGE,
field: METRIC_SYSTEM_MEMORY_USAGE,
id: METRIC_SYSTEM_MEMORY_USAGE,
columnType: OPERATION_COLUMN,
},
{
field: 'performance.metric',
custom: true,
options: [
{
label: RESPONSE_LATENCY,
field: TRANSACTION_DURATION,
id: TRANSACTION_DURATION,
columnType: OPERATION_COLUMN,
},
{
label: MEMORY_USAGE,
field: METRIC_SYSTEM_MEMORY_USAGE,
id: METRIC_SYSTEM_MEMORY_USAGE,
columnType: OPERATION_COLUMN,
},
{
label: CPU_USAGE,
field: METRIC_SYSTEM_CPU_USAGE,
id: METRIC_SYSTEM_CPU_USAGE,
columnType: OPERATION_COLUMN,
},
],
label: CPU_USAGE,
field: METRIC_SYSTEM_CPU_USAGE,
id: METRIC_SYSTEM_CPU_USAGE,
columnType: OPERATION_COLUMN,
},
],
};

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import { ConfigProps, DataSeries } from '../../types';
import { FieldLabels, OPERATION_COLUMN, RECORDS_FIELD } from '../constants';
import { ConfigProps, SeriesConfig } from '../../types';
import { FieldLabels, OPERATION_COLUMN, RECORDS_FIELD, REPORT_METRIC_FIELD } from '../constants';
import { buildPhrasesFilter } from '../utils';
import {
METRIC_SYSTEM_CPU_USAGE,
@ -24,7 +24,7 @@ import {
} from '../constants/labels';
import { MobileFields } from './mobile_fields';
export function getMobileKPIConfig({ indexPattern }: ConfigProps): DataSeries {
export function getMobileKPIConfig({ indexPattern }: ConfigProps): SeriesConfig {
return {
reportType: 'kpi-over-time',
defaultSeriesType: 'line',
@ -34,14 +34,14 @@ export function getMobileKPIConfig({ indexPattern }: ConfigProps): DataSeries {
},
yAxisColumns: [
{
sourceField: 'business.kpi',
sourceField: REPORT_METRIC_FIELD,
operationType: 'median',
},
],
hasOperationType: true,
defaultFilters: Object.keys(MobileFields),
breakdowns: Object.keys(MobileFields),
filters: [
filterFields: Object.keys(MobileFields),
breakdownFields: Object.keys(MobileFields),
baseFilters: [
...buildPhrasesFilter('agent.name', ['iOS/swift', 'open-telemetry/swift'], indexPattern),
],
labels: {
@ -52,50 +52,37 @@ export function getMobileKPIConfig({ indexPattern }: ConfigProps): DataSeries {
[METRIC_SYSTEM_MEMORY_USAGE]: MEMORY_USAGE,
[METRIC_SYSTEM_CPU_USAGE]: CPU_USAGE,
},
reportDefinitions: [
definitionFields: [SERVICE_NAME, SERVICE_ENVIRONMENT],
metricOptions: [
{
field: SERVICE_NAME,
required: true,
label: RESPONSE_LATENCY,
field: TRANSACTION_DURATION,
id: TRANSACTION_DURATION,
columnType: OPERATION_COLUMN,
},
{
field: SERVICE_ENVIRONMENT,
required: true,
},
{
field: 'business.kpi',
custom: true,
options: [
field: RECORDS_FIELD,
id: RECORDS_FIELD,
label: TRANSACTIONS_PER_MINUTE,
columnFilters: [
{
label: RESPONSE_LATENCY,
field: TRANSACTION_DURATION,
id: TRANSACTION_DURATION,
columnType: OPERATION_COLUMN,
},
{
field: RECORDS_FIELD,
id: RECORDS_FIELD,
label: TRANSACTIONS_PER_MINUTE,
columnFilters: [
{
language: 'kuery',
query: `processor.event: transaction`,
},
],
timeScale: 'm',
},
{
label: MEMORY_USAGE,
field: METRIC_SYSTEM_MEMORY_USAGE,
id: METRIC_SYSTEM_MEMORY_USAGE,
columnType: OPERATION_COLUMN,
},
{
label: CPU_USAGE,
field: METRIC_SYSTEM_CPU_USAGE,
id: METRIC_SYSTEM_CPU_USAGE,
columnType: OPERATION_COLUMN,
language: 'kuery',
query: `processor.event: transaction`,
},
],
timeScale: 'm',
},
{
label: MEMORY_USAGE,
field: METRIC_SYSTEM_MEMORY_USAGE,
id: METRIC_SYSTEM_MEMORY_USAGE,
columnType: OPERATION_COLUMN,
},
{
label: CPU_USAGE,
field: METRIC_SYSTEM_CPU_USAGE,
id: METRIC_SYSTEM_CPU_USAGE,
columnType: OPERATION_COLUMN,
},
],
};

View file

@ -6,8 +6,13 @@
*/
import { euiPaletteForStatus } from '@elastic/eui';
import { ConfigProps, DataSeries } from '../../types';
import { FieldLabels, FILTER_RECORDS, USE_BREAK_DOWN_COLUMN } from '../constants';
import { ConfigProps, SeriesConfig } from '../../types';
import {
FieldLabels,
FILTER_RECORDS,
REPORT_METRIC_FIELD,
USE_BREAK_DOWN_COLUMN,
} from '../constants';
import { buildPhraseFilter } from '../utils';
import {
CLIENT_GEO_COUNTRY_NAME,
@ -27,7 +32,7 @@ import {
SERVICE_ENVIRONMENT,
} from '../constants/elasticsearch_fieldnames';
export function getCoreWebVitalsConfig({ indexPattern }: ConfigProps): DataSeries {
export function getCoreWebVitalsConfig({ indexPattern }: ConfigProps): SeriesConfig {
const statusPallete = euiPaletteForStatus(3);
return {
@ -39,20 +44,20 @@ export function getCoreWebVitalsConfig({ indexPattern }: ConfigProps): DataSerie
},
yAxisColumns: [
{
sourceField: 'core.web.vitals',
sourceField: REPORT_METRIC_FIELD,
label: 'Good',
},
{
sourceField: 'core.web.vitals',
sourceField: REPORT_METRIC_FIELD,
label: 'Average',
},
{
sourceField: 'core.web.vitals',
sourceField: REPORT_METRIC_FIELD,
label: 'Poor',
},
],
hasOperationType: false,
defaultFilters: [
filterFields: [
{
field: TRANSACTION_URL,
isNegated: false,
@ -69,7 +74,7 @@ export function getCoreWebVitalsConfig({ indexPattern }: ConfigProps): DataSerie
nested: USER_AGENT_VERSION,
},
],
breakdowns: [
breakdownFields: [
SERVICE_NAME,
USER_AGENT_NAME,
USER_AGENT_OS,
@ -77,79 +82,67 @@ export function getCoreWebVitalsConfig({ indexPattern }: ConfigProps): DataSerie
USER_AGENT_DEVICE,
URL_FULL,
],
filters: [
baseFilters: [
...buildPhraseFilter(TRANSACTION_TYPE, 'page-load', indexPattern),
...buildPhraseFilter(PROCESSOR_EVENT, 'transaction', indexPattern),
],
labels: { ...FieldLabels, [SERVICE_NAME]: 'Web Application' },
reportDefinitions: [
definitionFields: [SERVICE_NAME, SERVICE_ENVIRONMENT],
metricOptions: [
{
field: SERVICE_NAME,
required: true,
},
{
field: SERVICE_ENVIRONMENT,
},
{
field: 'core.web.vitals',
custom: true,
options: [
id: LCP_FIELD,
label: 'Largest contentful paint',
columnType: FILTER_RECORDS,
columnFilters: [
{
id: LCP_FIELD,
label: 'Largest contentful paint',
columnType: FILTER_RECORDS,
columnFilters: [
{
language: 'kuery',
query: `${LCP_FIELD} < 2500`,
},
{
language: 'kuery',
query: `${LCP_FIELD} > 2500 and ${LCP_FIELD} < 4000`,
},
{
language: 'kuery',
query: `${LCP_FIELD} > 4000`,
},
],
language: 'kuery',
query: `${LCP_FIELD} < 2500`,
},
{
label: 'First input delay',
id: FID_FIELD,
columnType: FILTER_RECORDS,
columnFilters: [
{
language: 'kuery',
query: `${FID_FIELD} < 100`,
},
{
language: 'kuery',
query: `${FID_FIELD} > 100 and ${FID_FIELD} < 300`,
},
{
language: 'kuery',
query: `${FID_FIELD} > 300`,
},
],
language: 'kuery',
query: `${LCP_FIELD} > 2500 and ${LCP_FIELD} < 4000`,
},
{
label: 'Cumulative layout shift',
id: CLS_FIELD,
columnType: FILTER_RECORDS,
columnFilters: [
{
language: 'kuery',
query: `${CLS_FIELD} < 0.1`,
},
{
language: 'kuery',
query: `${CLS_FIELD} > 0.1 and ${CLS_FIELD} < 0.25`,
},
{
language: 'kuery',
query: `${CLS_FIELD} > 0.25`,
},
],
language: 'kuery',
query: `${LCP_FIELD} > 4000`,
},
],
},
{
label: 'First input delay',
id: FID_FIELD,
columnType: FILTER_RECORDS,
columnFilters: [
{
language: 'kuery',
query: `${FID_FIELD} < 100`,
},
{
language: 'kuery',
query: `${FID_FIELD} > 100 and ${FID_FIELD} < 300`,
},
{
language: 'kuery',
query: `${FID_FIELD} > 300`,
},
],
},
{
label: 'Cumulative layout shift',
id: CLS_FIELD,
columnType: FILTER_RECORDS,
columnFilters: [
{
language: 'kuery',
query: `${CLS_FIELD} < 0.1`,
},
{
language: 'kuery',
query: `${CLS_FIELD} > 0.1 and ${CLS_FIELD} < 0.25`,
},
{
language: 'kuery',
query: `${CLS_FIELD} > 0.25`,
},
],
},

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import { ConfigProps, DataSeries } from '../../types';
import { FieldLabels, RECORDS_FIELD } from '../constants';
import { ConfigProps, SeriesConfig } from '../../types';
import { FieldLabels, RECORDS_FIELD, REPORT_METRIC_FIELD } from '../constants';
import { buildPhraseFilter } from '../utils';
import {
CLIENT_GEO_COUNTRY_NAME,
@ -39,13 +39,13 @@ import {
WEB_APPLICATION_LABEL,
} from '../constants/labels';
export function getRumDistributionConfig({ indexPattern }: ConfigProps): DataSeries {
export function getRumDistributionConfig({ indexPattern }: ConfigProps): SeriesConfig {
return {
reportType: 'data-distribution',
defaultSeriesType: 'line',
seriesTypes: [],
xAxisColumn: {
sourceField: 'performance.metric',
sourceField: REPORT_METRIC_FIELD,
},
yAxisColumns: [
{
@ -54,7 +54,7 @@ export function getRumDistributionConfig({ indexPattern }: ConfigProps): DataSer
},
],
hasOperationType: false,
defaultFilters: [
filterFields: [
{
field: TRANSACTION_URL,
isNegated: false,
@ -67,34 +67,22 @@ export function getRumDistributionConfig({ indexPattern }: ConfigProps): DataSer
nested: USER_AGENT_VERSION,
},
],
breakdowns: [USER_AGENT_NAME, USER_AGENT_OS, CLIENT_GEO_COUNTRY_NAME, USER_AGENT_DEVICE],
reportDefinitions: [
breakdownFields: [USER_AGENT_NAME, USER_AGENT_OS, CLIENT_GEO_COUNTRY_NAME, USER_AGENT_DEVICE],
definitionFields: [SERVICE_NAME, SERVICE_ENVIRONMENT],
metricOptions: [
{ label: PAGE_LOAD_TIME_LABEL, id: TRANSACTION_DURATION, field: TRANSACTION_DURATION },
{
field: SERVICE_NAME,
required: true,
},
{
field: SERVICE_ENVIRONMENT,
},
{
field: 'performance.metric',
custom: true,
options: [
{ label: PAGE_LOAD_TIME_LABEL, id: TRANSACTION_DURATION, field: TRANSACTION_DURATION },
{
label: BACKEND_TIME_LABEL,
id: TRANSACTION_TIME_TO_FIRST_BYTE,
field: TRANSACTION_TIME_TO_FIRST_BYTE,
},
{ label: FCP_LABEL, id: FCP_FIELD, field: FCP_FIELD },
{ label: TBT_LABEL, id: TBT_FIELD, field: TBT_FIELD },
{ label: LCP_LABEL, id: LCP_FIELD, field: LCP_FIELD },
{ label: FID_LABEL, id: FID_FIELD, field: FID_FIELD },
{ label: CLS_LABEL, id: CLS_FIELD, field: CLS_FIELD },
],
label: BACKEND_TIME_LABEL,
id: TRANSACTION_TIME_TO_FIRST_BYTE,
field: TRANSACTION_TIME_TO_FIRST_BYTE,
},
{ label: FCP_LABEL, id: FCP_FIELD, field: FCP_FIELD },
{ label: TBT_LABEL, id: TBT_FIELD, field: TBT_FIELD },
{ label: LCP_LABEL, id: LCP_FIELD, field: LCP_FIELD },
{ label: FID_LABEL, id: FID_FIELD, field: FID_FIELD },
{ label: CLS_LABEL, id: CLS_FIELD, field: CLS_FIELD },
],
filters: [
baseFilters: [
...buildPhraseFilter(TRANSACTION_TYPE, 'page-load', indexPattern),
...buildPhraseFilter(PROCESSOR_EVENT, 'transaction', indexPattern),
],

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import { ConfigProps, DataSeries } from '../../types';
import { FieldLabels, OPERATION_COLUMN, RECORDS_FIELD } from '../constants';
import { ConfigProps, SeriesConfig } from '../../types';
import { FieldLabels, OPERATION_COLUMN, RECORDS_FIELD, REPORT_METRIC_FIELD } from '../constants';
import { buildPhraseFilter } from '../utils';
import {
CLIENT_GEO_COUNTRY_NAME,
@ -39,7 +39,7 @@ import {
WEB_APPLICATION_LABEL,
} from '../constants/labels';
export function getKPITrendsLensConfig({ indexPattern }: ConfigProps): DataSeries {
export function getKPITrendsLensConfig({ indexPattern }: ConfigProps): SeriesConfig {
return {
defaultSeriesType: 'bar_stacked',
seriesTypes: [],
@ -49,12 +49,12 @@ export function getKPITrendsLensConfig({ indexPattern }: ConfigProps): DataSerie
},
yAxisColumns: [
{
sourceField: 'business.kpi',
sourceField: REPORT_METRIC_FIELD,
operationType: 'median',
},
],
hasOperationType: false,
defaultFilters: [
filterFields: [
{
field: TRANSACTION_URL,
isNegated: false,
@ -67,44 +67,32 @@ export function getKPITrendsLensConfig({ indexPattern }: ConfigProps): DataSerie
nested: USER_AGENT_VERSION,
},
],
breakdowns: [USER_AGENT_NAME, USER_AGENT_OS, CLIENT_GEO_COUNTRY_NAME, USER_AGENT_DEVICE],
filters: [
breakdownFields: [USER_AGENT_NAME, USER_AGENT_OS, CLIENT_GEO_COUNTRY_NAME, USER_AGENT_DEVICE],
baseFilters: [
...buildPhraseFilter(TRANSACTION_TYPE, 'page-load', indexPattern),
...buildPhraseFilter(PROCESSOR_EVENT, 'transaction', indexPattern),
],
labels: { ...FieldLabels, [SERVICE_NAME]: WEB_APPLICATION_LABEL },
reportDefinitions: [
definitionFields: [SERVICE_NAME, SERVICE_ENVIRONMENT],
metricOptions: [
{ field: RECORDS_FIELD, id: RECORDS_FIELD, label: PAGE_VIEWS_LABEL },
{
field: SERVICE_NAME,
required: true,
label: PAGE_LOAD_TIME_LABEL,
field: TRANSACTION_DURATION,
id: TRANSACTION_DURATION,
columnType: OPERATION_COLUMN,
},
{
field: SERVICE_ENVIRONMENT,
},
{
field: 'business.kpi',
custom: true,
options: [
{ field: RECORDS_FIELD, id: RECORDS_FIELD, label: PAGE_VIEWS_LABEL },
{
label: PAGE_LOAD_TIME_LABEL,
field: TRANSACTION_DURATION,
id: TRANSACTION_DURATION,
columnType: OPERATION_COLUMN,
},
{
label: BACKEND_TIME_LABEL,
field: TRANSACTION_TIME_TO_FIRST_BYTE,
id: TRANSACTION_TIME_TO_FIRST_BYTE,
columnType: OPERATION_COLUMN,
},
{ label: FCP_LABEL, field: FCP_FIELD, id: FCP_FIELD, columnType: OPERATION_COLUMN },
{ label: TBT_LABEL, field: TBT_FIELD, id: TBT_FIELD, columnType: OPERATION_COLUMN },
{ label: LCP_LABEL, field: LCP_FIELD, id: LCP_FIELD, columnType: OPERATION_COLUMN },
{ label: FID_LABEL, field: FID_FIELD, id: FID_FIELD, columnType: OPERATION_COLUMN },
{ label: CLS_LABEL, field: CLS_FIELD, id: CLS_FIELD, columnType: OPERATION_COLUMN },
],
label: BACKEND_TIME_LABEL,
field: TRANSACTION_TIME_TO_FIRST_BYTE,
id: TRANSACTION_TIME_TO_FIRST_BYTE,
columnType: OPERATION_COLUMN,
},
{ label: FCP_LABEL, field: FCP_FIELD, id: FCP_FIELD, columnType: OPERATION_COLUMN },
{ label: TBT_LABEL, field: TBT_FIELD, id: TBT_FIELD, columnType: OPERATION_COLUMN },
{ label: LCP_LABEL, field: LCP_FIELD, id: LCP_FIELD, columnType: OPERATION_COLUMN },
{ label: FID_LABEL, field: FID_FIELD, id: FID_FIELD, columnType: OPERATION_COLUMN },
{ label: CLS_LABEL, field: CLS_FIELD, id: CLS_FIELD, columnType: OPERATION_COLUMN },
],
};
}

View file

@ -5,18 +5,21 @@
* 2.0.
*/
import { ConfigProps, DataSeries } from '../../types';
import { FieldLabels, RECORDS_FIELD } from '../constants';
import { ConfigProps, SeriesConfig } from '../../types';
import { FieldLabels, RECORDS_FIELD, REPORT_METRIC_FIELD } from '../constants';
import { buildExistsFilter } from '../utils';
import { MONITORS_DURATION_LABEL, PINGS_LABEL } from '../constants/labels';
export function getSyntheticsDistributionConfig({ series, indexPattern }: ConfigProps): DataSeries {
export function getSyntheticsDistributionConfig({
series,
indexPattern,
}: ConfigProps): SeriesConfig {
return {
reportType: 'data-distribution',
defaultSeriesType: series?.seriesType || 'line',
seriesTypes: [],
xAxisColumn: {
sourceField: 'performance.metric',
sourceField: REPORT_METRIC_FIELD,
},
yAxisColumns: [
{
@ -25,8 +28,8 @@ export function getSyntheticsDistributionConfig({ series, indexPattern }: Config
},
],
hasOperationType: false,
defaultFilters: ['monitor.type', 'observer.geo.name', 'tags'],
breakdowns: [
filterFields: ['monitor.type', 'observer.geo.name', 'tags'],
breakdownFields: [
'observer.geo.name',
'monitor.name',
'monitor.id',
@ -34,21 +37,10 @@ export function getSyntheticsDistributionConfig({ series, indexPattern }: Config
'tags',
'url.port',
],
filters: [...buildExistsFilter('summary.up', indexPattern)],
reportDefinitions: [
{
field: 'monitor.name',
},
{
field: 'url.full',
},
{
field: 'performance.metric',
custom: true,
options: [
{ label: 'Monitor duration', id: 'monitor.duration.us', field: 'monitor.duration.us' },
],
},
baseFilters: [...buildExistsFilter('summary.up', indexPattern)],
definitionFields: ['monitor.name', 'url.full'],
metricOptions: [
{ label: 'Monitor duration', id: 'monitor.duration.us', field: 'monitor.duration.us' },
],
labels: { ...FieldLabels, 'monitor.duration.us': MONITORS_DURATION_LABEL },
};

View file

@ -5,15 +5,15 @@
* 2.0.
*/
import { ConfigProps, DataSeries } from '../../types';
import { FieldLabels, OPERATION_COLUMN } from '../constants';
import { ConfigProps, SeriesConfig } from '../../types';
import { FieldLabels, OPERATION_COLUMN, REPORT_METRIC_FIELD } from '../constants';
import { buildExistsFilter } from '../utils';
import { DOWN_LABEL, MONITORS_DURATION_LABEL, UP_LABEL } from '../constants/labels';
import { MONITOR_DURATION_US } from '../constants/field_names/synthetics';
const SUMMARY_UP = 'summary.up';
const SUMMARY_DOWN = 'summary.down';
export function getSyntheticsKPIConfig({ indexPattern }: ConfigProps): DataSeries {
export function getSyntheticsKPIConfig({ indexPattern }: ConfigProps): SeriesConfig {
return {
reportType: 'kpi-over-time',
defaultSeriesType: 'bar_stacked',
@ -23,45 +23,34 @@ export function getSyntheticsKPIConfig({ indexPattern }: ConfigProps): DataSerie
},
yAxisColumns: [
{
sourceField: 'business.kpi',
sourceField: REPORT_METRIC_FIELD,
operationType: 'median',
},
],
hasOperationType: false,
defaultFilters: ['observer.geo.name', 'monitor.type', 'tags'],
breakdowns: ['observer.geo.name', 'monitor.type'],
filters: [...buildExistsFilter('summary.up', indexPattern)],
filterFields: ['observer.geo.name', 'monitor.type', 'tags'],
breakdownFields: ['observer.geo.name', 'monitor.type'],
baseFilters: [...buildExistsFilter('summary.up', indexPattern)],
palette: { type: 'palette', name: 'status' },
reportDefinitions: [
definitionFields: ['monitor.name', 'url.full'],
metricOptions: [
{
field: 'monitor.name',
label: MONITORS_DURATION_LABEL,
field: MONITOR_DURATION_US,
id: MONITOR_DURATION_US,
columnType: OPERATION_COLUMN,
},
{
field: 'url.full',
field: SUMMARY_UP,
id: SUMMARY_UP,
label: UP_LABEL,
columnType: OPERATION_COLUMN,
},
{
field: 'business.kpi',
custom: true,
options: [
{
label: MONITORS_DURATION_LABEL,
field: MONITOR_DURATION_US,
id: MONITOR_DURATION_US,
columnType: OPERATION_COLUMN,
},
{
field: SUMMARY_UP,
id: SUMMARY_UP,
label: UP_LABEL,
columnType: OPERATION_COLUMN,
},
{
field: SUMMARY_DOWN,
id: SUMMARY_DOWN,
label: DOWN_LABEL,
columnType: OPERATION_COLUMN,
},
],
field: SUMMARY_DOWN,
id: SUMMARY_DOWN,
label: DOWN_LABEL,
columnType: OPERATION_COLUMN,
},
],
labels: { ...FieldLabels },

View file

@ -0,0 +1,71 @@
/*
* 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.
*/
export const sampleAttributeKpi = {
title: 'Prefilled from exploratory view app',
description: '',
visualizationType: 'lnsXY',
references: [
{ id: 'apm-*', name: 'indexpattern-datasource-current-indexpattern', type: 'index-pattern' },
{ id: 'apm-*', name: 'indexpattern-datasource-layer-layer0', type: 'index-pattern' },
],
state: {
datasourceStates: {
indexpattern: {
layers: {
layer0: {
columnOrder: ['x-axis-column-layer0', 'y-axis-column-layer0'],
columns: {
'x-axis-column-layer0': {
sourceField: '@timestamp',
dataType: 'date',
isBucketed: true,
label: '@timestamp',
operationType: 'date_histogram',
params: { interval: 'auto' },
scale: 'interval',
},
'y-axis-column-layer0': {
dataType: 'number',
isBucketed: false,
label: 'Page views',
operationType: 'count',
scale: 'ratio',
sourceField: 'Records',
filter: {
query: 'transaction.type: page-load and processor.event: transaction',
language: 'kuery',
},
},
},
incompleteColumns: {},
},
},
},
},
visualization: {
legend: { isVisible: true, position: 'right' },
valueLabels: 'hide',
fittingFunction: 'Linear',
curveType: 'CURVE_MONOTONE_X',
axisTitlesVisibilitySettings: { x: true, yLeft: true, yRight: true },
tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true },
gridlinesVisibilitySettings: { x: true, yLeft: true, yRight: true },
preferredSeriesType: 'line',
layers: [
{
accessors: ['y-axis-column-layer0'],
layerId: 'layer0',
seriesType: 'line',
yConfig: [{ forAccessor: 'y-axis-column-layer0' }],
xAccessor: 'x-axis-column-layer0',
},
],
},
query: { query: '', language: 'kuery' },
filters: [],
},
};

View file

@ -21,6 +21,7 @@ export function convertToShortUrl(series: SeriesUrl) {
filters,
reportDefinitions,
dataType,
selectedMetricField,
...restSeries
} = series;
@ -32,6 +33,7 @@ export function convertToShortUrl(series: SeriesUrl) {
[URL_KEYS.FILTERS]: filters,
[URL_KEYS.REPORT_DEFINITIONS]: reportDefinitions,
[URL_KEYS.DATA_TYPE]: dataType,
[URL_KEYS.SELECTED_METRIC]: selectedMetricField,
...restSeries,
};
}

View file

@ -12,25 +12,16 @@ import { LayerConfig, LensAttributes } from '../configurations/lens_attributes';
import { useSeriesStorage } from './use_series_storage';
import { getDefaultConfigs } from '../configurations/default_configs';
import { DataSeries, SeriesUrl, UrlFilter } from '../types';
import { SeriesUrl, UrlFilter } from '../types';
import { useAppIndexPatternContext } from './use_app_index_pattern';
export const getFiltersFromDefs = (
reportDefinitions: SeriesUrl['reportDefinitions'],
dataViewConfig: DataSeries
) => {
const rdfFilters = Object.entries(reportDefinitions ?? {}).map(([field, value]) => {
export const getFiltersFromDefs = (reportDefinitions: SeriesUrl['reportDefinitions']) => {
return Object.entries(reportDefinitions ?? {}).map(([field, value]) => {
return {
field,
values: value,
};
}) as UrlFilter[];
// let's filter out custom fields
return rdfFilters.filter(({ field }) => {
const rdf = dataViewConfig.reportDefinitions.find(({ field: fd }) => field === fd);
return !rdf?.custom;
});
};
export const useLensAttributes = (): TypedLensByValueInput['attributes'] | null => {
@ -49,25 +40,26 @@ export const useLensAttributes = (): TypedLensByValueInput['attributes'] | null
const seriesT = allSeries[seriesIdT];
const indexPattern = indexPatterns?.[seriesT?.dataType];
if (indexPattern && seriesT.reportType && !isEmpty(seriesT.reportDefinitions)) {
const reportViewConfig = getDefaultConfigs({
const seriesConfig = getDefaultConfigs({
reportType: seriesT.reportType,
dataType: seriesT.dataType,
indexPattern,
});
const filters: UrlFilter[] = (seriesT.filters ?? []).concat(
getFiltersFromDefs(seriesT.reportDefinitions, reportViewConfig)
getFiltersFromDefs(seriesT.reportDefinitions)
);
layerConfigs.push({
filters,
indexPattern,
reportConfig: reportViewConfig,
breakdown: seriesT.breakdown,
operationType: seriesT.operationType,
seriesType: seriesT.seriesType,
reportDefinitions: seriesT.reportDefinitions ?? {},
seriesConfig,
time: seriesT.time,
breakdown: seriesT.breakdown,
seriesType: seriesT.seriesType,
operationType: seriesT.operationType,
reportDefinitions: seriesT.reportDefinitions ?? {},
selectedMetricField: seriesT.selectedMetricField,
});
}
});

View file

@ -110,7 +110,7 @@ export function useSeriesStorage() {
}
function convertFromShortUrl(newValue: ShortUrlSeries): SeriesUrl {
const { dt, op, st, rt, bd, ft, time, rdf, ...restSeries } = newValue;
const { dt, op, st, rt, bd, ft, time, rdf, mt, ...restSeries } = newValue;
return {
operationType: op,
reportType: rt!,
@ -120,6 +120,7 @@ function convertFromShortUrl(newValue: ShortUrlSeries): SeriesUrl {
time: time!,
reportDefinitions: rdf,
dataType: dt!,
selectedMetricField: mt,
...restSeries,
};
}
@ -132,6 +133,7 @@ interface ShortUrlSeries {
[URL_KEYS.BREAK_DOWN]?: string;
[URL_KEYS.FILTERS]?: UrlFilter[];
[URL_KEYS.REPORT_DEFINITIONS]?: URLReportDefinition;
[URL_KEYS.SELECTED_METRIC]?: string;
time?: {
to: string;
from: string;

View file

@ -21,7 +21,7 @@ describe('Series Builder ReportBreakdowns', function () {
});
it('should render properly', function () {
render(<ReportBreakdowns dataViewSeries={dataViewSeries} seriesId={seriesId} />);
render(<ReportBreakdowns seriesConfig={dataViewSeries} seriesId={seriesId} />);
screen.getByText('Select an option: , is selected');
screen.getAllByText('Browser family');
@ -29,7 +29,7 @@ describe('Series Builder ReportBreakdowns', function () {
it('should set new series breakdown on change', function () {
const { setSeries } = render(
<ReportBreakdowns dataViewSeries={dataViewSeries} seriesId={seriesId} />
<ReportBreakdowns seriesConfig={dataViewSeries} seriesId={seriesId} />
);
const btn = screen.getByRole('button', {
@ -51,7 +51,7 @@ describe('Series Builder ReportBreakdowns', function () {
});
it('should set undefined on new series on no select breakdown', function () {
const { setSeries } = render(
<ReportBreakdowns dataViewSeries={dataViewSeries} seriesId={seriesId} />
<ReportBreakdowns seriesConfig={dataViewSeries} seriesId={seriesId} />
);
const btn = screen.getByRole('button', {

View file

@ -7,19 +7,19 @@
import React from 'react';
import { Breakdowns } from '../../series_editor/columns/breakdowns';
import { DataSeries } from '../../types';
import { SeriesConfig } from '../../types';
export function ReportBreakdowns({
seriesId,
dataViewSeries,
seriesConfig,
}: {
dataViewSeries: DataSeries;
seriesConfig: SeriesConfig;
seriesId: string;
}) {
return (
<Breakdowns
reportViewConfig={dataViewSeries}
breakdowns={dataViewSeries.breakdowns ?? []}
seriesConfig={seriesConfig}
breakdowns={seriesConfig.breakdownFields ?? []}
seriesId={seriesId}
/>
);

View file

@ -21,7 +21,7 @@ describe('Series Builder ReportDefinitionCol', function () {
mockAppIndexPattern();
const seriesId = 'test-series-id';
const dataViewSeries = getDefaultConfigs({
const seriesConfig = getDefaultConfigs({
reportType: 'data-distribution',
indexPattern: mockIndexPattern,
dataType: 'ux',
@ -41,7 +41,7 @@ describe('Series Builder ReportDefinitionCol', function () {
mockUseValuesList([{ label: 'elastic-co', count: 10 }]);
it('should render properly', async function () {
render(<ReportDefinitionCol dataViewSeries={dataViewSeries} seriesId={seriesId} />, {
render(<ReportDefinitionCol seriesConfig={seriesConfig} seriesId={seriesId} />, {
initSeries,
});
@ -52,7 +52,7 @@ describe('Series Builder ReportDefinitionCol', function () {
});
it('should render selected report definitions', async function () {
render(<ReportDefinitionCol dataViewSeries={dataViewSeries} seriesId={seriesId} />, {
render(<ReportDefinitionCol seriesConfig={seriesConfig} seriesId={seriesId} />, {
initSeries,
});
@ -63,7 +63,7 @@ describe('Series Builder ReportDefinitionCol', function () {
it('should be able to remove selected definition', async function () {
const { setSeries } = render(
<ReportDefinitionCol dataViewSeries={dataViewSeries} seriesId={seriesId} />,
<ReportDefinitionCol seriesConfig={seriesConfig} seriesId={seriesId} />,
{ initSeries }
);

View file

@ -9,39 +9,40 @@ import React from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui';
import styled from 'styled-components';
import { useSeriesStorage } from '../../hooks/use_series_storage';
import { CustomReportField } from '../custom_report_field';
import { DataSeries, URLReportDefinition } from '../../types';
import { ReportMetricOptions } from '../report_metric_options';
import { SeriesConfig } from '../../types';
import { SeriesChartTypesSelect } from './chart_types';
import { OperationTypeSelect } from './operation_type_select';
import { DatePickerCol } from './date_picker_col';
import { parseCustomFieldName } from '../../configurations/lens_attributes';
import { ReportDefinitionField } from './report_definition_field';
function getColumnType(dataView: DataSeries, selectedDefinition: URLReportDefinition) {
const { reportDefinitions } = dataView;
const customColumn = reportDefinitions.find((item) => item.custom);
if (customColumn?.field && selectedDefinition[customColumn?.field]) {
const { columnType } = parseCustomFieldName(customColumn.field, dataView, selectedDefinition);
function getColumnType(seriesConfig: SeriesConfig, selectedMetricField?: string) {
const { columnType } = parseCustomFieldName(seriesConfig, selectedMetricField);
return columnType;
}
return null;
return columnType;
}
export function ReportDefinitionCol({
dataViewSeries,
seriesConfig,
seriesId,
}: {
dataViewSeries: DataSeries;
seriesConfig: SeriesConfig;
seriesId: string;
}) {
const { getSeries, setSeries } = useSeriesStorage();
const series = getSeries(seriesId);
const { reportDefinitions: selectedReportDefinitions = {} } = series ?? {};
const { reportDefinitions: selectedReportDefinitions = {}, selectedMetricField } = series ?? {};
const { reportDefinitions, defaultSeriesType, hasOperationType, yAxisColumns } = dataViewSeries;
const {
definitionFields,
defaultSeriesType,
hasOperationType,
yAxisColumns,
metricOptions,
} = seriesConfig;
const onChange = (field: string, value?: string[]) => {
if (!value?.[0]) {
@ -58,7 +59,7 @@ export function ReportDefinitionCol({
}
};
const columnType = getColumnType(dataViewSeries, selectedReportDefinitions);
const columnType = getColumnType(seriesConfig, selectedMetricField);
return (
<FlexGroup direction="column" gutterSize="s">
@ -66,20 +67,21 @@ export function ReportDefinitionCol({
<DatePickerCol seriesId={seriesId} />
</EuiFlexItem>
<EuiHorizontalRule margin="xs" />
{reportDefinitions.map(({ field, custom, options }) => (
{definitionFields.map((field) => (
<EuiFlexItem key={field}>
{!custom ? (
<ReportDefinitionField
seriesId={seriesId}
dataSeries={dataViewSeries}
field={field}
onChange={onChange}
/>
) : (
<CustomReportField field={field} options={options} seriesId={seriesId} />
)}
<ReportDefinitionField
seriesId={seriesId}
seriesConfig={seriesConfig}
field={field}
onChange={onChange}
/>
</EuiFlexItem>
))}
{metricOptions && (
<EuiFlexItem>
<ReportMetricOptions options={metricOptions} seriesId={seriesId} />
</EuiFlexItem>
)}
{(hasOperationType || columnType === 'operation') && (
<EuiFlexItem>
<OperationTypeSelect
@ -92,7 +94,7 @@ export function ReportDefinitionCol({
<SeriesChartTypesSelect
seriesId={seriesId}
defaultChartType={defaultSeriesType}
seriesTypes={dataViewSeries.seriesTypes}
seriesTypes={seriesConfig.seriesTypes}
/>
</EuiFlexItem>
</FlexGroup>

View file

@ -15,16 +15,16 @@ import { ESFilter } from '../../../../../../../../../src/core/types/elasticsearc
import { PersistableFilter } from '../../../../../../../lens/common';
import { ExistsFilter } from '../../../../../../../../../src/plugins/data/common/es_query/filters';
import { buildPhrasesFilter } from '../../configurations/utils';
import { DataSeries } from '../../types';
import { SeriesConfig } from '../../types';
interface Props {
seriesId: string;
field: string;
dataSeries: DataSeries;
seriesConfig: SeriesConfig;
onChange: (field: string, value?: string[]) => void;
}
export function ReportDefinitionField({ seriesId, field, dataSeries, onChange }: Props) {
export function ReportDefinitionField({ seriesId, field, seriesConfig, onChange }: Props) {
const { getSeries } = useSeriesStorage();
const series = getSeries(seriesId);
@ -33,11 +33,11 @@ export function ReportDefinitionField({ seriesId, field, dataSeries, onChange }:
const { reportDefinitions: selectedReportDefinitions = {} } = series;
const { labels, filters, reportDefinitions } = dataSeries;
const { labels, baseFilters, definitionFields } = seriesConfig;
const queryFilters = useMemo(() => {
const filtersN: ESFilter[] = [];
(filters ?? []).forEach((qFilter: PersistableFilter | ExistsFilter) => {
(baseFilters ?? []).forEach((qFilter: PersistableFilter | ExistsFilter) => {
if (qFilter.query) {
filtersN.push(qFilter.query);
}
@ -48,8 +48,8 @@ export function ReportDefinitionField({ seriesId, field, dataSeries, onChange }:
});
if (!isEmpty(selectedReportDefinitions)) {
reportDefinitions.forEach(({ field: fieldT, custom }) => {
if (!custom && indexPattern && selectedReportDefinitions?.[fieldT] && fieldT !== field) {
definitionFields.forEach((fieldT) => {
if (indexPattern && selectedReportDefinitions?.[fieldT] && fieldT !== field) {
const values = selectedReportDefinitions?.[fieldT];
const valueFilter = buildPhrasesFilter(fieldT, values, indexPattern)[0];
filtersN.push(valueFilter.query);
@ -59,7 +59,7 @@ export function ReportDefinitionField({ seriesId, field, dataSeries, onChange }:
return filtersN;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(selectedReportDefinitions), JSON.stringify(filters)]);
}, [JSON.stringify(selectedReportDefinitions), JSON.stringify(baseFilters)]);
return (
<EuiFlexGroup justifyContent="flexStart" gutterSize="s" alignItems="center" wrap>

View file

@ -21,7 +21,7 @@ describe('Series Builder ReportFilters', function () {
});
it('should render properly', function () {
render(<ReportFilters dataViewSeries={dataViewSeries} seriesId={seriesId} />);
render(<ReportFilters seriesConfig={dataViewSeries} seriesId={seriesId} />);
screen.getByText('Add filter');
});

View file

@ -7,23 +7,23 @@
import React from 'react';
import { SeriesFilter } from '../../series_editor/columns/series_filter';
import { DataSeries } from '../../types';
import { SeriesConfig } from '../../types';
export function ReportFilters({
dataViewSeries,
seriesConfig,
seriesId,
}: {
dataViewSeries: DataSeries;
seriesConfig: SeriesConfig;
seriesId: string;
}) {
return (
<SeriesFilter
series={dataViewSeries}
defaultFilters={dataViewSeries.defaultFilters}
filters={dataViewSeries.filters}
seriesConfig={seriesConfig}
filterFields={seriesConfig.filterFields}
baseFilters={seriesConfig.baseFilters}
seriesId={seriesId}
isNew={true}
labels={dataViewSeries.labels}
labels={seriesConfig.labels}
/>
);
}

View file

@ -38,7 +38,7 @@ describe('ReportTypesCol', function () {
expect(setSeries).toHaveBeenCalledWith(seriesId, {
breakdown: 'user_agent.name',
dataType: 'ux',
reportDefinitions: {},
selectedMetricField: undefined,
reportType: 'kpi-over-time',
time: { from: 'now-15m', to: 'now' },
});

View file

@ -15,7 +15,7 @@ import { ReportViewType, SeriesUrl } from '../../types';
import { useSeriesStorage } from '../../hooks/use_series_storage';
import { DEFAULT_TIME } from '../../configurations/constants';
import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern';
import { ReportTypeItem, SELECT_DATA_TYPE } from '../series_builder';
import { ReportTypeItem } from '../series_builder';
interface Props {
seriesId: string;
@ -30,7 +30,12 @@ export function ReportTypesCol({ seriesId, reportTypes }: Props) {
const { loading, hasData } = useAppIndexPatternContext(restSeries.dataType);
if (!restSeries.dataType) {
return <span>{SELECT_DATA_TYPE}</span>;
return (
<FormattedMessage
id="xpack.observability.expView.seriesBuilder.selectDataType"
defaultMessage="No data type selected"
/>
);
}
if (!loading && !hasData) {
@ -72,8 +77,7 @@ export function ReportTypesCol({ seriesId, reportTypes }: Props) {
setSeries(seriesId, {
...restSeries,
reportType,
operationType: undefined,
reportDefinitions: {},
selectedMetricField: undefined,
time: restSeries?.time ?? DEFAULT_TIME,
});
}

View file

@ -8,28 +8,26 @@
import React from 'react';
import { EuiSuperSelect } from '@elastic/eui';
import { useSeriesStorage } from '../hooks/use_series_storage';
import { ReportDefinition } from '../types';
import { SeriesConfig } from '../types';
interface Props {
field: string;
seriesId: string;
defaultValue?: string;
options: ReportDefinition['options'];
options: SeriesConfig['metricOptions'];
}
export function CustomReportField({ field, seriesId, options: opts }: Props) {
export function ReportMetricOptions({ seriesId, options: opts }: Props) {
const { getSeries, setSeries } = useSeriesStorage();
const series = getSeries(seriesId);
const { reportDefinitions: rtd = {} } = series;
const onChange = (value: string) => {
setSeries(seriesId, { ...series, reportDefinitions: { ...rtd, [field]: [value] } });
setSeries(seriesId, {
...series,
selectedMetricField: value,
});
};
const { reportDefinitions } = series;
const options = opts ?? [];
return (
@ -41,7 +39,7 @@ export function CustomReportField({ field, seriesId, options: opts }: Props) {
value: fd || id,
inputDisplay: label,
}))}
valueOfSelected={reportDefinitions?.[field]?.[0] || options?.[0].field || options?.[0].id}
valueOfSelected={series.selectedMetricField || options?.[0].field || options?.[0].id}
onChange={(value) => onChange(value)}
/>
);

View file

@ -17,7 +17,7 @@ import {
EuiSwitch,
} from '@elastic/eui';
import { rgba } from 'polished';
import { AppDataType, DataSeries, ReportViewType, SeriesUrl } from '../types';
import { AppDataType, SeriesConfig, ReportViewType, SeriesUrl } from '../types';
import { DataTypesCol } from './columns/data_types_col';
import { ReportTypesCol } from './columns/report_types_col';
import { ReportDefinitionCol } from './columns/report_definition_col';
@ -66,7 +66,7 @@ export const ReportTypes: Record<AppDataType, ReportTypeItem[]> = {
interface BuilderItem {
id: string;
series: SeriesUrl;
seriesConfig?: DataSeries;
seriesConfig?: SeriesConfig;
}
export function SeriesBuilder({
@ -142,7 +142,7 @@ export function SeriesBuilder({
return loading ? (
LOADING_VIEW
) : reportType ? (
<ReportDefinitionCol seriesId={seriesId} dataViewSeries={seriesConfig} />
<ReportDefinitionCol seriesId={seriesId} seriesConfig={seriesConfig} />
) : (
SELECT_REPORT_TYPE
);
@ -159,7 +159,7 @@ export function SeriesBuilder({
field: 'id',
render: (seriesId: string, { series: { reportType }, seriesConfig }: BuilderItem) =>
reportType && seriesConfig ? (
<ReportFilters seriesId={seriesId} dataViewSeries={seriesConfig} />
<ReportFilters seriesId={seriesId} seriesConfig={seriesConfig} />
) : null,
},
{
@ -170,7 +170,7 @@ export function SeriesBuilder({
field: 'id',
render: (seriesId: string, { series: { reportType }, seriesConfig }: BuilderItem) =>
reportType && seriesConfig ? (
<ReportBreakdowns seriesId={seriesId} dataViewSeries={seriesConfig} />
<ReportBreakdowns seriesId={seriesId} seriesConfig={seriesConfig} />
) : null,
},
...(multiSeries
@ -301,10 +301,3 @@ export const SELECT_REPORT_TYPE = i18n.translate(
defaultMessage: 'No report type selected',
}
);
export const SELECT_DATA_TYPE = i18n.translate(
'xpack.observability.expView.seriesBuilder.selectDataType',
{
defaultMessage: 'No data type selected',
}
);

View file

@ -8,22 +8,22 @@
import React from 'react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { Breakdowns } from './columns/breakdowns';
import { DataSeries } from '../types';
import { SeriesConfig } from '../types';
import { ChartOptions } from './columns/chart_options';
interface Props {
series: DataSeries;
seriesConfig: SeriesConfig;
seriesId: string;
breakdowns: string[];
breakdownFields: string[];
}
export function ChartEditOptions({ series, seriesId, breakdowns }: Props) {
export function ChartEditOptions({ seriesConfig, seriesId, breakdownFields }: Props) {
return (
<EuiFlexGroup wrap>
<EuiFlexItem>
<Breakdowns seriesId={seriesId} breakdowns={breakdowns} reportViewConfig={series} />
<Breakdowns seriesId={seriesId} breakdowns={breakdownFields} seriesConfig={seriesConfig} />
</EuiFlexItem>
<EuiFlexItem>
<ChartOptions series={series} seriesId={seriesId} />
<ChartOptions seriesConfig={seriesConfig} seriesId={seriesId} />
</EuiFlexItem>
</EuiFlexGroup>
);

View file

@ -23,8 +23,8 @@ describe('Breakdowns', function () {
render(
<Breakdowns
seriesId={'series-id'}
breakdowns={dataViewSeries.breakdowns}
reportViewConfig={dataViewSeries}
breakdowns={dataViewSeries.breakdownFields}
seriesConfig={dataViewSeries}
/>
);
@ -37,8 +37,8 @@ describe('Breakdowns', function () {
const { setSeries } = render(
<Breakdowns
seriesId={'series-id'}
breakdowns={dataViewSeries.breakdowns}
reportViewConfig={dataViewSeries}
breakdowns={dataViewSeries.breakdownFields}
seriesConfig={dataViewSeries}
/>,
{ initSeries }
);

View file

@ -10,15 +10,15 @@ import { EuiSuperSelect } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useSeriesStorage } from '../../hooks/use_series_storage';
import { USE_BREAK_DOWN_COLUMN } from '../../configurations/constants';
import { DataSeries } from '../../types';
import { SeriesConfig } from '../../types';
interface Props {
seriesId: string;
breakdowns: string[];
reportViewConfig: DataSeries;
seriesConfig: SeriesConfig;
}
export function Breakdowns({ reportViewConfig, seriesId, breakdowns = [] }: Props) {
export function Breakdowns({ seriesConfig, seriesId, breakdowns = [] }: Props) {
const { setSeries, getSeries } = useSeriesStorage();
const series = getSeries(seriesId);
@ -40,11 +40,11 @@ export function Breakdowns({ reportViewConfig, seriesId, breakdowns = [] }: Prop
}
};
const hasUseBreakdownColumn = reportViewConfig.xAxisColumn.sourceField === USE_BREAK_DOWN_COLUMN;
const hasUseBreakdownColumn = seriesConfig.xAxisColumn.sourceField === USE_BREAK_DOWN_COLUMN;
const items = breakdowns.map((breakdown) => ({
id: breakdown,
label: reportViewConfig.labels[breakdown],
label: seriesConfig.labels[breakdown],
}));
if (!hasUseBreakdownColumn) {

View file

@ -7,22 +7,25 @@
import React from 'react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { DataSeries } from '../../types';
import { SeriesConfig } from '../../types';
import { OperationTypeSelect } from '../../series_builder/columns/operation_type_select';
import { SeriesChartTypesSelect } from '../../series_builder/columns/chart_types';
interface Props {
series: DataSeries;
seriesConfig: SeriesConfig;
seriesId: string;
}
export function ChartOptions({ series, seriesId }: Props) {
export function ChartOptions({ seriesConfig, seriesId }: Props) {
return (
<EuiFlexGroup direction="column" gutterSize="s" justifyContent="center">
<EuiFlexItem grow={false}>
<SeriesChartTypesSelect seriesId={seriesId} defaultChartType={series.seriesTypes[0]} />
<SeriesChartTypesSelect
seriesId={seriesId}
defaultChartType={seriesConfig.seriesTypes[0]}
/>
</EuiFlexItem>
{series.hasOperationType && (
{seriesConfig.hasOperationType && (
<EuiFlexItem grow={false}>
<OperationTypeSelect seriesId={seriesId} />
</EuiFlexItem>

View file

@ -14,7 +14,7 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/api/types';
import { map } from 'lodash';
import { useAppIndexPatternContext } from '../../hooks/use_app_index_pattern';
import { useSeriesStorage } from '../../hooks/use_series_storage';
import { DataSeries, UrlFilter } from '../../types';
import { SeriesConfig, UrlFilter } from '../../types';
import { FilterValueButton } from './filter_value_btn';
import { useValuesList } from '../../../../../hooks/use_values_list';
import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common';
@ -29,7 +29,7 @@ interface Props {
isNegated?: boolean;
goBack: () => void;
nestedField?: string;
filters: DataSeries['filters'];
filters: SeriesConfig['baseFilters'];
}
export function FilterExpanded({

View file

@ -16,16 +16,16 @@ import {
EuiFlexGroup,
} from '@elastic/eui';
import { FilterExpanded } from './filter_expanded';
import { DataSeries } from '../../types';
import { SeriesConfig } from '../../types';
import { FieldLabels } from '../../configurations/constants/constants';
import { SelectedFilters } from '../selected_filters';
import { useSeriesStorage } from '../../hooks/use_series_storage';
interface Props {
seriesId: string;
defaultFilters: DataSeries['defaultFilters'];
filters: DataSeries['filters'];
series: DataSeries;
filterFields: SeriesConfig['filterFields'];
baseFilters: SeriesConfig['baseFilters'];
seriesConfig: SeriesConfig;
isNew?: boolean;
labels?: Record<string, string>;
}
@ -38,18 +38,18 @@ export interface Field {
}
export function SeriesFilter({
series,
seriesConfig,
isNew,
seriesId,
defaultFilters = [],
filters,
filterFields = [],
baseFilters,
labels,
}: Props) {
const [isPopoverVisible, setIsPopoverVisible] = useState(false);
const [selectedField, setSelectedField] = useState<Field | undefined>();
const options: Field[] = defaultFilters.map((field) => {
const options: Field[] = filterFields.map((field) => {
if (typeof field === 'string') {
return { label: labels?.[field] ?? FieldLabels[field], field };
}
@ -111,7 +111,7 @@ export function SeriesFilter({
goBack={() => {
setSelectedField(undefined);
}}
filters={filters}
filters={baseFilters}
/>
) : null;
@ -122,7 +122,7 @@ export function SeriesFilter({
return (
<EuiFlexGroup wrap direction="column" gutterSize="xs" alignItems="flexStart">
<SelectedFilters seriesId={seriesId} series={series} isNew={isNew} />
<SelectedFilters seriesId={seriesId} seriesConfig={seriesConfig} isNew={isNew} />
<EuiFlexItem grow={false}>
<EuiPopover
button={button}

View file

@ -24,7 +24,9 @@ describe('SelectedFilters', function () {
it('should render properly', async function () {
const initSeries = { filters: [{ field: USER_AGENT_NAME, values: ['Chrome'] }] };
render(<SelectedFilters seriesId={'series-id'} series={dataViewSeries} />, { initSeries });
render(<SelectedFilters seriesId={'series-id'} seriesConfig={dataViewSeries} />, {
initSeries,
});
await waitFor(() => {
screen.getByText('Chrome');

View file

@ -9,28 +9,28 @@ import React, { Fragment } from 'react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { useSeriesStorage } from '../hooks/use_series_storage';
import { FilterLabel } from '../components/filter_label';
import { DataSeries, UrlFilter } from '../types';
import { SeriesConfig, UrlFilter } from '../types';
import { useAppIndexPatternContext } from '../hooks/use_app_index_pattern';
import { useSeriesFilters } from '../hooks/use_series_filters';
import { getFiltersFromDefs } from '../hooks/use_lens_attributes';
interface Props {
seriesId: string;
series: DataSeries;
seriesConfig: SeriesConfig;
isNew?: boolean;
}
export function SelectedFilters({ seriesId, isNew, series: dataSeries }: Props) {
export function SelectedFilters({ seriesId, isNew, seriesConfig }: Props) {
const { getSeries } = useSeriesStorage();
const series = getSeries(seriesId);
const { reportDefinitions = {} } = series;
const { labels } = dataSeries;
const { labels } = seriesConfig;
const filters: UrlFilter[] = series.filters ?? [];
let definitionFilters: UrlFilter[] = getFiltersFromDefs(reportDefinitions, dataSeries);
let definitionFilters: UrlFilter[] = getFiltersFromDefs(reportDefinitions);
// we don't want to display report definition filters in new series view
if (isNew) {

View file

@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n';
import { EuiBasicTable, EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { SeriesFilter } from './columns/series_filter';
import { DataSeries } from '../types';
import { SeriesConfig } from '../types';
import { NEW_SERIES_KEY, useSeriesStorage } from '../hooks/use_series_storage';
import { getDefaultConfigs } from '../configurations/default_configs';
import { DatePickerCol } from './columns/date_picker_col';
@ -19,7 +19,7 @@ import { SeriesActions } from './columns/series_actions';
import { ChartEditOptions } from './chart_edit_options';
interface EditItem {
seriesConfig: DataSeries;
seriesConfig: SeriesConfig;
id: string;
}
@ -48,10 +48,10 @@ export function SeriesEditor() {
width: '15%',
render: (seriesId: string, { seriesConfig, id }: EditItem) => (
<SeriesFilter
defaultFilters={seriesConfig.defaultFilters}
filterFields={seriesConfig.filterFields}
seriesId={id}
series={seriesConfig}
filters={seriesConfig.filters}
seriesConfig={seriesConfig}
baseFilters={seriesConfig.baseFilters}
/>
),
},
@ -64,8 +64,8 @@ export function SeriesEditor() {
render: (seriesId: string, { seriesConfig, id }: EditItem) => (
<ChartEditOptions
seriesId={id}
breakdowns={seriesConfig.breakdowns}
series={seriesConfig}
breakdownFields={seriesConfig.breakdownFields}
seriesConfig={seriesConfig}
/>
),
},
@ -123,7 +123,7 @@ export function SeriesEditor() {
rowHeader="firstName"
columns={columns}
noItemsMessage={i18n.translate('xpack.observability.expView.seriesEditor.seriesNotFound', {
defaultMessage: 'No series found, please add a series.',
defaultMessage: 'No series found. Please add a series.',
})}
cellProps={{
style: {

View file

@ -37,31 +37,27 @@ export interface ColumnFilter {
query: string;
}
export interface ReportDefinition {
field: string;
required?: boolean;
custom?: boolean;
options?: Array<{
id: string;
field?: string;
label: string;
description?: string;
columnType?: 'range' | 'operation' | 'FILTER_RECORDS' | 'TERMS_COLUMN';
columnFilters?: ColumnFilter[];
timeScale?: string;
}>;
export interface MetricOption {
id: string;
field?: string;
label: string;
description?: string;
columnType?: 'range' | 'operation' | 'FILTER_RECORDS' | 'TERMS_COLUMN';
columnFilters?: ColumnFilter[];
timeScale?: string;
}
export interface DataSeries {
export interface SeriesConfig {
reportType: ReportViewType;
xAxisColumn: Partial<LastValueIndexPatternColumn> | Partial<DateHistogramIndexPatternColumn>;
yAxisColumns: Array<Partial<FieldBasedIndexPatternColumn>>;
breakdowns: string[];
breakdownFields: string[];
defaultSeriesType: SeriesType;
defaultFilters: Array<string | { field: string; nested?: string; isNegated?: boolean }>;
filterFields: Array<string | { field: string; nested?: string; isNegated?: boolean }>;
seriesTypes: SeriesType[];
filters?: PersistableFilter[] | ExistsFilter[];
reportDefinitions: ReportDefinition[];
baseFilters?: PersistableFilter[] | ExistsFilter[];
definitionFields: string[];
metricOptions?: MetricOption[];
labels: Record<string, string>;
hasOperationType: boolean;
palette?: PaletteOutput;
@ -83,6 +79,7 @@ export interface SeriesUrl {
operationType?: OperationType;
dataType: AppDataType;
reportDefinitions?: URLReportDefinition;
selectedMetricField?: string;
isNew?: boolean;
}