diff --git a/public/app/features/trails/MetricSelectScene.tsx b/public/app/features/trails/MetricSelectScene.tsx index 65f3169984c..74cf94b6f40 100644 --- a/public/app/features/trails/MetricSelectScene.tsx +++ b/public/app/features/trails/MetricSelectScene.tsx @@ -115,7 +115,7 @@ export class MetricSelectScene extends SceneObjectBase { return; } - const searchRegex = new RegExp(this.state.searchQuery ?? '.*'); + const searchRegex = createSearchRegExp(this.state.searchQuery); const metricNames = variable.state.options; const sortedMetricNames = trail.state.metric !== undefined ? sortRelatedMetrics(metricNames, trail.state.metric) : metricNames; @@ -126,7 +126,8 @@ export class MetricSelectScene extends SceneObjectBase { const metric = sortedMetricNames[index]; const metricName = String(metric.value); - if (!metricName.match(searchRegex)) { + + if (searchRegex && !searchRegex.test(metricName)) { continue; } @@ -319,3 +320,26 @@ function getStyles(theme: GrafanaTheme2) { }), }; } + +// Consider any sequence of characters not permitted for metric names as a sepratator +const splitSeparator = /[^a-z0-9_:]+/; + +function createSearchRegExp(spaceSeparatedMetricNames?: string) { + if (!spaceSeparatedMetricNames) { + return null; + } + const searchParts = spaceSeparatedMetricNames + ?.toLowerCase() + .split(splitSeparator) + .filter((part) => part.length > 0) + .map((part) => `(?=(.*${part}.*))`); + + if (searchParts.length === 0) { + return null; + } + + const regex = searchParts.join(''); + // (?=(.*expr1.*))(?=().*expr2.*))... + // The ?=(...) lookahead allows us to match these in any order. + return new RegExp(regex, 'igy'); +}