From 1296582f4b28c6fdd3b1e274ba5d5962145f817e Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Fri, 2 Sep 2022 14:07:40 +0200 Subject: [PATCH] Plugins Catalog: Allow to filter plugins using special characters (#54474) (#54589) (cherry picked from commit f6827a0518ef979b588f385ba9a9ac794b0c6d97) Co-authored-by: Murtaza Ahmedi <29052897+murtazaqa@users.noreply.github.com> --- .../features/plugins/admin/pages/Browse.test.tsx | 14 +++++++++++++- public/app/features/plugins/admin/state/hooks.ts | 2 +- .../app/features/plugins/admin/state/selectors.ts | 4 ++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/public/app/features/plugins/admin/pages/Browse.test.tsx b/public/app/features/plugins/admin/pages/Browse.test.tsx index 56096458df0..632d8bcfb18 100644 --- a/public/app/features/plugins/admin/pages/Browse.test.tsx +++ b/public/app/features/plugins/admin/pages/Browse.test.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { Provider } from 'react-redux'; import { Router } from 'react-router-dom'; -import { PluginType } from '@grafana/data'; +import { PluginType, escapeStringForRegex } from '@grafana/data'; import { locationService } from '@grafana/runtime'; import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps'; import { configureStore } from 'app/store/configureStore'; @@ -197,6 +197,18 @@ describe('Browse list of plugins', () => { expect(queryByText('Plugin 2')).not.toBeInTheDocument(); expect(queryByText('Plugin 3')).not.toBeInTheDocument(); }); + + it('should handle escaped regex characters in the search query (e.g. "(" )', async () => { + const { queryByText } = renderBrowse('/plugins?filterBy=all&q=' + escapeStringForRegex('graph (old)'), [ + getCatalogPluginMock({ id: 'graph', name: 'Graph (old)' }), + getCatalogPluginMock({ id: 'plugin-2', name: 'Plugin 2' }), + getCatalogPluginMock({ id: 'plugin-3', name: 'Plugin 3' }), + ]); + await waitFor(() => expect(queryByText('Graph (old)')).toBeInTheDocument()); + // Other plugin types shouldn't be shown + expect(queryByText('Plugin 2')).not.toBeInTheDocument(); + expect(queryByText('Plugin 3')).not.toBeInTheDocument(); + }); }); describe('when sorting', () => { diff --git a/public/app/features/plugins/admin/state/hooks.ts b/public/app/features/plugins/admin/state/hooks.ts index 9a4862f3d19..a8790eea9b4 100644 --- a/public/app/features/plugins/admin/state/hooks.ts +++ b/public/app/features/plugins/admin/state/hooks.ts @@ -20,7 +20,7 @@ import { } from './selectors'; type Filters = { - query?: string; + query?: string; // Note: this will be an escaped regex string as it comes from `FilterInput` filterBy?: string; filterByType?: string; sortBy?: Sorters; diff --git a/public/app/features/plugins/admin/state/selectors.ts b/public/app/features/plugins/admin/state/selectors.ts index b8bced29eae..1b84ff6cd60 100644 --- a/public/app/features/plugins/admin/state/selectors.ts +++ b/public/app/features/plugins/admin/state/selectors.ts @@ -1,6 +1,6 @@ import { createSelector } from '@reduxjs/toolkit'; -import { PluginError, PluginErrorCode } from '@grafana/data'; +import { PluginError, PluginErrorCode, unEscapeStringFromRegex } from '@grafana/data'; import { RequestStatus, PluginCatalogStoreState } from '../types'; @@ -40,7 +40,7 @@ const findByKeyword = (searchBy: string) => fields.push(plugin.orgName.toLowerCase()); } - return fields.some((f) => f.includes(searchBy.toLowerCase())); + return fields.some((f) => f.includes(unEscapeStringFromRegex(searchBy).toLowerCase())); }); });