Skip to content

Commit

Permalink
[Synthetics] [ON Week] Refactor Synthetics Overview page for increase…
Browse files Browse the repository at this point in the history
…d scalability (elastic#187092)

## Summary

Resolves elastic#183622.

This is part of some ON Week PoC work I did that introduces [React
Window](https://github.com/bvaughn/react-window) and its [Infinite
Loader](https://github.com/bvaughn/react-window-infinite-loader) to the
Synthetics Overview page.

Additionally, I have refactored the way that duration fetching is done
for the overview cards; the fetching is now handled at a top-level and
as-needed during the infinite scroll. This results in a page that is
scrollable all the way to the end of very large amounts of monitors. The
example deployment I'm using has about 900 monitors, and in the latest
versions of Kibana this dataset causes the overview page to crash the
tab.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Shahzad <shahzad31comp@gmail.com>
  • Loading branch information
3 people committed Sep 4, 2024
1 parent 7cb2a59 commit fd704de
Show file tree
Hide file tree
Showing 32 changed files with 738 additions and 900 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1201,11 +1201,13 @@
"react-use": "^15.3.8",
"react-virtualized": "^9.22.5",
"react-window": "^1.8.10",
"react-window-infinite-loader": "^1.0.9",
"reduce-reducers": "^1.0.4",
"redux": "^4.2.1",
"redux-actions": "^2.6.5",
"redux-devtools-extension": "^2.13.8",
"redux-saga": "^1.1.3",
"redux-saga-testing": "^2.0.2",
"redux-thunk": "^2.4.2",
"redux-thunks": "^1.0.0",
"reflect-metadata": "^0.2.1",
Expand Down Expand Up @@ -1597,6 +1599,7 @@
"@types/react-test-renderer": "^17.0.2",
"@types/react-virtualized": "^9.21.22",
"@types/react-window": "^1.8.8",
"@types/react-window-infinite-loader": "^1.0.9",
"@types/redux-actions": "^2.6.1",
"@types/resolve": "^1.20.1",
"@types/seedrandom": ">=2.0.0 <4.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export enum SYNTHETICS_API_URLS {
SYNTHETICS_OVERVIEW = '/internal/synthetics/overview',
PINGS = '/internal/synthetics/pings',
PING_STATUSES = '/internal/synthetics/ping_statuses',
OVERVIEW_TRENDS = '/internal/synthetics/overview_trends',
OVERVIEW_STATUS = `/internal/synthetics/overview_status`,
INDEX_SIZE = `/internal/synthetics/index_size`,
AGENT_POLICIES = `/internal/synthetics/agent_policies`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ export const MonitorOverviewItemCodec = t.intersection([
schedule: t.string,
}),
t.partial({
status: t.string,
projectId: t.string,
}),
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
export * from './synthetics_monitor';
export * from './monitor_validation';
export * from './default_alerts';
export * from './overview';
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export interface TrendKey {
configId: string;
locationId: string;
}

export type TrendRequest = TrendKey & { schedule: string };

export interface TrendDatum {
x: number;
y: number;
}

export interface OverviewTrend {
configId: string;
locationId: string;
data: TrendDatum[];
count: number;
min: number;
max: number;
avg: number;
sum: number;
median: number;
}

export type TrendTable = Record<string, OverviewTrend | null>;
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ import { useKey } from 'react-use';
import { OverviewLoader } from '../overview_loader';
import { useFilteredGroupMonitors } from './use_filtered_group_monitors';
import { MonitorOverviewItem } from '../../types';
import { FlyoutParamProps, OverviewGridItem } from '../overview_grid_item';
import { selectOverviewStatus } from '../../../../../state/overview_status';
import { MetricItem } from '../metric_item';
import { FlyoutParamProps } from '../types';

const PER_ROW = 4;
const DEFAULT_ROW_SIZE = 2;
Expand Down Expand Up @@ -163,7 +164,7 @@ export const GroupGridItem = ({
key={`${monitor.id}-${monitor.location?.id}`}
data-test-subj="syntheticsOverviewGridItem"
>
<OverviewGridItem monitor={monitor} onClick={setFlyoutConfigCallback} />
<MetricItem monitor={monitor} onClick={setFlyoutConfigCallback} />
</EuiFlexItem>
))}
</EuiFlexGrid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import {
import { useFilters } from '../../../common/monitor_filters/use_filters';
import { GroupGridItem } from './grid_group_item';
import { ConfigKey, MonitorOverviewItem } from '../../../../../../../../common/runtime_types';
import { FlyoutParamProps } from '../overview_grid_item';
import { selectOverviewState, selectServiceLocationsState } from '../../../../../state';
import { FlyoutParamProps } from '../types';

export const GridItemsByGroup = ({
loaded,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,21 @@
*/
import { i18n } from '@kbn/i18n';
import React, { useState } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { css } from '@emotion/react';
import { Chart, Settings, Metric, MetricTrendShape } from '@elastic/charts';
import { EuiPanel } from '@elastic/eui';
import { EuiPanel, EuiSpacer } from '@elastic/eui';
import { DARK_THEME } from '@elastic/charts';
import { useTheme } from '@kbn/observability-shared-plugin/public';
import { useDispatch, useSelector } from 'react-redux';
import moment from 'moment';
import { useSelector, useDispatch } from 'react-redux';

import { MetricItemBody } from './metric_item/metric_item_body';
import { MetricItemExtra } from './metric_item/metric_item_extra';
import { selectErrorPopoverState, toggleErrorPopoverOpen } from '../../../../state';
import {
selectErrorPopoverState,
selectOverviewTrends,
toggleErrorPopoverOpen,
} from '../../../../state';
import { useLocationName, useStatusByLocationOverview } from '../../../../hooks';
import { formatDuration } from '../../../../utils/formatting';
import { MonitorOverviewItem } from '../../../../../../../common/runtime_types';
Expand All @@ -26,6 +31,9 @@ import {
toggleTestNowFlyoutAction,
} from '../../../../state/manual_test_runs';
import { MetricItemIcon } from './metric_item_icon';
import { MetricItemExtra } from './metric_item/metric_item_extra';

const METRIC_ITEM_HEIGHT = 160;

export const getColor = (
theme: ReturnType<typeof useTheme>,
Expand All @@ -49,20 +57,14 @@ export const getColor = (

export const MetricItem = ({
monitor,
stats,
data,
onClick,
style,
}: {
monitor: MonitorOverviewItem;
data: Array<{ x: number; y: number }>;
stats: {
medianDuration: number;
avgDuration: number;
minDuration: number;
maxDuration: number;
};
style?: React.CSSProperties;
onClick: (params: { id: string; configId: string; location: string; locationId: string }) => void;
}) => {
const trendData = useSelector(selectOverviewTrends)[monitor.configId + monitor.location.id];
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const isErrorPopoverOpen = useSelector(selectErrorPopoverState);
const locationName = useLocationName(monitor);
Expand All @@ -77,7 +79,10 @@ export const MetricItem = ({
const dispatch = useDispatch();

return (
<div data-test-subj={`${monitor.name}-metric-item`} style={{ height: '160px' }}>
<div
data-test-subj={`${monitor.name}-${monitor.location.id}-metric-item`}
style={style ?? { height: METRIC_ITEM_HEIGHT }}
>
<EuiPanel
data-test-subj={`${monitor.name}-metric-item-${locationName}-${status}`}
paddingSize="none"
Expand Down Expand Up @@ -136,10 +141,26 @@ export const MetricItem = ({
{
title: monitor.name,
subtitle: locationName,
value: stats.medianDuration,
value: trendData?.median ?? 0,
trendShape: MetricTrendShape.Area,
trend: data,
extra: <MetricItemExtra stats={stats} />,
trend: trendData?.data ?? [],
extra: trendData ? (
<MetricItemExtra
stats={{
medianDuration: trendData.median,
minDuration: trendData.min,
maxDuration: trendData.max,
avgDuration: trendData.avg,
}}
/>
) : (
<div>
<FormattedMessage
defaultMessage="Loading metrics"
id="xpack.synthetics.overview.metricItem.loadingMessage"
/>
</div>
),
valueFormatter: (d: number) => formatDuration(d),
color: getColor(theme, monitor.isEnabled, status),
body: <MetricItemBody monitor={monitor} />,
Expand Down Expand Up @@ -167,6 +188,7 @@ export const MetricItem = ({
/>
)}
</EuiPanel>
<EuiSpacer size="s" />
</div>
);
};
Loading

0 comments on commit fd704de

Please sign in to comment.