[v11.2.x] Explore metrics: Improve performance for build layout (#92264)
Explore metrics: Improve performance for build layout (#92238)
* revert buildLayout
* filter metric names using metricPrefix using regex
* build groups with all the metric names and only build them once
* remove commented code
* use the metrics search input results to build the prefix select options
* simplify prefix regex because we do not have to do it at the same time as the metrics search input regex
(cherry picked from commit 130a86d9c7)
Co-authored-by: Brendan O'Handley <brendan.ohandley@grafana.com>
This commit is contained in:
co-authored by
Brendan O'Handley
parent
a919c7561b
commit
c7380fe642
@@ -29,7 +29,6 @@ import {
|
||||
import { Alert, Field, Icon, IconButton, InlineSwitch, Input, Select, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { Trans } from 'app/core/internationalization';
|
||||
|
||||
import { DataTrail } from '../DataTrail';
|
||||
import { MetricScene } from '../MetricScene';
|
||||
import { StatusWrapper } from '../StatusWrapper';
|
||||
import { Node, Parser } from '../groop/parser';
|
||||
@@ -214,10 +213,20 @@ export class MetricSelectScene extends SceneObjectBase<MetricSelectSceneState> i
|
||||
try {
|
||||
const response = await getMetricNames(datasourceUid, timeRange, match, MAX_METRIC_NAMES);
|
||||
const searchRegex = createJSRegExpFromSearchTerms(getMetricSearch(this));
|
||||
const metricNames = searchRegex
|
||||
let metricNames = searchRegex
|
||||
? response.data.filter((metric) => !searchRegex || searchRegex.test(metric))
|
||||
: response.data;
|
||||
|
||||
// use this to generate groups for metric prefix
|
||||
const filteredMetricNames = metricNames;
|
||||
|
||||
// filter the remaining metrics with the metric prefix
|
||||
const metricPrefix = this.state.metricPrefix;
|
||||
if (metricPrefix && metricPrefix !== 'all') {
|
||||
const prefixRegex = new RegExp(`(^${metricPrefix}.*)`, 'igy');
|
||||
metricNames = metricNames.filter((metric) => !prefixRegex || prefixRegex.test(metric));
|
||||
}
|
||||
|
||||
const metricNamesWarning = response.limitReached
|
||||
? `This feature will only return up to ${MAX_METRIC_NAMES} metric names for performance reasons. ` +
|
||||
`This limit is being exceeded for the current data source. ` +
|
||||
@@ -225,7 +234,11 @@ export class MetricSelectScene extends SceneObjectBase<MetricSelectSceneState> i
|
||||
: undefined;
|
||||
|
||||
let bodyLayout = this.state.body;
|
||||
const rootGroupNode = await this.generateGroups(metricNames);
|
||||
|
||||
let rootGroupNode = this.state.rootGroup;
|
||||
|
||||
// generate groups based on the search metrics input
|
||||
rootGroupNode = await this.generateGroups(filteredMetricNames);
|
||||
|
||||
this.setState({
|
||||
metricNames,
|
||||
@@ -311,6 +324,21 @@ export class MetricSelectScene extends SceneObjectBase<MetricSelectSceneState> i
|
||||
this.buildLayout();
|
||||
}
|
||||
|
||||
private sortedPreviewMetrics() {
|
||||
return Object.values(this.previewCache).sort((a, b) => {
|
||||
if (a.isEmpty && b.isEmpty) {
|
||||
return a.index - b.index;
|
||||
}
|
||||
if (a.isEmpty) {
|
||||
return 1;
|
||||
}
|
||||
if (b.isEmpty) {
|
||||
return -1;
|
||||
}
|
||||
return a.index - b.index;
|
||||
});
|
||||
}
|
||||
|
||||
private async buildLayout() {
|
||||
// Temp hack when going back to select metric scene and variable updates
|
||||
if (this.ignoreNextUpdate) {
|
||||
@@ -318,67 +346,32 @@ export class MetricSelectScene extends SceneObjectBase<MetricSelectSceneState> i
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.state.rootGroup) {
|
||||
const rootGroupNode = await this.generateGroups(this.state.metricNames);
|
||||
this.setState({ rootGroup: rootGroupNode });
|
||||
}
|
||||
const children: SceneFlexItem[] = [];
|
||||
|
||||
const children = await this.populateFilterableViewLayout();
|
||||
const rowTemplate = this.state.showPreviews ? ROW_PREVIEW_HEIGHT : ROW_CARD_HEIGHT;
|
||||
this.state.body.setState({ children, autoRows: rowTemplate });
|
||||
}
|
||||
|
||||
private async populateFilterableViewLayout() {
|
||||
const trail = getTrailFor(this);
|
||||
|
||||
const metricsList = this.sortedPreviewMetrics();
|
||||
|
||||
// Get the current filters to determine the count of them
|
||||
// Which is required for `getPreviewPanelFor`
|
||||
const filters = getFilters(this);
|
||||
|
||||
let rootGroupNode = this.state.rootGroup;
|
||||
if (!rootGroupNode) {
|
||||
rootGroupNode = await this.generateGroups(this.state.metricNames);
|
||||
this.setState({ rootGroup: rootGroupNode });
|
||||
}
|
||||
|
||||
const children: SceneFlexItem[] = [];
|
||||
|
||||
for (const [groupKey, groupNode] of rootGroupNode.groups) {
|
||||
if (this.state.metricPrefix !== METRIC_PREFIX_ALL && this.state.metricPrefix !== groupKey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const [_, value] of groupNode.groups) {
|
||||
const panels = await this.populatePanels(trail, filters, value.values);
|
||||
children.push(...panels);
|
||||
}
|
||||
|
||||
const morePanelsMaybe = await this.populatePanels(trail, filters, groupNode.values);
|
||||
children.push(...morePanelsMaybe);
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
private async populatePanels(trail: DataTrail, filters: ReturnType<typeof getFilters>, values: string[]) {
|
||||
const currentFilterCount = filters?.length || 0;
|
||||
|
||||
const previewPanelLayoutItems: SceneFlexItem[] = [];
|
||||
for (let index = 0; index < values.length; index++) {
|
||||
const metricName = values[index];
|
||||
const metric: MetricPanel = this.previewCache[metricName] ?? { name: metricName, index, loaded: false };
|
||||
const metadata = await trail.getMetricMetadata(metricName);
|
||||
for (let index = 0; index < metricsList.length; index++) {
|
||||
const metric = metricsList[index];
|
||||
const metadata = await trail.getMetricMetadata(metric.name);
|
||||
const description = getMetricDescription(metadata);
|
||||
|
||||
if (this.state.showPreviews) {
|
||||
if (metric.itemRef && metric.isPanel) {
|
||||
previewPanelLayoutItems.push(metric.itemRef.resolve());
|
||||
children.push(metric.itemRef.resolve());
|
||||
continue;
|
||||
}
|
||||
const panel = getPreviewPanelFor(metric.name, index, currentFilterCount, description);
|
||||
|
||||
metric.itemRef = panel.getRef();
|
||||
metric.isPanel = true;
|
||||
previewPanelLayoutItems.push(panel);
|
||||
children.push(panel);
|
||||
} else {
|
||||
const panel = new SceneCSSGridItem({
|
||||
$variables: new SceneVariableSet({
|
||||
@@ -388,11 +381,13 @@ export class MetricSelectScene extends SceneObjectBase<MetricSelectSceneState> i
|
||||
});
|
||||
metric.itemRef = panel.getRef();
|
||||
metric.isPanel = false;
|
||||
previewPanelLayoutItems.push(panel);
|
||||
children.push(panel);
|
||||
}
|
||||
}
|
||||
|
||||
return previewPanelLayoutItems;
|
||||
const rowTemplate = this.state.showPreviews ? ROW_PREVIEW_HEIGHT : ROW_CARD_HEIGHT;
|
||||
|
||||
this.state.body.setState({ children, autoRows: rowTemplate });
|
||||
}
|
||||
|
||||
public updateMetricPanel = (metric: string, isLoaded?: boolean, isEmpty?: boolean) => {
|
||||
@@ -416,7 +411,7 @@ export class MetricSelectScene extends SceneObjectBase<MetricSelectSceneState> i
|
||||
|
||||
public onPrefixFilterChange = (val: SelectableValue) => {
|
||||
this.setState({ metricPrefix: val.value });
|
||||
this.buildLayout();
|
||||
this._refreshMetricNames();
|
||||
};
|
||||
|
||||
public reportPrefixFilterInteraction = (isMenuOpen: boolean) => {
|
||||
|
||||
Reference in New Issue
Block a user