mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Controls] Collect Telemetry (#130498)
* collect telemetry for controls
This commit is contained in:
parent
0082e0cb06
commit
3b37b27826
25 changed files with 567 additions and 137 deletions
|
@ -115,7 +115,7 @@ pageLoadAssetSize:
|
|||
reporting: 57003
|
||||
visTypeHeatmap: 25340
|
||||
expressionGauge: 25000
|
||||
controls: 34788
|
||||
controls: 40000
|
||||
expressionPartitionVis: 26338
|
||||
sharedUX: 16225
|
||||
ux: 20784
|
||||
|
|
|
@ -6,21 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ControlGroupInput } from '..';
|
||||
import { ControlStyle, ControlWidth } from '../types';
|
||||
|
||||
export const DEFAULT_CONTROL_WIDTH: ControlWidth = 'auto';
|
||||
export const DEFAULT_CONTROL_STYLE: ControlStyle = 'oneLine';
|
||||
|
||||
export const getDefaultControlGroupInput = (): Omit<ControlGroupInput, 'id'> => ({
|
||||
panels: {},
|
||||
defaultControlWidth: DEFAULT_CONTROL_WIDTH,
|
||||
controlStyle: DEFAULT_CONTROL_STYLE,
|
||||
chainingSystem: 'HIERARCHICAL',
|
||||
ignoreParentSettings: {
|
||||
ignoreFilters: false,
|
||||
ignoreQuery: false,
|
||||
ignoreTimerange: false,
|
||||
ignoreValidations: false,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -7,21 +7,12 @@
|
|||
*/
|
||||
|
||||
import { SerializableRecord } from '@kbn/utility-types';
|
||||
import { ControlGroupInput, getDefaultControlGroupInput } from '@kbn/controls-plugin/common';
|
||||
import { RawControlGroupAttributes } from '../types';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
|
||||
export const getDefaultDashboardControlGroupInput = getDefaultControlGroupInput;
|
||||
|
||||
export const controlGroupInputToRawAttributes = (
|
||||
controlGroupInput: Omit<ControlGroupInput, 'id'>
|
||||
): RawControlGroupAttributes => {
|
||||
return {
|
||||
controlStyle: controlGroupInput.controlStyle,
|
||||
chainingSystem: controlGroupInput.chainingSystem,
|
||||
panelsJSON: JSON.stringify(controlGroupInput.panels),
|
||||
ignoreParentSettingsJSON: JSON.stringify(controlGroupInput.ignoreParentSettings),
|
||||
};
|
||||
};
|
||||
import { pick } from 'lodash';
|
||||
import { ControlGroupInput } from '..';
|
||||
import { DEFAULT_CONTROL_STYLE, DEFAULT_CONTROL_WIDTH } from './control_group_constants';
|
||||
import { PersistableControlGroupInput, RawControlGroupAttributes } from './types';
|
||||
|
||||
const safeJSONParse = <OutType>(jsonString?: string): OutType | undefined => {
|
||||
if (!jsonString && typeof jsonString !== 'string') return;
|
||||
|
@ -32,7 +23,48 @@ const safeJSONParse = <OutType>(jsonString?: string): OutType | undefined => {
|
|||
}
|
||||
};
|
||||
|
||||
export const rawAttributesToControlGroupInput = (
|
||||
export const getDefaultControlGroupInput = (): Omit<ControlGroupInput, 'id'> => ({
|
||||
panels: {},
|
||||
defaultControlWidth: DEFAULT_CONTROL_WIDTH,
|
||||
controlStyle: DEFAULT_CONTROL_STYLE,
|
||||
chainingSystem: 'HIERARCHICAL',
|
||||
ignoreParentSettings: {
|
||||
ignoreFilters: false,
|
||||
ignoreQuery: false,
|
||||
ignoreTimerange: false,
|
||||
ignoreValidations: false,
|
||||
},
|
||||
});
|
||||
|
||||
export const persistableControlGroupInputIsEqual = (
|
||||
a: PersistableControlGroupInput | undefined,
|
||||
b: PersistableControlGroupInput | undefined
|
||||
) => {
|
||||
const defaultInput = getDefaultControlGroupInput();
|
||||
const inputA = {
|
||||
...defaultInput,
|
||||
...pick(a, ['panels', 'chainingSystem', 'controlStyle', 'ignoreParentSettings']),
|
||||
};
|
||||
const inputB = {
|
||||
...defaultInput,
|
||||
...pick(b, ['panels', 'chainingSystem', 'controlStyle', 'ignoreParentSettings']),
|
||||
};
|
||||
if (deepEqual(inputA, inputB)) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const controlGroupInputToRawControlGroupAttributes = (
|
||||
controlGroupInput: Omit<ControlGroupInput, 'id'>
|
||||
): RawControlGroupAttributes => {
|
||||
return {
|
||||
controlStyle: controlGroupInput.controlStyle,
|
||||
chainingSystem: controlGroupInput.chainingSystem,
|
||||
panelsJSON: JSON.stringify(controlGroupInput.panels),
|
||||
ignoreParentSettingsJSON: JSON.stringify(controlGroupInput.ignoreParentSettings),
|
||||
};
|
||||
};
|
||||
|
||||
export const rawControlGroupAttributesToControlGroupInput = (
|
||||
rawControlGroupAttributes: RawControlGroupAttributes
|
||||
): Omit<ControlGroupInput, 'id'> | undefined => {
|
||||
const defaultControlGroupInput = getDefaultControlGroupInput();
|
||||
|
@ -50,7 +82,7 @@ export const rawAttributesToControlGroupInput = (
|
|||
};
|
||||
};
|
||||
|
||||
export const rawAttributesToSerializable = (
|
||||
export const rawControlGroupAttributesToSerializable = (
|
||||
rawControlGroupAttributes: Omit<RawControlGroupAttributes, 'id'>
|
||||
): SerializableRecord => {
|
||||
const defaultControlGroupInput = getDefaultControlGroupInput();
|
||||
|
@ -62,7 +94,7 @@ export const rawAttributesToSerializable = (
|
|||
};
|
||||
};
|
||||
|
||||
export const serializableToRawAttributes = (
|
||||
export const serializableToRawControlGroupAttributes = (
|
||||
serializable: SerializableRecord
|
||||
): Omit<RawControlGroupAttributes, 'id' | 'type'> => {
|
||||
return {
|
|
@ -29,3 +29,36 @@ export interface ControlGroupInput extends EmbeddableInput, ControlInput {
|
|||
controlStyle: ControlStyle;
|
||||
panels: ControlsPanels;
|
||||
}
|
||||
|
||||
// only parts of the Control Group Input should be persisted
|
||||
export type PersistableControlGroupInput = Pick<
|
||||
ControlGroupInput,
|
||||
'panels' | 'chainingSystem' | 'controlStyle' | 'ignoreParentSettings'
|
||||
>;
|
||||
|
||||
// panels are json stringified for storage in a saved object.
|
||||
export type RawControlGroupAttributes = Omit<
|
||||
PersistableControlGroupInput,
|
||||
'panels' | 'ignoreParentSettings'
|
||||
> & {
|
||||
ignoreParentSettingsJSON: string;
|
||||
panelsJSON: string;
|
||||
};
|
||||
export interface ControlGroupTelemetry {
|
||||
total: number;
|
||||
chaining_system: {
|
||||
[key: string]: number;
|
||||
};
|
||||
label_position: {
|
||||
[key: string]: number;
|
||||
};
|
||||
ignore_settings: {
|
||||
[key: string]: number;
|
||||
};
|
||||
by_type: {
|
||||
[key: string]: {
|
||||
total: number;
|
||||
details: { [key: string]: number };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,14 +7,37 @@
|
|||
*/
|
||||
|
||||
export type { ControlWidth } from './types';
|
||||
export type { ControlPanelState, ControlsPanels, ControlGroupInput } from './control_group/types';
|
||||
export type { OptionsListEmbeddableInput } from './control_types/options_list/types';
|
||||
export type { RangeSliderEmbeddableInput } from './control_types/range_slider/types';
|
||||
|
||||
export { CONTROL_GROUP_TYPE } from './control_group/types';
|
||||
export { OPTIONS_LIST_CONTROL } from './control_types/options_list/types';
|
||||
export { RANGE_SLIDER_CONTROL } from './control_types/range_slider/types';
|
||||
|
||||
export { getDefaultControlGroupInput } from './control_group/control_group_constants';
|
||||
// Control Group exports
|
||||
export {
|
||||
CONTROL_GROUP_TYPE,
|
||||
type ControlPanelState,
|
||||
type ControlsPanels,
|
||||
type ControlGroupInput,
|
||||
type ControlGroupTelemetry,
|
||||
type RawControlGroupAttributes,
|
||||
type PersistableControlGroupInput,
|
||||
} from './control_group/types';
|
||||
export {
|
||||
controlGroupInputToRawControlGroupAttributes,
|
||||
rawControlGroupAttributesToControlGroupInput,
|
||||
rawControlGroupAttributesToSerializable,
|
||||
serializableToRawControlGroupAttributes,
|
||||
persistableControlGroupInputIsEqual,
|
||||
getDefaultControlGroupInput,
|
||||
} from './control_group/control_group_persistence';
|
||||
export {
|
||||
DEFAULT_CONTROL_WIDTH,
|
||||
DEFAULT_CONTROL_STYLE,
|
||||
} from './control_group/control_group_constants';
|
||||
|
||||
// Control Type exports
|
||||
export {
|
||||
OPTIONS_LIST_CONTROL,
|
||||
type OptionsListEmbeddableInput,
|
||||
} from './control_types/options_list/types';
|
||||
export {
|
||||
type RangeSliderEmbeddableInput,
|
||||
RANGE_SLIDER_CONTROL,
|
||||
} from './control_types/range_slider/types';
|
||||
export { TIME_SLIDER_CONTROL } from './control_types/time_slider/types';
|
||||
|
|
|
@ -44,10 +44,7 @@ import { ControlStyle, ControlWidth } from '../../types';
|
|||
import { ParentIgnoreSettings } from '../..';
|
||||
import { ControlsPanels } from '../types';
|
||||
import { ControlGroupInput } from '..';
|
||||
import {
|
||||
DEFAULT_CONTROL_WIDTH,
|
||||
getDefaultControlGroupInput,
|
||||
} from '../../../common/control_group/control_group_constants';
|
||||
import { DEFAULT_CONTROL_WIDTH, getDefaultControlGroupInput } from '../../../common';
|
||||
|
||||
interface EditControlGroupProps {
|
||||
initialInput: ControlGroupInput;
|
||||
|
|
|
@ -23,7 +23,7 @@ import {
|
|||
createControlGroupExtract,
|
||||
createControlGroupInject,
|
||||
} from '../../../common/control_group/control_group_persistable_state';
|
||||
import { getDefaultControlGroupInput } from '../../../common/control_group/control_group_constants';
|
||||
import { getDefaultControlGroupInput } from '../../../common';
|
||||
|
||||
export class ControlGroupContainerFactory implements EmbeddableFactoryDefinition {
|
||||
public readonly isContainerType = true;
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
createControlGroupInject,
|
||||
migrations,
|
||||
} from '../../common/control_group/control_group_persistable_state';
|
||||
import { controlGroupTelemetry } from './control_group_telemetry';
|
||||
|
||||
export const controlGroupContainerPersistableStateServiceFactory = (
|
||||
persistableStateService: EmbeddablePersistableStateService
|
||||
|
@ -22,6 +23,7 @@ export const controlGroupContainerPersistableStateServiceFactory = (
|
|||
id: CONTROL_GROUP_TYPE,
|
||||
extract: createControlGroupExtract(persistableStateService),
|
||||
inject: createControlGroupInject(persistableStateService),
|
||||
telemetry: controlGroupTelemetry,
|
||||
migrations,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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 { ControlGroupTelemetry, RawControlGroupAttributes } from '../../common';
|
||||
import { controlGroupTelemetry, initializeControlGroupTelemetry } from './control_group_telemetry';
|
||||
|
||||
// controls attributes with all settings ignored + 3 options lists + hierarchical chaining + label above
|
||||
const rawControlAttributes1: RawControlGroupAttributes = {
|
||||
controlStyle: 'twoLine',
|
||||
chainingSystem: 'NONE',
|
||||
panelsJSON:
|
||||
'{"6fc71ac6-62f9-4ff4-bf5a-d1e066065376":{"order":0,"width":"auto","type":"optionsListControl","explicitInput":{"title":"Carrier","fieldName":"Carrier","id":"6fc71ac6-62f9-4ff4-bf5a-d1e066065376","enhancements":{}}},"1ca90451-908b-4eae-ac4d-535f2e30c4ad":{"order":2,"width":"auto","type":"optionsListControl","explicitInput":{"title":"DestAirportID","fieldName":"DestAirportID","id":"1ca90451-908b-4eae-ac4d-535f2e30c4ad","enhancements":{}}},"71086bac-316d-415f-8aa8-b9a921bc7f58":{"order":1,"width":"auto","type":"optionsListControl","explicitInput":{"title":"DestRegion","fieldName":"DestRegion","id":"71086bac-316d-415f-8aa8-b9a921bc7f58","enhancements":{}}}}',
|
||||
ignoreParentSettingsJSON:
|
||||
'{"ignoreFilters":true,"ignoreQuery":true,"ignoreTimerange":true,"ignoreValidations":true}',
|
||||
};
|
||||
|
||||
// controls attributes with some settings ignored + 2 range sliders, 1 time slider + No chaining + label inline
|
||||
const rawControlAttributes2: RawControlGroupAttributes = {
|
||||
controlStyle: 'oneLine',
|
||||
chainingSystem: 'NONE',
|
||||
panelsJSON:
|
||||
'{"9cf90205-e94d-43c9-a3aa-45f359a7522f":{"order":0,"width":"auto","type":"rangeSliderControl","explicitInput":{"title":"DistanceKilometers","fieldName":"DistanceKilometers","id":"9cf90205-e94d-43c9-a3aa-45f359a7522f","enhancements":{}}},"b47916fd-fc03-4dcd-bef1-5c3b7a315723":{"order":1,"width":"auto","type":"timeSlider","explicitInput":{"title":"timestamp","fieldName":"timestamp","id":"b47916fd-fc03-4dcd-bef1-5c3b7a315723","enhancements":{}}},"f6b076c6-9ef5-483e-b08d-d313d60d4b8c":{"order":2,"width":"auto","type":"rangeSliderControl","explicitInput":{"title":"DistanceMiles","fieldName":"DistanceMiles","id":"f6b076c6-9ef5-483e-b08d-d313d60d4b8c","enhancements":{}}}}',
|
||||
ignoreParentSettingsJSON:
|
||||
'{"ignoreFilters":true,"ignoreQuery":false,"ignoreTimerange":false,"ignoreValidations":false}',
|
||||
};
|
||||
|
||||
// controls attributes with no settings ignored + 2 options lists, 1 range slider, 1 time slider + hierarchical chaining + label inline
|
||||
const rawControlAttributes3: RawControlGroupAttributes = {
|
||||
controlStyle: 'oneLine',
|
||||
chainingSystem: 'HIERARCHICAL',
|
||||
panelsJSON:
|
||||
'{"9cf90205-e94d-43c9-a3aa-45f359a7522f":{"order":0,"width":"auto","type":"rangeSliderControl","explicitInput":{"title":"DistanceKilometers","fieldName":"DistanceKilometers","id":"9cf90205-e94d-43c9-a3aa-45f359a7522f","enhancements":{}}},"b47916fd-fc03-4dcd-bef1-5c3b7a315723":{"order":1,"width":"auto","type":"timeSlider","explicitInput":{"title":"timestamp","fieldName":"timestamp","id":"b47916fd-fc03-4dcd-bef1-5c3b7a315723","enhancements":{}}},"ee325e9e-6ec1-41f9-953f-423d59850d44":{"order":2,"width":"auto","type":"optionsListControl","explicitInput":{"title":"Carrier","fieldName":"Carrier","id":"ee325e9e-6ec1-41f9-953f-423d59850d44","enhancements":{}}},"cb0f5fcd-9ad9-4d4a-b489-b75bd060399b":{"order":3,"width":"auto","type":"optionsListControl","explicitInput":{"title":"DestCityName","fieldName":"DestCityName","id":"cb0f5fcd-9ad9-4d4a-b489-b75bd060399b","enhancements":{}}}}',
|
||||
ignoreParentSettingsJSON:
|
||||
'{"ignoreFilters":false,"ignoreQuery":false,"ignoreTimerange":false,"ignoreValidations":false}',
|
||||
};
|
||||
|
||||
describe('Initialize telemetry', () => {
|
||||
test('initializes telemetry when given blank object', () => {
|
||||
const initializedTelemetry = initializeControlGroupTelemetry({});
|
||||
expect(initializedTelemetry.total).toBe(0);
|
||||
expect(initializedTelemetry.chaining_system).toEqual({});
|
||||
expect(initializedTelemetry.ignore_settings).toEqual({});
|
||||
expect(initializedTelemetry.by_type).toEqual({});
|
||||
});
|
||||
|
||||
test('initializes telemetry without overwriting any keys when given a partial telemetry object', () => {
|
||||
const partialTelemetry: Partial<ControlGroupTelemetry> = {
|
||||
total: 77,
|
||||
chaining_system: { TESTCHAIN: 10, OTHERCHAIN: 1 },
|
||||
by_type: { test1: { total: 10, details: {} } },
|
||||
};
|
||||
const initializedTelemetry = initializeControlGroupTelemetry(partialTelemetry);
|
||||
expect(initializedTelemetry.total).toBe(77);
|
||||
expect(initializedTelemetry.chaining_system).toEqual({ TESTCHAIN: 10, OTHERCHAIN: 1 });
|
||||
expect(initializedTelemetry.ignore_settings).toEqual({});
|
||||
expect(initializedTelemetry.by_type).toEqual({ test1: { total: 10, details: {} } });
|
||||
expect(initializedTelemetry.label_position).toEqual({});
|
||||
});
|
||||
|
||||
test('initiailizes telemetry without overwriting any keys when given a completed telemetry object', () => {
|
||||
const partialTelemetry: Partial<ControlGroupTelemetry> = {
|
||||
total: 5,
|
||||
chaining_system: { TESTCHAIN: 10, OTHERCHAIN: 1 },
|
||||
by_type: { test1: { total: 10, details: {} } },
|
||||
ignore_settings: { ignoreValidations: 12 },
|
||||
label_position: { inline: 10, above: 12 },
|
||||
};
|
||||
const initializedTelemetry = initializeControlGroupTelemetry(partialTelemetry);
|
||||
expect(initializedTelemetry.total).toBe(5);
|
||||
expect(initializedTelemetry.chaining_system).toEqual({ TESTCHAIN: 10, OTHERCHAIN: 1 });
|
||||
expect(initializedTelemetry.ignore_settings).toEqual({ ignoreValidations: 12 });
|
||||
expect(initializedTelemetry.by_type).toEqual({ test1: { total: 10, details: {} } });
|
||||
expect(initializedTelemetry.label_position).toEqual({ inline: 10, above: 12 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Control group telemetry function', () => {
|
||||
let finalTelemetry: ControlGroupTelemetry;
|
||||
|
||||
beforeAll(() => {
|
||||
const allControlGroups = [rawControlAttributes1, rawControlAttributes2, rawControlAttributes3];
|
||||
|
||||
finalTelemetry = allControlGroups.reduce<ControlGroupTelemetry>(
|
||||
(telemetrySoFar, rawControlGroupAttributes) => {
|
||||
return controlGroupTelemetry(
|
||||
rawControlGroupAttributes,
|
||||
telemetrySoFar
|
||||
) as ControlGroupTelemetry;
|
||||
},
|
||||
{} as ControlGroupTelemetry
|
||||
);
|
||||
});
|
||||
|
||||
test('counts all telemetry over multiple runs', () => {
|
||||
expect(finalTelemetry.total).toBe(10);
|
||||
});
|
||||
|
||||
test('counts control types over multiple runs.', () => {
|
||||
expect(finalTelemetry.by_type).toEqual({
|
||||
optionsListControl: {
|
||||
details: {},
|
||||
total: 5,
|
||||
},
|
||||
rangeSliderControl: {
|
||||
details: {},
|
||||
total: 3,
|
||||
},
|
||||
timeSlider: {
|
||||
details: {},
|
||||
total: 2,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('collects ignore settings over multiple runs.', () => {
|
||||
expect(finalTelemetry.ignore_settings).toEqual({
|
||||
ignoreFilters: 2,
|
||||
ignoreQuery: 1,
|
||||
ignoreTimerange: 1,
|
||||
ignoreValidations: 1,
|
||||
});
|
||||
});
|
||||
|
||||
test('counts various chaining systems over multiple runs.', () => {
|
||||
expect(finalTelemetry.chaining_system).toEqual({
|
||||
HIERARCHICAL: 1,
|
||||
NONE: 2,
|
||||
});
|
||||
});
|
||||
|
||||
test('counts label positions over multiple runs.', () => {
|
||||
expect(finalTelemetry.label_position).toEqual({
|
||||
oneLine: 2,
|
||||
twoLine: 1,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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 { set } from 'lodash';
|
||||
import { PersistableStateService } from '@kbn/kibana-utils-plugin/common';
|
||||
import {
|
||||
ControlGroupTelemetry,
|
||||
RawControlGroupAttributes,
|
||||
rawControlGroupAttributesToControlGroupInput,
|
||||
} from '../../common';
|
||||
import { ControlGroupInput } from '../../common/control_group/types';
|
||||
|
||||
export const initializeControlGroupTelemetry = (
|
||||
statsSoFar: Record<string, unknown>
|
||||
): ControlGroupTelemetry => {
|
||||
return {
|
||||
total: (statsSoFar?.total as number) ?? 0,
|
||||
chaining_system:
|
||||
(statsSoFar?.chaining_system as ControlGroupTelemetry['chaining_system']) ?? {},
|
||||
ignore_settings:
|
||||
(statsSoFar?.ignore_settings as ControlGroupTelemetry['ignore_settings']) ?? {},
|
||||
label_position: (statsSoFar?.label_position as ControlGroupTelemetry['label_position']) ?? {},
|
||||
by_type: (statsSoFar?.by_type as ControlGroupTelemetry['by_type']) ?? {},
|
||||
};
|
||||
};
|
||||
|
||||
const reportChainingSystemInUse = (
|
||||
chainingSystemsStats: ControlGroupTelemetry['chaining_system'],
|
||||
chainingSystem: ControlGroupInput['chainingSystem']
|
||||
): ControlGroupTelemetry['chaining_system'] => {
|
||||
if (!chainingSystem) return chainingSystemsStats;
|
||||
if (Boolean(chainingSystemsStats[chainingSystem])) {
|
||||
chainingSystemsStats[chainingSystem]++;
|
||||
} else {
|
||||
chainingSystemsStats[chainingSystem] = 1;
|
||||
}
|
||||
return chainingSystemsStats;
|
||||
};
|
||||
|
||||
const reportLabelPositionsInUse = (
|
||||
labelPositionStats: ControlGroupTelemetry['label_position'],
|
||||
labelPosition: ControlGroupInput['controlStyle'] // controlStyle was renamed labelPosition
|
||||
): ControlGroupTelemetry['label_position'] => {
|
||||
if (!labelPosition) return labelPositionStats;
|
||||
if (Boolean(labelPositionStats[labelPosition])) {
|
||||
labelPositionStats[labelPosition]++;
|
||||
} else {
|
||||
labelPositionStats[labelPosition] = 1;
|
||||
}
|
||||
return labelPositionStats;
|
||||
};
|
||||
|
||||
const reportIgnoreSettingsInUse = (
|
||||
settingsStats: ControlGroupTelemetry['ignore_settings'],
|
||||
settings: ControlGroupInput['ignoreParentSettings']
|
||||
): ControlGroupTelemetry['ignore_settings'] => {
|
||||
if (!settings) return settingsStats;
|
||||
for (const [settingKey, settingValue] of Object.entries(settings)) {
|
||||
if (settingValue) {
|
||||
// only report ignore settings which are turned ON
|
||||
const currentValueForSetting = settingsStats[settingKey] ?? 0;
|
||||
set(settingsStats, settingKey, currentValueForSetting + 1);
|
||||
}
|
||||
}
|
||||
return settingsStats;
|
||||
};
|
||||
|
||||
const reportControlTypes = (
|
||||
controlTypeStats: ControlGroupTelemetry['by_type'],
|
||||
panels: ControlGroupInput['panels']
|
||||
): ControlGroupTelemetry['by_type'] => {
|
||||
for (const { type } of Object.values(panels)) {
|
||||
const currentTypeCount = controlTypeStats[type]?.total ?? 0;
|
||||
const currentTypeDetails = controlTypeStats[type]?.details ?? {};
|
||||
|
||||
// here if we need to start tracking details on specific control types, we can call embeddableService.telemetry
|
||||
|
||||
set(controlTypeStats, `${type}.total`, currentTypeCount + 1);
|
||||
set(controlTypeStats, `${type}.details`, currentTypeDetails);
|
||||
}
|
||||
return controlTypeStats;
|
||||
};
|
||||
|
||||
export const controlGroupTelemetry: PersistableStateService['telemetry'] = (
|
||||
state,
|
||||
stats
|
||||
): ControlGroupTelemetry => {
|
||||
const controlGroupStats = initializeControlGroupTelemetry(stats);
|
||||
const controlGroupInput = rawControlGroupAttributesToControlGroupInput(
|
||||
state as unknown as RawControlGroupAttributes
|
||||
);
|
||||
if (!controlGroupInput) return controlGroupStats;
|
||||
|
||||
controlGroupStats.total += Object.keys(controlGroupInput?.panels ?? {}).length;
|
||||
|
||||
controlGroupStats.chaining_system = reportChainingSystemInUse(
|
||||
controlGroupStats.chaining_system,
|
||||
controlGroupInput.chainingSystem
|
||||
);
|
||||
|
||||
controlGroupStats.label_position = reportLabelPositionsInUse(
|
||||
controlGroupStats.label_position,
|
||||
controlGroupInput.controlStyle
|
||||
);
|
||||
|
||||
controlGroupStats.ignore_settings = reportIgnoreSettingsInUse(
|
||||
controlGroupStats.ignore_settings,
|
||||
controlGroupInput.ignoreParentSettings
|
||||
);
|
||||
|
||||
controlGroupStats.by_type = reportControlTypes(
|
||||
controlGroupStats.by_type,
|
||||
controlGroupInput.panels
|
||||
);
|
||||
|
||||
return controlGroupStats;
|
||||
};
|
|
@ -9,3 +9,5 @@
|
|||
import { ControlsPlugin } from './plugin';
|
||||
|
||||
export const plugin = () => new ControlsPlugin();
|
||||
|
||||
export { initializeControlGroupTelemetry } from './control_group/control_group_telemetry';
|
||||
|
|
|
@ -12,12 +12,8 @@ import {
|
|||
EmbeddableStateWithType,
|
||||
} from '@kbn/embeddable-plugin/common';
|
||||
import { SavedObjectReference } from '@kbn/core/types';
|
||||
import { CONTROL_GROUP_TYPE } from '@kbn/controls-plugin/common';
|
||||
import {
|
||||
DashboardContainerControlGroupInput,
|
||||
DashboardContainerStateWithType,
|
||||
DashboardPanelState,
|
||||
} from '../types';
|
||||
import { CONTROL_GROUP_TYPE, PersistableControlGroupInput } from '@kbn/controls-plugin/common';
|
||||
import { DashboardContainerStateWithType, DashboardPanelState } from '../types';
|
||||
|
||||
const getPanelStatePrefix = (state: DashboardPanelState) => `${state.explicitInput.id}:`;
|
||||
|
||||
|
@ -95,7 +91,7 @@ export const createInject = (
|
|||
controlGroupReferences
|
||||
);
|
||||
workingState.controlGroupInput =
|
||||
injectedControlGroupState as unknown as DashboardContainerControlGroupInput;
|
||||
injectedControlGroupState as unknown as PersistableControlGroupInput;
|
||||
}
|
||||
|
||||
return workingState as EmbeddableStateWithType;
|
||||
|
@ -160,7 +156,7 @@ export const createExtract = (
|
|||
id: controlGroupId,
|
||||
});
|
||||
workingState.controlGroupInput =
|
||||
extractedControlGroupState as unknown as DashboardContainerControlGroupInput;
|
||||
extractedControlGroupState as unknown as PersistableControlGroupInput;
|
||||
const prefixedControlGroupReferences = controlGroupReferences.map((reference) => ({
|
||||
...reference,
|
||||
name: `${controlGroupReferencePrefix}${reference.name}`,
|
||||
|
|
|
@ -28,11 +28,3 @@ export { migratePanelsTo730 } from './migrate_to_730_panels';
|
|||
export const UI_SETTINGS = {
|
||||
ENABLE_LABS_UI: 'labs:dashboard:enable_ui',
|
||||
};
|
||||
|
||||
export {
|
||||
controlGroupInputToRawAttributes,
|
||||
getDefaultDashboardControlGroupInput,
|
||||
rawAttributesToControlGroupInput,
|
||||
rawAttributesToSerializable,
|
||||
serializableToRawAttributes,
|
||||
} from './embeddable/dashboard_control_group';
|
||||
|
|
|
@ -9,11 +9,10 @@ import semverGt from 'semver/functions/gt';
|
|||
import { SavedObjectAttributes, SavedObjectReference } from '@kbn/core/types';
|
||||
import { EmbeddablePersistableStateService } from '@kbn/embeddable-plugin/common/types';
|
||||
import {
|
||||
DashboardContainerControlGroupInput,
|
||||
DashboardContainerStateWithType,
|
||||
DashboardPanelState,
|
||||
PersistableControlGroupInput,
|
||||
RawControlGroupAttributes,
|
||||
} from './types';
|
||||
} from '@kbn/controls-plugin/common';
|
||||
import { DashboardContainerStateWithType, DashboardPanelState } from './types';
|
||||
import {
|
||||
convertPanelStateToSavedDashboardPanel,
|
||||
convertSavedDashboardPanelToPanelState,
|
||||
|
@ -41,7 +40,7 @@ function dashboardAttributesToState(attributes: SavedObjectAttributes): {
|
|||
inputPanels = JSON.parse(attributes.panelsJSON) as SavedDashboardPanel[];
|
||||
}
|
||||
|
||||
let controlGroupInput: DashboardContainerControlGroupInput | undefined;
|
||||
let controlGroupInput: PersistableControlGroupInput | undefined;
|
||||
if (attributes.controlGroupInput) {
|
||||
const rawControlGroupInput =
|
||||
attributes.controlGroupInput as unknown as RawControlGroupAttributes;
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
PanelState,
|
||||
} from '@kbn/embeddable-plugin/common/types';
|
||||
import { SavedObjectEmbeddableInput } from '@kbn/embeddable-plugin/common/lib/saved_object_embeddable';
|
||||
import { ControlGroupInput } from '@kbn/controls-plugin/common';
|
||||
import { PersistableControlGroupInput } from '@kbn/controls-plugin/common';
|
||||
import {
|
||||
RawSavedDashboardPanelTo60,
|
||||
RawSavedDashboardPanel610,
|
||||
|
@ -23,6 +23,7 @@ import {
|
|||
} from './bwc/types';
|
||||
|
||||
import { GridData } from './embeddable/types';
|
||||
|
||||
export type PanelId = string;
|
||||
export type SavedObjectId = string;
|
||||
|
||||
|
@ -98,23 +99,9 @@ export type SavedDashboardPanel730ToLatest = Pick<
|
|||
// Making this interface because so much of the Container type from embeddable is tied up in public
|
||||
// Once that is all available from common, we should be able to move the dashboard_container type to our common as well
|
||||
|
||||
// dashboard only persists part of the Control Group Input
|
||||
export type DashboardContainerControlGroupInput = Pick<
|
||||
ControlGroupInput,
|
||||
'panels' | 'chainingSystem' | 'controlStyle' | 'ignoreParentSettings'
|
||||
>;
|
||||
|
||||
export type RawControlGroupAttributes = Omit<
|
||||
DashboardContainerControlGroupInput,
|
||||
'panels' | 'ignoreParentSettings'
|
||||
> & {
|
||||
ignoreParentSettingsJSON: string;
|
||||
panelsJSON: string;
|
||||
};
|
||||
|
||||
export interface DashboardContainerStateWithType extends EmbeddableStateWithType {
|
||||
panels: {
|
||||
[panelId: string]: DashboardPanelState<EmbeddableInput & { [k: string]: unknown }>;
|
||||
};
|
||||
controlGroupInput?: DashboardContainerControlGroupInput;
|
||||
controlGroupInput?: PersistableControlGroupInput;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
ControlGroupOutput,
|
||||
CONTROL_GROUP_TYPE,
|
||||
} from '@kbn/controls-plugin/public';
|
||||
import { getDefaultControlGroupInput } from '@kbn/controls-plugin/common';
|
||||
import { DashboardContainerInput } from '../..';
|
||||
import { DASHBOARD_CONTAINER_TYPE } from './dashboard_constants';
|
||||
import type { DashboardContainer, DashboardContainerServices } from './dashboard_container';
|
||||
|
@ -31,8 +32,6 @@ import {
|
|||
createInject,
|
||||
} from '../../../common/embeddable/dashboard_container_persistable_state';
|
||||
|
||||
import { getDefaultDashboardControlGroupInput } from '../../../common/embeddable/dashboard_control_group';
|
||||
|
||||
export type DashboardContainerFactory = EmbeddableFactory<
|
||||
DashboardContainerInput,
|
||||
ContainerOutput,
|
||||
|
@ -90,7 +89,7 @@ export class DashboardContainerFactoryDefinition
|
|||
const { filters, query, timeRange, viewMode, controlGroupInput, id } = initialInput;
|
||||
const controlGroup = await controlsGroupFactory?.create({
|
||||
id: `control_group_${id ?? 'new_dashboard'}`,
|
||||
...getDefaultDashboardControlGroupInput(),
|
||||
...getDefaultControlGroupInput(),
|
||||
...pickBy(controlGroupInput, identity), // undefined keys in initialInput should not overwrite defaults
|
||||
timeRange,
|
||||
viewMode,
|
||||
|
|
|
@ -11,16 +11,19 @@ import deepEqual from 'fast-deep-equal';
|
|||
import { compareFilters, COMPARE_ALL_OPTIONS, type Filter } from '@kbn/es-query';
|
||||
import { debounceTime, distinctUntilChanged, distinctUntilKeyChanged } from 'rxjs/operators';
|
||||
|
||||
import { pick } from 'lodash';
|
||||
import { ControlGroupContainer, ControlGroupInput } from '@kbn/controls-plugin/public';
|
||||
import { DashboardContainer, DashboardContainerControlGroupInput } from '..';
|
||||
import {
|
||||
ControlGroupInput,
|
||||
controlGroupInputToRawControlGroupAttributes,
|
||||
getDefaultControlGroupInput,
|
||||
persistableControlGroupInputIsEqual,
|
||||
rawControlGroupAttributesToControlGroupInput,
|
||||
} from '@kbn/controls-plugin/common';
|
||||
import { ControlGroupContainer } from '@kbn/controls-plugin/public';
|
||||
|
||||
import { DashboardContainer } from '..';
|
||||
import { DashboardState } from '../../types';
|
||||
import { DashboardContainerInput, DashboardSavedObject } from '../..';
|
||||
import {
|
||||
controlGroupInputToRawAttributes,
|
||||
getDefaultDashboardControlGroupInput,
|
||||
rawAttributesToControlGroupInput,
|
||||
} from '../../../common';
|
||||
|
||||
interface DiffChecks {
|
||||
[key: string]: (a?: unknown, b?: unknown) => boolean;
|
||||
}
|
||||
|
@ -45,7 +48,7 @@ export const syncDashboardControlGroup = async ({
|
|||
const subscriptions = new Subscription();
|
||||
|
||||
const isControlGroupInputEqual = () =>
|
||||
controlGroupInputIsEqual(
|
||||
persistableControlGroupInputIsEqual(
|
||||
controlGroup.getInput(),
|
||||
dashboardContainer.getInput().controlGroupInput
|
||||
);
|
||||
|
@ -122,7 +125,7 @@ export const syncDashboardControlGroup = async ({
|
|||
.subscribe(() => {
|
||||
if (!isControlGroupInputEqual()) {
|
||||
if (!dashboardContainer.getInput().controlGroupInput) {
|
||||
controlGroup.updateInput(getDefaultDashboardControlGroupInput());
|
||||
controlGroup.updateInput(getDefaultControlGroupInput());
|
||||
return;
|
||||
}
|
||||
controlGroup.updateInput({ ...dashboardContainer.getInput().controlGroupInput });
|
||||
|
@ -152,39 +155,22 @@ export const syncDashboardControlGroup = async ({
|
|||
};
|
||||
};
|
||||
|
||||
export const controlGroupInputIsEqual = (
|
||||
a: DashboardContainerControlGroupInput | undefined,
|
||||
b: DashboardContainerControlGroupInput | undefined
|
||||
) => {
|
||||
const defaultInput = getDefaultDashboardControlGroupInput();
|
||||
const inputA = {
|
||||
...defaultInput,
|
||||
...pick(a, ['panels', 'chainingSystem', 'controlStyle', 'ignoreParentSettings']),
|
||||
};
|
||||
const inputB = {
|
||||
...defaultInput,
|
||||
...pick(b, ['panels', 'chainingSystem', 'controlStyle', 'ignoreParentSettings']),
|
||||
};
|
||||
if (deepEqual(inputA, inputB)) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const serializeControlGroupToDashboardSavedObject = (
|
||||
dashboardSavedObject: DashboardSavedObject,
|
||||
dashboardState: DashboardState
|
||||
) => {
|
||||
// only save to saved object if control group is not default
|
||||
if (
|
||||
controlGroupInputIsEqual(
|
||||
persistableControlGroupInputIsEqual(
|
||||
dashboardState.controlGroupInput,
|
||||
getDefaultDashboardControlGroupInput()
|
||||
getDefaultControlGroupInput()
|
||||
)
|
||||
) {
|
||||
dashboardSavedObject.controlGroupInput = undefined;
|
||||
return;
|
||||
}
|
||||
if (dashboardState.controlGroupInput) {
|
||||
dashboardSavedObject.controlGroupInput = controlGroupInputToRawAttributes(
|
||||
dashboardSavedObject.controlGroupInput = controlGroupInputToRawControlGroupAttributes(
|
||||
dashboardState.controlGroupInput
|
||||
);
|
||||
}
|
||||
|
@ -194,7 +180,7 @@ export const deserializeControlGroupFromDashboardSavedObject = (
|
|||
dashboardSavedObject: DashboardSavedObject
|
||||
): Omit<ControlGroupInput, 'id'> | undefined => {
|
||||
if (!dashboardSavedObject.controlGroupInput) return;
|
||||
return rawAttributesToControlGroupInput(dashboardSavedObject.controlGroupInput);
|
||||
return rawControlGroupAttributesToControlGroupInput(dashboardSavedObject.controlGroupInput);
|
||||
};
|
||||
|
||||
export const combineDashboardFiltersWithControlGroupFilters = (
|
||||
|
|
|
@ -10,8 +10,8 @@ import { xor, omit, isEmpty } from 'lodash';
|
|||
import fastIsEqual from 'fast-deep-equal';
|
||||
import { compareFilters, COMPARE_ALL_OPTIONS, type Filter, isFilterPinned } from '@kbn/es-query';
|
||||
|
||||
import { persistableControlGroupInputIsEqual } from '@kbn/controls-plugin/common';
|
||||
import { DashboardContainerInput } from '../..';
|
||||
import { controlGroupInputIsEqual } from './dashboard_control_group';
|
||||
import { DashboardOptions, DashboardPanelMap, DashboardState } from '../../types';
|
||||
import { IEmbeddable } from '../../services/embeddable';
|
||||
|
||||
|
@ -84,7 +84,7 @@ export const diffDashboardState = async ({
|
|||
);
|
||||
const optionsAreEqual = getOptionsAreEqual(originalState.options, newState.options);
|
||||
const filtersAreEqual = getFiltersAreEqual(originalState.filters, newState.filters, true);
|
||||
const controlGroupIsEqual = controlGroupInputIsEqual(
|
||||
const controlGroupIsEqual = persistableControlGroupInputIsEqual(
|
||||
originalState.controlGroupInput,
|
||||
newState.controlGroupInput
|
||||
);
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
*/
|
||||
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { PersistableControlGroupInput } from '@kbn/controls-plugin/common';
|
||||
|
||||
import { Filter, Query, TimeRange } from '../../services/data';
|
||||
import { ViewMode } from '../../services/embeddable';
|
||||
import { DashboardOptions, DashboardPanelMap, DashboardState } from '../../types';
|
||||
import { DashboardContainerControlGroupInput } from '../embeddable';
|
||||
|
||||
export const dashboardStateSlice = createSlice({
|
||||
name: 'dashboardState',
|
||||
|
@ -44,7 +44,7 @@ export const dashboardStateSlice = createSlice({
|
|||
},
|
||||
setControlGroupState: (
|
||||
state,
|
||||
action: PayloadAction<DashboardContainerControlGroupInput | undefined>
|
||||
action: PayloadAction<PersistableControlGroupInput | undefined>
|
||||
) => {
|
||||
state.controlGroupInput = action.payload;
|
||||
},
|
||||
|
|
|
@ -10,6 +10,7 @@ import { assign, cloneDeep } from 'lodash';
|
|||
import { SavedObjectsClientContract } from '@kbn/core/public';
|
||||
import type { ResolvedSimpleSavedObject } from '@kbn/core/public';
|
||||
import { SavedObjectAttributes, SavedObjectReference } from '@kbn/core/types';
|
||||
import { RawControlGroupAttributes } from '@kbn/controls-plugin/common';
|
||||
import { EmbeddableStart } from '../services/embeddable';
|
||||
import { SavedObject, SavedObjectsStart } from '../services/saved_objects';
|
||||
import { Filter, ISearchSource, Query, RefreshInterval } from '../services/data';
|
||||
|
@ -18,7 +19,6 @@ import { createDashboardEditUrl } from '../dashboard_constants';
|
|||
import { extractReferences, injectReferences } from '../../common/saved_dashboard_references';
|
||||
|
||||
import { DashboardOptions } from '../types';
|
||||
import { RawControlGroupAttributes } from '../application';
|
||||
|
||||
export interface DashboardSavedObject extends SavedObject {
|
||||
id?: string;
|
||||
|
|
|
@ -23,6 +23,7 @@ import { BehaviorSubject, Subject } from 'rxjs';
|
|||
|
||||
import { UrlForwardingStart } from '@kbn/url-forwarding-plugin/public';
|
||||
import { VisualizationsStart } from '@kbn/visualizations-plugin/public';
|
||||
import { PersistableControlGroupInput } from '@kbn/controls-plugin/common';
|
||||
import { DataView } from './services/data_views';
|
||||
import { SharePluginStart } from './services/share';
|
||||
import { EmbeddableStart } from './services/embeddable';
|
||||
|
@ -30,11 +31,7 @@ import { DashboardSessionStorage } from './application/lib';
|
|||
import { UsageCollectionSetup } from './services/usage_collection';
|
||||
import { NavigationPublicPluginStart } from './services/navigation';
|
||||
import { Query, RefreshInterval, TimeRange } from './services/data';
|
||||
import {
|
||||
DashboardContainerControlGroupInput,
|
||||
DashboardPanelState,
|
||||
SavedDashboardPanel,
|
||||
} from '../common/types';
|
||||
import { DashboardPanelState, SavedDashboardPanel } from '../common/types';
|
||||
import { SavedObjectsTaggingApi } from './services/saved_objects_tagging_oss';
|
||||
import { DataPublicPluginStart, DataViewsContract } from './services/data';
|
||||
import { ContainerInput, EmbeddableInput, ViewMode } from './services/embeddable';
|
||||
|
@ -74,7 +71,7 @@ export interface DashboardState {
|
|||
panels: DashboardPanelMap;
|
||||
timeRange?: TimeRange;
|
||||
|
||||
controlGroupInput?: DashboardContainerControlGroupInput;
|
||||
controlGroupInput?: PersistableControlGroupInput;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,7 +81,7 @@ export type RawDashboardState = Omit<DashboardState, 'panels'> & { panels: Saved
|
|||
|
||||
export interface DashboardContainerInput extends ContainerInput {
|
||||
dashboardCapabilities?: DashboardAppCapabilities;
|
||||
controlGroupInput?: DashboardContainerControlGroupInput;
|
||||
controlGroupInput?: PersistableControlGroupInput;
|
||||
refreshConfig?: RefreshInterval;
|
||||
isEmbeddedExternally?: boolean;
|
||||
isFullScreenMode: boolean;
|
||||
|
|
|
@ -22,16 +22,15 @@ import {
|
|||
MigrateFunction,
|
||||
MigrateFunctionsObject,
|
||||
} from '@kbn/kibana-utils-plugin/common';
|
||||
import { CONTROL_GROUP_TYPE } from '@kbn/controls-plugin/common';
|
||||
import {
|
||||
CONTROL_GROUP_TYPE,
|
||||
rawControlGroupAttributesToSerializable,
|
||||
serializableToRawControlGroupAttributes,
|
||||
} from '@kbn/controls-plugin/common';
|
||||
import { migrations730 } from './migrations_730';
|
||||
import { SavedDashboardPanel } from '../../common/types';
|
||||
import { migrateMatchAllQuery } from './migrate_match_all_query';
|
||||
import {
|
||||
serializableToRawAttributes,
|
||||
DashboardDoc700To720,
|
||||
DashboardDoc730ToLatest,
|
||||
rawAttributesToSerializable,
|
||||
} from '../../common';
|
||||
import { DashboardDoc700To720, DashboardDoc730ToLatest } from '../../common';
|
||||
import { injectReferences, extractReferences } from '../../common/saved_dashboard_references';
|
||||
import {
|
||||
convertPanelStateToSavedDashboardPanel,
|
||||
|
@ -221,12 +220,15 @@ const migrateByValuePanels =
|
|||
const { attributes } = doc;
|
||||
|
||||
if (attributes?.controlGroupInput) {
|
||||
const controlGroupInput = rawAttributesToSerializable(attributes.controlGroupInput);
|
||||
const controlGroupInput = rawControlGroupAttributesToSerializable(
|
||||
attributes.controlGroupInput
|
||||
);
|
||||
const migratedControlGroupInput = migrate({
|
||||
...controlGroupInput,
|
||||
type: CONTROL_GROUP_TYPE,
|
||||
});
|
||||
attributes.controlGroupInput = serializableToRawAttributes(migratedControlGroupInput);
|
||||
attributes.controlGroupInput =
|
||||
serializableToRawControlGroupAttributes(migratedControlGroupInput);
|
||||
}
|
||||
|
||||
// Skip if panelsJSON is missing otherwise this will cause saved object import to fail when
|
||||
|
|
|
@ -6,8 +6,16 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { isEmpty } from 'lodash';
|
||||
import { ISavedObjectsRepository, SavedObjectAttributes } from '@kbn/core/server';
|
||||
import { EmbeddablePersistableStateService } from '@kbn/embeddable-plugin/common';
|
||||
import {
|
||||
type ControlGroupTelemetry,
|
||||
CONTROL_GROUP_TYPE,
|
||||
RawControlGroupAttributes,
|
||||
} from '@kbn/controls-plugin/common';
|
||||
import { initializeControlGroupTelemetry } from '@kbn/controls-plugin/server';
|
||||
|
||||
import { SavedDashboardPanel730ToLatest } from '../../common';
|
||||
import { injectReferences } from '../../common/saved_dashboard_references';
|
||||
export interface DashboardCollectorData {
|
||||
|
@ -26,6 +34,7 @@ export interface DashboardCollectorData {
|
|||
};
|
||||
};
|
||||
};
|
||||
controls: ControlGroupTelemetry;
|
||||
}
|
||||
|
||||
export const getEmptyDashboardData = (): DashboardCollectorData => ({
|
||||
|
@ -35,6 +44,7 @@ export const getEmptyDashboardData = (): DashboardCollectorData => ({
|
|||
by_value: 0,
|
||||
by_type: {},
|
||||
},
|
||||
controls: initializeControlGroupTelemetry({}),
|
||||
});
|
||||
|
||||
export const getEmptyPanelTypeData = () => ({
|
||||
|
@ -92,6 +102,19 @@ export async function collectDashboardTelemetry(
|
|||
embeddablePersistableStateService: embeddableService,
|
||||
});
|
||||
|
||||
const controlGroupAttributes: RawControlGroupAttributes | undefined =
|
||||
attributes.controlGroupInput as unknown as RawControlGroupAttributes;
|
||||
if (!isEmpty(controlGroupAttributes)) {
|
||||
collectorData.controls = embeddableService.telemetry(
|
||||
{
|
||||
...controlGroupAttributes,
|
||||
type: CONTROL_GROUP_TYPE,
|
||||
id: `DASHBOARD_${CONTROL_GROUP_TYPE}`,
|
||||
},
|
||||
collectorData.controls
|
||||
) as ControlGroupTelemetry;
|
||||
}
|
||||
|
||||
const panels = JSON.parse(
|
||||
attributes.panelsJSON as string
|
||||
) as unknown as SavedDashboardPanel730ToLatest[];
|
||||
|
|
|
@ -60,6 +60,55 @@ export function registerDashboardUsageCollector(
|
|||
},
|
||||
},
|
||||
},
|
||||
controls: {
|
||||
total: { type: 'long' },
|
||||
by_type: {
|
||||
DYNAMIC_KEY: {
|
||||
total: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description: 'The number of this type of control in all Control Groups',
|
||||
},
|
||||
},
|
||||
details: {
|
||||
DYNAMIC_KEY: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description:
|
||||
'Collection of telemetry metrics that embeddable service reports. Will be used for details which are specific to the current control type',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ignore_settings: {
|
||||
DYNAMIC_KEY: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description:
|
||||
'Collection of telemetry metrics that count the number of control groups which have this ignore setting turned on',
|
||||
},
|
||||
},
|
||||
},
|
||||
chaining_system: {
|
||||
DYNAMIC_KEY: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description:
|
||||
'Collection of telemetry metrics that count the number of control groups which are using this chaining system',
|
||||
},
|
||||
},
|
||||
},
|
||||
label_position: {
|
||||
DYNAMIC_KEY: {
|
||||
type: 'long',
|
||||
_meta: {
|
||||
description:
|
||||
'Collection of telemetry metrics that count the number of control groups which have their labels in this position',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -50,6 +50,67 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"controls": {
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "long"
|
||||
},
|
||||
"by_type": {
|
||||
"properties": {
|
||||
"DYNAMIC_KEY": {
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "The number of this type of control in all Control Groups"
|
||||
}
|
||||
},
|
||||
"details": {
|
||||
"properties": {
|
||||
"DYNAMIC_KEY": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Collection of telemetry metrics that embeddable service reports. Will be used for details which are specific to the current control type"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ignore_settings": {
|
||||
"properties": {
|
||||
"DYNAMIC_KEY": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Collection of telemetry metrics that count the number of control groups which have this ignore setting turned on"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"chaining_system": {
|
||||
"properties": {
|
||||
"DYNAMIC_KEY": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Collection of telemetry metrics that count the number of control groups which are using this chaining system"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"label_position": {
|
||||
"properties": {
|
||||
"DYNAMIC_KEY": {
|
||||
"type": "long",
|
||||
"_meta": {
|
||||
"description": "Collection of telemetry metrics that count the number of control groups which have their labels in this position"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue