Skip to content

Commit

Permalink
AdHocFilters: Fix matching non-latin template vars in filter (#1018)
Browse files Browse the repository at this point in the history
  • Loading branch information
leeoniya authored Dec 31, 2024
1 parent 60b8409 commit bd2ba60
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
import {
ERROR_STATE_DROPDOWN_WIDTH,
flattenOptionGroups,
fuzzySearchOptions,
searchOptions,
generateFilterUpdatePayload,
generatePlaceholder,
populateInputValueOnInputTypeSwitch,
Expand Down Expand Up @@ -81,7 +81,7 @@ export const AdHocCombobox = forwardRef(function AdHocCombobox(
const disabledIndicesRef = useRef<number[]>([]);
const filterInputTypeRef = useRef<AdHocInputType>(!isAlwaysWip ? 'value' : 'key');

const optionsSearcher = useMemo(() => fuzzySearchOptions(options), [options]);
const optionsSearcher = useMemo(() => searchOptions(options), [options]);

const isLastFilter = useMemo(() => {
if (isAlwaysWip) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@ export const VIRTUAL_LIST_ITEM_HEIGHT = 38;
export const VIRTUAL_LIST_ITEM_HEIGHT_WITH_DESCRIPTION = 60;
export const ERROR_STATE_DROPDOWN_WIDTH = 366;

export function fuzzySearchOptions(options: Array<SelectableValue<string>>) {
// https://catonmat.net/my-favorite-regex :)
const REGEXP_NON_ASCII = /[^ -~]/m;

export function searchOptions(options: Array<SelectableValue<string>>) {
const haystack = options.map((o) => o.label ?? o.value!);
const fuzzySearch = getFuzzySearcher(haystack);

return (search: string, filterInputType: AdHocInputType) => {
// fall back to substring matching for non-latin chars
if (REGEXP_NON_ASCII.test(search)) {
return options.filter((o) => o.label?.includes(search) || o.value?.includes(search) || false);
}

if (filterInputType === 'operator' && search !== '') {
// uFuzzy can only match non-alphanum chars if quoted
search = `"${search}"`;
Expand Down
20 changes: 20 additions & 0 deletions packages/scenes/src/variables/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { getFuzzySearcher, getQueriesForVariables } from './utils';
import { SceneVariableSet } from './sets/SceneVariableSet';
import { DataSourceVariable } from './variants/DataSourceVariable';
import { GetDataSourceListFilters } from '@grafana/runtime';
import { searchOptions } from './adhoc/AdHocFiltersCombobox/utils';
import { SelectableValue } from '@grafana/data';

describe('getQueriesForVariables', () => {
it('should resolve queries', () => {
Expand Down Expand Up @@ -289,6 +291,24 @@ describe('getFuzzySearcher orders by match quality with case-sensitivity', () =>
});
});

describe('searchOptions falls back to substring matching for non-latin needles', () => {
it('Can filter options by search query', async () => {
const options: SelectableValue[] = [
'台灣省',
'台中市',
'台北市',
'台南市',
'南投縣',
'高雄市',
'台中第一高級中學',
].map((v) => ({ label: v, value: v }));

const searcher = searchOptions(options);

expect(searcher('南', 'key').map((o) => o.label!)).toEqual(['台南市', '南投縣']);
});
});

interface TestObjectState extends SceneObjectState {
datasource: DataSourceRef | null;
}
Expand Down

0 comments on commit bd2ba60

Please sign in to comment.