mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Perfomance] Track time range picker with onPageReady
function (#202889)
## Summary closes https://github.com/elastic/observability-dev/issues/3377 ## Metrics #### `meta.query_range_secs` - The duration of the selected time range in seconds. #### `meta.query_offset_secs` - The offset from "now" to the 'rangeTo'/end' time picker value in seconds. ____ Extend the `onPageReady` function to support date ranges in the meta field. The function should compute the query range in seconds based on the provided time range and report it to telemetry as meta.query_range_secs. If the `rangeTo` is different from 'now', calculate the offset. - A negative offset indicates that the rangeTo is in the past, - a positive offset means it is in the future, - and zero indicates that the rangeTo is exactly 'now'." ### How to instrument To report the selected time range, pass the `rangeFrom` and `rangeTo` . > Failing to pass the correct type will result in TS error. Then, use this data when invoking onPageReady: ``` onPageReady({ meta: { rangeFrom, rangeTo }, }); ``` ### Analysis Meta is flatten field. In order to aggregate the data it's necessary to create a run time field. You can add a field in the 1. select data view (`ebt-kibana-*-performance-metrics`) 2. Add a new field 3. Type double 4. Set value `query_range_secs` ``` def meta = doc[“meta”].size(); if (meta > 0) { def range = doc[“meta.query_range_secs”].size(); if (range > 0) { // Emit the value of ‘meta.target’ emit(Double.parseDouble(doc[“meta.query_range_secs”].value)); } } ``` `query_offset_secs` ``` def meta = doc[“meta”].size(); if (meta > 0) { def offset = doc[“meta.query_offset_secs”].size(); if (offset > 0) { emit(Double.parseDouble(doc[“meta.query_offset_secs”].value)); } } ``` ### Examples <img width="1478" alt="Screenshot 2024-12-09 at 19 51 32" src="https://github.com/user-attachments/assets/72f796e1-4f20-487f-b62a-b6a4aead9a4a"> <img width="1478" alt="Screenshot 2024-12-09 at 19 56 08" src="https://github.com/user-attachments/assets/c278dc3b-e6f3-47ed-9c90-954d71b59161"> <img width="1478" alt="Screenshot 2024-12-09 at 19 53 45 1" src="https://github.com/user-attachments/assets/ef42ecef-48cd-4396-9f5d-c971098d5219"> ### Notes - Instrumented only 2 solutions as an example (dataset and apm services) ### TODO - [x] Update documentation - https://github.com/elastic/kibana/pull/204179 - [ ] Update dashboards (create a runtime field) - [x] Track offset ( we need to know if the user selected now or now) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
492d4d2e5f
commit
bd1c00fd65
18 changed files with 398 additions and 58 deletions
|
@ -128,4 +128,31 @@ describe('trackPerformanceMeasureEntries', () => {
|
|||
value1: 'value1',
|
||||
});
|
||||
});
|
||||
|
||||
test('reports an analytics event with query metadata', () => {
|
||||
setupMockPerformanceObserver([
|
||||
{
|
||||
name: '/',
|
||||
entryType: 'measure',
|
||||
startTime: 100,
|
||||
duration: 1000,
|
||||
detail: {
|
||||
eventName: 'kibana:plugin_render_time',
|
||||
type: 'kibana:performance',
|
||||
meta: {
|
||||
queryRangeSecs: 86400,
|
||||
queryOffsetSecs: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
trackPerformanceMeasureEntries(analyticsClientMock, true);
|
||||
|
||||
expect(analyticsClientMock.reportEvent).toHaveBeenCalledTimes(1);
|
||||
expect(analyticsClientMock.reportEvent).toHaveBeenCalledWith('performance_metric', {
|
||||
duration: 1000,
|
||||
eventName: 'kibana:plugin_render_time',
|
||||
meta: { target: '/', query_range_secs: 86400, query_offset_secs: 0 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,6 +27,7 @@ export function trackPerformanceMeasureEntries(analytics: AnalyticsClient, isDev
|
|||
if (entry.entryType === 'measure' && entry.detail?.type === 'kibana:performance') {
|
||||
const target = entry?.name;
|
||||
const duration = entry.duration;
|
||||
const meta = entry.detail?.meta;
|
||||
const customMetrics = Object.keys(entry.detail?.customMetrics ?? {}).reduce(
|
||||
(acc, metric) => {
|
||||
if (ALLOWED_CUSTOM_METRICS_KEYS_VALUES.includes(metric)) {
|
||||
|
@ -72,6 +73,8 @@ export function trackPerformanceMeasureEntries(analytics: AnalyticsClient, isDev
|
|||
...customMetrics,
|
||||
meta: {
|
||||
target,
|
||||
query_range_secs: meta?.queryRangeSecs,
|
||||
query_offset_secs: meta?.queryOffsetSecs,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
@ -25,6 +25,7 @@ SHARED_DEPS = [
|
|||
"@npm//@elastic/apm-rum-core",
|
||||
"@npm//react",
|
||||
"@npm//react-router-dom",
|
||||
"//packages/kbn-timerange"
|
||||
]
|
||||
|
||||
js_library(
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the "Elastic License
|
||||
* 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import {
|
||||
getDateRange,
|
||||
getOffsetFromNowInSeconds,
|
||||
getTimeDifferenceInSeconds,
|
||||
} from '@kbn/timerange';
|
||||
import { perfomanceMarkers } from '../../performance_markers';
|
||||
import { EventData } from '../performance_context';
|
||||
|
||||
interface PerformanceMeta {
|
||||
queryRangeSecs: number;
|
||||
queryOffsetSecs: number;
|
||||
}
|
||||
|
||||
export function measureInteraction() {
|
||||
performance.mark(perfomanceMarkers.startPageChange);
|
||||
const trackedRoutes: string[] = [];
|
||||
return {
|
||||
/**
|
||||
* Marks the end of the page ready state and measures the performance between the start of the page change and the end of the page ready state.
|
||||
* @param pathname - The pathname of the page.
|
||||
* @param customMetrics - Custom metrics to be included in the performance measure.
|
||||
*/
|
||||
pageReady(pathname: string, eventData?: EventData) {
|
||||
let performanceMeta: PerformanceMeta | undefined;
|
||||
performance.mark(perfomanceMarkers.endPageReady);
|
||||
|
||||
if (eventData?.meta) {
|
||||
const { rangeFrom, rangeTo } = eventData.meta;
|
||||
|
||||
// Convert the date range to epoch timestamps (in milliseconds)
|
||||
const dateRangesInEpoch = getDateRange({
|
||||
from: rangeFrom,
|
||||
to: rangeTo,
|
||||
});
|
||||
|
||||
performanceMeta = {
|
||||
queryRangeSecs: getTimeDifferenceInSeconds(dateRangesInEpoch),
|
||||
queryOffsetSecs:
|
||||
rangeTo === 'now' ? 0 : getOffsetFromNowInSeconds(dateRangesInEpoch.endDate),
|
||||
};
|
||||
}
|
||||
|
||||
if (!trackedRoutes.includes(pathname)) {
|
||||
performance.measure(pathname, {
|
||||
detail: {
|
||||
eventName: 'kibana:plugin_render_time',
|
||||
type: 'kibana:performance',
|
||||
customMetrics: eventData?.customMetrics,
|
||||
meta: performanceMeta,
|
||||
},
|
||||
start: perfomanceMarkers.startPageChange,
|
||||
end: perfomanceMarkers.endPageReady,
|
||||
});
|
||||
trackedRoutes.push(pathname);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { measureInteraction } from '.';
|
||||
import { perfomanceMarkers } from '../../performance_markers';
|
||||
|
||||
describe('measureInteraction', () => {
|
||||
afterAll(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
performance.mark = jest.fn();
|
||||
performance.measure = jest.fn();
|
||||
});
|
||||
|
||||
it('should mark the start of the page change', () => {
|
||||
measureInteraction();
|
||||
expect(performance.mark).toHaveBeenCalledWith(perfomanceMarkers.startPageChange);
|
||||
});
|
||||
|
||||
it('should mark the end of the page ready state and measure performance', () => {
|
||||
const interaction = measureInteraction();
|
||||
const pathname = '/test-path';
|
||||
interaction.pageReady(pathname);
|
||||
|
||||
expect(performance.mark).toHaveBeenCalledWith(perfomanceMarkers.endPageReady);
|
||||
expect(performance.measure).toHaveBeenCalledWith(pathname, {
|
||||
detail: {
|
||||
eventName: 'kibana:plugin_render_time',
|
||||
type: 'kibana:performance',
|
||||
},
|
||||
start: perfomanceMarkers.startPageChange,
|
||||
end: perfomanceMarkers.endPageReady,
|
||||
});
|
||||
});
|
||||
|
||||
it('should include custom metrics and meta in the performance measure', () => {
|
||||
const interaction = measureInteraction();
|
||||
const pathname = '/test-path';
|
||||
const eventData = {
|
||||
customMetrics: { key1: 'foo-metric', value1: 100 },
|
||||
meta: { rangeFrom: 'now-15m', rangeTo: 'now' },
|
||||
};
|
||||
|
||||
interaction.pageReady(pathname, eventData);
|
||||
|
||||
expect(performance.mark).toHaveBeenCalledWith(perfomanceMarkers.endPageReady);
|
||||
expect(performance.measure).toHaveBeenCalledWith(pathname, {
|
||||
detail: {
|
||||
eventName: 'kibana:plugin_render_time',
|
||||
type: 'kibana:performance',
|
||||
customMetrics: eventData.customMetrics,
|
||||
meta: {
|
||||
queryRangeSecs: 900,
|
||||
queryOffsetSecs: 0,
|
||||
},
|
||||
},
|
||||
end: 'end::pageReady',
|
||||
start: 'start::pageChange',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle absolute date format correctly', () => {
|
||||
const interaction = measureInteraction();
|
||||
const pathname = '/test-path';
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(1733704200000); // 2024-12-09T00:30:00Z
|
||||
|
||||
const eventData = {
|
||||
meta: { rangeFrom: '2024-12-09T00:00:00Z', rangeTo: '2024-12-09T00:30:00Z' },
|
||||
};
|
||||
|
||||
interaction.pageReady(pathname, eventData);
|
||||
|
||||
expect(performance.mark).toHaveBeenCalledWith(perfomanceMarkers.endPageReady);
|
||||
expect(performance.measure).toHaveBeenCalledWith(pathname, {
|
||||
detail: {
|
||||
eventName: 'kibana:plugin_render_time',
|
||||
type: 'kibana:performance',
|
||||
customMetrics: undefined,
|
||||
meta: {
|
||||
queryRangeSecs: 1800,
|
||||
queryOffsetSecs: 0,
|
||||
},
|
||||
},
|
||||
end: 'end::pageReady',
|
||||
start: 'start::pageChange',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle negative offset when rangeTo is in the past', () => {
|
||||
const interaction = measureInteraction();
|
||||
const pathname = '/test-path';
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(1733704200000); // 2024-12-09T00:30:00Z
|
||||
|
||||
const eventData = {
|
||||
meta: { rangeFrom: '2024-12-08T00:00:00Z', rangeTo: '2024-12-09T00:00:00Z' },
|
||||
};
|
||||
|
||||
interaction.pageReady(pathname, eventData);
|
||||
|
||||
expect(performance.mark).toHaveBeenCalledWith(perfomanceMarkers.endPageReady);
|
||||
expect(performance.measure).toHaveBeenCalledWith(pathname, {
|
||||
detail: {
|
||||
eventName: 'kibana:plugin_render_time',
|
||||
type: 'kibana:performance',
|
||||
customMetrics: undefined,
|
||||
meta: {
|
||||
queryRangeSecs: 86400,
|
||||
queryOffsetSecs: -1800,
|
||||
},
|
||||
},
|
||||
end: 'end::pageReady',
|
||||
start: 'start::pageChange',
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle positive offset when rangeTo is in the future', () => {
|
||||
const interaction = measureInteraction();
|
||||
const pathname = '/test-path';
|
||||
jest.spyOn(global.Date, 'now').mockReturnValue(1733704200000); // 2024-12-09T00:30:00Z
|
||||
|
||||
const eventData = {
|
||||
meta: { rangeFrom: '2024-12-08T01:00:00Z', rangeTo: '2024-12-09T01:00:00Z' },
|
||||
};
|
||||
|
||||
interaction.pageReady(pathname, eventData);
|
||||
|
||||
expect(performance.mark).toHaveBeenCalledWith(perfomanceMarkers.endPageReady);
|
||||
expect(performance.measure).toHaveBeenCalledWith(pathname, {
|
||||
detail: {
|
||||
eventName: 'kibana:plugin_render_time',
|
||||
type: 'kibana:performance',
|
||||
customMetrics: undefined,
|
||||
meta: {
|
||||
queryRangeSecs: 86400,
|
||||
queryOffsetSecs: 1800,
|
||||
},
|
||||
},
|
||||
end: 'end::pageReady',
|
||||
start: 'start::pageChange',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not measure the same route twice', () => {
|
||||
const interaction = measureInteraction();
|
||||
const pathname = '/test-path';
|
||||
|
||||
interaction.pageReady(pathname);
|
||||
interaction.pageReady(pathname);
|
||||
|
||||
expect(performance.measure).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
|
@ -10,38 +10,19 @@
|
|||
import React, { useMemo, useState } from 'react';
|
||||
import { afterFrame } from '@elastic/apm-rum-core';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { perfomanceMarkers } from '../performance_markers';
|
||||
import { PerformanceApi, PerformanceContext } from './use_performance_context';
|
||||
import { PerformanceMetricEvent } from '../../performance_metric_events';
|
||||
import { measureInteraction } from './measure_interaction';
|
||||
|
||||
export type CustomMetrics = Omit<PerformanceMetricEvent, 'eventName' | 'meta' | 'duration'>;
|
||||
|
||||
function measureInteraction() {
|
||||
performance.mark(perfomanceMarkers.startPageChange);
|
||||
const trackedRoutes: string[] = [];
|
||||
return {
|
||||
/**
|
||||
* Marks the end of the page ready state and measures the performance between the start of the page change and the end of the page ready state.
|
||||
* @param pathname - The pathname of the page.
|
||||
* @param customMetrics - Custom metrics to be included in the performance measure.
|
||||
*/
|
||||
pageReady(pathname: string, customMetrics?: CustomMetrics) {
|
||||
performance.mark(perfomanceMarkers.endPageReady);
|
||||
|
||||
if (!trackedRoutes.includes(pathname)) {
|
||||
performance.measure(pathname, {
|
||||
detail: {
|
||||
eventName: 'kibana:plugin_render_time',
|
||||
type: 'kibana:performance',
|
||||
customMetrics,
|
||||
},
|
||||
start: perfomanceMarkers.startPageChange,
|
||||
end: perfomanceMarkers.endPageReady,
|
||||
});
|
||||
trackedRoutes.push(pathname);
|
||||
}
|
||||
},
|
||||
};
|
||||
export interface Meta {
|
||||
rangeFrom: string;
|
||||
rangeTo: string;
|
||||
}
|
||||
export interface EventData {
|
||||
customMetrics?: CustomMetrics;
|
||||
meta?: Meta;
|
||||
}
|
||||
|
||||
export function PerformanceContextProvider({ children }: { children: React.ReactElement }) {
|
||||
|
@ -61,9 +42,9 @@ export function PerformanceContextProvider({ children }: { children: React.React
|
|||
|
||||
const api = useMemo<PerformanceApi>(
|
||||
() => ({
|
||||
onPageReady(customMetrics) {
|
||||
onPageReady(eventData) {
|
||||
if (isRendered) {
|
||||
interaction.pageReady(location.pathname, customMetrics);
|
||||
interaction.pageReady(location.pathname, eventData);
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
|
|
@ -8,18 +8,22 @@
|
|||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CustomMetrics } from './performance_context';
|
||||
import type { CustomMetrics, Meta } from './performance_context';
|
||||
import { usePerformanceContext } from '../../..';
|
||||
|
||||
export const usePageReady = (state: { customMetrics?: CustomMetrics; isReady: boolean }) => {
|
||||
export const usePageReady = (state: {
|
||||
customMetrics?: CustomMetrics;
|
||||
isReady: boolean;
|
||||
meta?: Meta;
|
||||
}) => {
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
|
||||
const [isReported, setIsReported] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (state.isReady && !isReported) {
|
||||
onPageReady(state.customMetrics);
|
||||
onPageReady({ customMetrics: state.customMetrics, meta: state.meta });
|
||||
setIsReported(true);
|
||||
}
|
||||
}, [isReported, onPageReady, state.customMetrics, state.isReady]);
|
||||
}, [isReported, onPageReady, state.customMetrics, state.isReady, state.meta]);
|
||||
};
|
||||
|
|
|
@ -8,14 +8,13 @@
|
|||
*/
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
import { CustomMetrics } from './performance_context';
|
||||
|
||||
import type { EventData } from './performance_context';
|
||||
export interface PerformanceApi {
|
||||
/**
|
||||
* Marks the end of the page ready state and measures the performance between the start of the page change and the end of the page ready state.
|
||||
* @param customMetrics - Custom metrics to be included in the performance measure.
|
||||
* @param eventData - Data to send with the performance measure, conforming the structure of a {@link EventData}.
|
||||
*/
|
||||
onPageReady(customMetrics?: CustomMetrics): void;
|
||||
onPageReady(eventData?: EventData): void;
|
||||
}
|
||||
|
||||
export const PerformanceContext = createContext<PerformanceApi | undefined>(undefined);
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.tsx"],
|
||||
"kbn_references": [
|
||||
"@kbn/logging-mocks"
|
||||
],
|
||||
"kbn_references": ["@kbn/logging-mocks", "@kbn/timerange"],
|
||||
"exclude": ["target/**/*"]
|
||||
}
|
||||
|
|
28
packages/kbn-io-ts-utils/BUILD.bazel
Normal file
28
packages/kbn-io-ts-utils/BUILD.bazel
Normal file
|
@ -0,0 +1,28 @@
|
|||
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
|
||||
|
||||
SRCS = glob(
|
||||
[
|
||||
"**/*.ts",
|
||||
"**/*.js",
|
||||
],
|
||||
exclude = [
|
||||
"**/*.config.js",
|
||||
"**/*.mock.*",
|
||||
"**/*.test.*",
|
||||
"**/*.stories.*",
|
||||
"**/__snapshots__/**",
|
||||
"**/integration_tests/**",
|
||||
"**/mocks/**",
|
||||
"**/scripts/**",
|
||||
"**/storybook/**",
|
||||
"**/test_fixtures/**",
|
||||
"**/test_helpers/**",
|
||||
],
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = "kbn-io-ts-utils",
|
||||
package_name = "@kbn/io-ts-utils",
|
||||
srcs = ["package.json"] + SRCS,
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
28
packages/kbn-timerange/BUILD.bazel
Normal file
28
packages/kbn-timerange/BUILD.bazel
Normal file
|
@ -0,0 +1,28 @@
|
|||
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
|
||||
|
||||
SRCS = glob(
|
||||
[
|
||||
"**/*.ts",
|
||||
"**/*.js",
|
||||
],
|
||||
exclude = [
|
||||
"**/*.config.js",
|
||||
"**/*.mock.*",
|
||||
"**/*.test.*",
|
||||
"**/*.stories.*",
|
||||
"**/__snapshots__/**",
|
||||
"**/integration_tests/**",
|
||||
"**/mocks/**",
|
||||
"**/scripts/**",
|
||||
"**/storybook/**",
|
||||
"**/test_fixtures/**",
|
||||
"**/test_helpers/**",
|
||||
],
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = "kbn-timerange",
|
||||
package_name = "@kbn/timerange",
|
||||
srcs = ["package.json"] + SRCS,
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -7,4 +7,9 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
export { getDateRange, getDateISORange } from './src';
|
||||
export {
|
||||
getDateRange,
|
||||
getDateISORange,
|
||||
getOffsetFromNowInSeconds,
|
||||
getTimeDifferenceInSeconds,
|
||||
} from './src';
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
{
|
||||
"type": "shared-common",
|
||||
"id": "@kbn/timerange",
|
||||
"owner": [
|
||||
"@elastic/obs-ux-logs-team"
|
||||
],
|
||||
"group": "observability",
|
||||
"visibility": "private"
|
||||
}
|
||||
"owner": ["@elastic/obs-ux-logs-team"],
|
||||
"group": "platform",
|
||||
"visibility": "shared"
|
||||
}
|
||||
|
|
|
@ -52,3 +52,24 @@ export function getDateISORange({ from, to }: { from: string; to: string }) {
|
|||
endDate,
|
||||
};
|
||||
}
|
||||
|
||||
export function getTimeDifferenceInSeconds({
|
||||
startDate,
|
||||
endDate,
|
||||
}: {
|
||||
startDate: number;
|
||||
endDate: number;
|
||||
}): number {
|
||||
if (!startDate || !endDate || startDate > endDate) {
|
||||
throw new Error(`Invalid Dates: from: ${startDate}, to: ${endDate}`);
|
||||
}
|
||||
|
||||
const rangeInSeconds = (endDate - startDate) / 1000;
|
||||
return Math.round(rangeInSeconds);
|
||||
}
|
||||
|
||||
export function getOffsetFromNowInSeconds(epochDate: number) {
|
||||
const now = Date.now();
|
||||
|
||||
return Math.round((epochDate - now) / 1000);
|
||||
}
|
||||
|
|
|
@ -180,6 +180,9 @@ export function ServiceInventory() {
|
|||
const [renderedItems, setRenderedItems] = useState<ServiceListItem[]>([]);
|
||||
const mainStatisticsFetch = useServicesMainStatisticsFetcher(debouncedSearchQuery);
|
||||
const { mainStatisticsData, mainStatisticsStatus } = mainStatisticsFetch;
|
||||
const {
|
||||
query: { rangeFrom, rangeTo },
|
||||
} = useApmParams('/services');
|
||||
|
||||
const displayHealthStatus = mainStatisticsData.items.some((item) => 'healthStatus' in item);
|
||||
|
||||
|
@ -285,9 +288,11 @@ export function ServiceInventory() {
|
|||
mainStatisticsStatus === FETCH_STATUS.SUCCESS &&
|
||||
comparisonFetch.status === FETCH_STATUS.SUCCESS
|
||||
) {
|
||||
onPageReady();
|
||||
onPageReady({
|
||||
meta: { rangeFrom, rangeTo },
|
||||
});
|
||||
}
|
||||
}, [mainStatisticsStatus, comparisonFetch.status, onPageReady]);
|
||||
}, [mainStatisticsStatus, comparisonFetch.status, onPageReady, rangeFrom, rangeTo]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -186,7 +186,9 @@ export function ServiceMap({
|
|||
}
|
||||
|
||||
if (status === FETCH_STATUS.SUCCESS) {
|
||||
onPageReady();
|
||||
onPageReady({
|
||||
meta: { rangeFrom: start, rangeTo: end },
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -135,15 +135,20 @@ export function TraceList({ response }: Props) {
|
|||
const { data: { items } = { items: [] }, status } = response;
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
|
||||
const { query } = useApmParams('/traces');
|
||||
const {
|
||||
query,
|
||||
query: { rangeFrom, rangeTo },
|
||||
} = useApmParams('/traces');
|
||||
|
||||
const traceListColumns = useMemo(() => getTraceListColumns({ query }), [query]);
|
||||
|
||||
useEffect(() => {
|
||||
if (status === FETCH_STATUS.SUCCESS) {
|
||||
onPageReady();
|
||||
onPageReady({
|
||||
meta: { rangeFrom, rangeTo },
|
||||
});
|
||||
}
|
||||
}, [status, onPageReady]);
|
||||
}, [status, onPageReady, rangeFrom, rangeTo]);
|
||||
|
||||
return (
|
||||
<ManagedTable
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
EuiPanel,
|
||||
|
@ -28,10 +27,12 @@ import {
|
|||
summaryPanelQualityTooltipText,
|
||||
} from '../../../../common/translations';
|
||||
import { mapPercentagesToQualityCounts } from '../../quality_indicator';
|
||||
import { useDatasetQualityFilters } from '../../../hooks/use_dataset_quality_filters';
|
||||
import { VerticalRule } from '../../common/vertical_rule';
|
||||
|
||||
export function DatasetsQualityIndicators() {
|
||||
const { onPageReady } = usePerformanceContext();
|
||||
const { timeRange } = useDatasetQualityFilters();
|
||||
const {
|
||||
datasetsQuality,
|
||||
isDatasetsQualityLoading,
|
||||
|
@ -45,10 +46,16 @@ export function DatasetsQualityIndicators() {
|
|||
|
||||
if (!isDatasetsQualityLoading && (numberOfDatasets || numberOfDocuments)) {
|
||||
onPageReady({
|
||||
key1: 'datasets',
|
||||
value1: numberOfDatasets,
|
||||
key2: 'documents',
|
||||
value2: numberOfDocuments,
|
||||
customMetrics: {
|
||||
key1: 'datasets',
|
||||
value1: numberOfDatasets,
|
||||
key2: 'documents',
|
||||
value2: numberOfDocuments,
|
||||
},
|
||||
meta: {
|
||||
rangeFrom: timeRange.from,
|
||||
rangeTo: timeRange.to,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue