From dd1fce5c8ad466109ad2faba77e6bfb06524c828 Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Tue, 8 Jul 2025 14:14:00 -0500 Subject: [PATCH] Search: Use case-insensitive substring matching in fuzzySearch fallback (#107661) --- packages/grafana-data/src/utils/fuzzySearch.test.ts | 8 ++++++++ packages/grafana-data/src/utils/fuzzySearch.ts | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/grafana-data/src/utils/fuzzySearch.test.ts b/packages/grafana-data/src/utils/fuzzySearch.test.ts index 71d75b27558..b53c26e98aa 100644 --- a/packages/grafana-data/src/utils/fuzzySearch.test.ts +++ b/packages/grafana-data/src/utils/fuzzySearch.test.ts @@ -48,6 +48,14 @@ describe('fuzzySearch', () => { expect(result.map((idx) => haystack[idx])).toEqual(['A水']); }); + it('should do case-insensitive substring match when needle contains non-ascii characters', () => { + const haystack = ['Über']; + const needle = 'ü'; + const result = fuzzySearch(haystack, needle); + + expect(result.map((idx) => haystack[idx])).toEqual(['Über']); + }); + it('should handle multiple non-latin characters', () => { const haystack = ['台灣省', '台中市', '台北市', '台南市', '南投縣', '高雄市', '台中第一高級中學']; const needle = '南'; diff --git a/packages/grafana-data/src/utils/fuzzySearch.ts b/packages/grafana-data/src/utils/fuzzySearch.ts index 72d1540f7b9..09ca02b7bc8 100644 --- a/packages/grafana-data/src/utils/fuzzySearch.ts +++ b/packages/grafana-data/src/utils/fuzzySearch.ts @@ -1,5 +1,7 @@ import uFuzzy from '@leeoniya/ufuzzy'; +import { escapeRegex } from '../text/string'; + // https://catonmat.net/my-favorite-regex :) const REGEXP_NON_ASCII = /[^ -~]/m; // https://www.asciitable.com/ @@ -36,11 +38,13 @@ export function fuzzySearch(haystack: string[], needle: string): number[] { needle.length > maxNeedleLength || uf.split(needle).length > maxFuzzyTerms ) { + const needleRegex = new RegExp(escapeRegex(needle), 'i'); const indices: number[] = []; + for (let i = 0; i < haystack.length; i++) { let item = haystack[i]; - if (item.includes(needle)) { + if (needleRegex.test(item)) { indices.push(i); } }