From 6b266ebc502f0b628f69f823c3e813516739effd Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Wed, 16 Jul 2025 22:39:39 +0200 Subject: [PATCH] Chore: Remove unused files in @grafana/prometheus (#108135) * remove unused files * lint * resolve circular dependencies * a bit more circular dependency cleaning * move unit tests --- .../components/VariableQueryEditor.test.tsx | 27 ++--- .../src/language_provider.test.ts | 57 ----------- .../src/language_provider.ts | 13 +-- .../src/language_utils.test.ts | 57 +++++++++++ .../grafana-prometheus/src/language_utils.ts | 12 +++ .../src/locales/en-US/grafana-prometheus.json | 3 - packages/grafana-prometheus/src/promql.ts | 16 --- .../src/querybuilder/PromQueryModeller.ts | 4 +- .../components/LabelFilters.test.tsx | 6 +- .../components/MetricCombobox.tsx | 26 +---- .../OperationParamEditorWrapper.tsx | 52 ---------- .../PromQueryBuilderOptions.test.tsx | 8 +- .../metrics-modal/MetricsModal.test.tsx | 3 +- .../components/metrics-modal/MetricsModal.tsx | 16 +-- .../metrics-modal/shared/actions.ts | 3 - .../components/metrics-modal/shared/state.ts | 17 ---- .../components/shared/BaseQueryBuilder.tsx | 2 +- .../shared/BaseQueryBuilderProps.ts | 13 --- .../components/shared/QueryBuilderContent.tsx | 2 +- .../components/shared/formatter.ts | 26 +++++ .../querybuilder/components/shared/types.ts | 14 +-- .../src/querybuilder/operationDefinitions.ts | 98 ------------------- ...dellerBase.ts => PromQueryModellerBase.ts} | 31 +++--- .../querybuilder/shared/QueryEditorHints.tsx | 70 ------------- .../shared/query_builder_utils.ts | 16 --- .../shared/rendering/operations.ts | 5 +- .../querybuilder/shared/rendering/query.ts | 11 +-- .../src/querybuilder/shared/types.ts | 14 +++ .../querybuilder/shared/types/visual_query.ts | 13 --- .../src/querybuilder/types.ts | 8 +- .../src/resource_clients.ts | 3 +- .../src/test/helpers/selectOptionInTest.ts | 9 -- 32 files changed, 169 insertions(+), 486 deletions(-) delete mode 100644 packages/grafana-prometheus/src/querybuilder/components/OperationParamEditorWrapper.tsx delete mode 100644 packages/grafana-prometheus/src/querybuilder/components/metrics-modal/shared/actions.ts delete mode 100644 packages/grafana-prometheus/src/querybuilder/components/metrics-modal/shared/state.ts delete mode 100644 packages/grafana-prometheus/src/querybuilder/components/shared/BaseQueryBuilderProps.ts create mode 100644 packages/grafana-prometheus/src/querybuilder/components/shared/formatter.ts delete mode 100644 packages/grafana-prometheus/src/querybuilder/operationDefinitions.ts rename packages/grafana-prometheus/src/querybuilder/shared/{LokiAndPromQueryModellerBase.ts => PromQueryModellerBase.ts} (75%) delete mode 100644 packages/grafana-prometheus/src/querybuilder/shared/QueryEditorHints.tsx delete mode 100644 packages/grafana-prometheus/src/querybuilder/shared/query_builder_utils.ts delete mode 100644 packages/grafana-prometheus/src/querybuilder/shared/types/visual_query.ts delete mode 100644 packages/grafana-prometheus/src/test/helpers/selectOptionInTest.ts diff --git a/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx b/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx index 116a06a5d87..4e4c63352f3 100644 --- a/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx +++ b/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx @@ -1,6 +1,7 @@ // Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.test.tsx import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { select } from 'react-select-event'; import { dateTime, TimeRange } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; @@ -8,7 +9,6 @@ import { selectors } from '@grafana/e2e-selectors'; import { PrometheusDatasource } from '../datasource'; import { PrometheusLanguageProviderInterface } from '../language_provider'; import { migrateVariableEditorBackToVariableSupport } from '../migrations/variableMigration'; -import { selectOptionInTest } from '../test/helpers/selectOptionInTest'; import { PromVariableQuery, PromVariableQueryType, StandardPromVariableQuery } from '../types'; import { PromVariableQueryEditor, Props, variableMigration } from './VariableQueryEditor'; @@ -186,7 +186,7 @@ describe('PromVariableQueryEditor', () => { render(); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Label names'); + await waitFor(() => select(screen.getByLabelText('Query type'), 'Label names', { container: document.body })); expect(onChange).toHaveBeenCalledWith({ query: 'label_names(that)', @@ -205,11 +205,11 @@ describe('PromVariableQueryEditor', () => { render(); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Label names'); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Label values'); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Metrics'); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Query result'); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Classic query'); + await waitFor(() => select(screen.getByLabelText('Query type'), 'Label names', { container: document.body })); + await waitFor(() => select(screen.getByLabelText('Query type'), 'Label values', { container: document.body })); + await waitFor(() => select(screen.getByLabelText('Query type'), 'Metrics', { container: document.body })); + await waitFor(() => select(screen.getByLabelText('Query type'), 'Query result', { container: document.body })); + await waitFor(() => select(screen.getByLabelText('Query type'), 'Classic query', { container: document.body })); expect(onChange).toHaveBeenCalledTimes(5); }); @@ -219,7 +219,7 @@ describe('PromVariableQueryEditor', () => { render(); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Series query'); + await waitFor(() => select(screen.getByLabelText('Query type'), 'Series query', { container: document.body })); expect(onChange).not.toHaveBeenCalled(); }); @@ -234,7 +234,7 @@ describe('PromVariableQueryEditor', () => { render(); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Metrics'); + await waitFor(() => select(screen.getByLabelText('Query type'), 'Metrics', { container: document.body })); const metricInput = screen.getByLabelText('Metric selector'); await userEvent.type(metricInput, 'a'); const queryType = screen.getByLabelText('Query type'); @@ -261,12 +261,13 @@ describe('PromVariableQueryEditor', () => { render(); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Label values'); + await waitFor(() => select(screen.getByLabelText('Query type'), 'Label values', { container: document.body })); const labelSelect = screen.getByTestId( selectors.components.DataSource.Prometheus.variableQueryEditor.labelValues.labelSelect ); await userEvent.type(labelSelect, 'this'); - await selectOptionInTest(labelSelect, 'this'); + + await waitFor(() => select(labelSelect, 'this', { container: document.body })); //display label in label select await waitFor(() => expect(screen.getByText('this')).toBeInTheDocument()); @@ -289,12 +290,12 @@ describe('PromVariableQueryEditor', () => { render(); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Label values'); + await waitFor(() => select(screen.getByLabelText('Query type'), 'Label values', { container: document.body })); const labelSelect = screen.getByTestId( selectors.components.DataSource.Prometheus.variableQueryEditor.labelValues.labelSelect ); await userEvent.type(labelSelect, 'this'); - await selectOptionInTest(labelSelect, 'this'); + await waitFor(() => select(labelSelect, 'this', { container: document.body })); const combobox = screen.getByPlaceholderText('Select metric'); await userEvent.type(combobox, 'that'); diff --git a/packages/grafana-prometheus/src/language_provider.test.ts b/packages/grafana-prometheus/src/language_provider.test.ts index 874c07bc151..a3c32d7f881 100644 --- a/packages/grafana-prometheus/src/language_provider.test.ts +++ b/packages/grafana-prometheus/src/language_provider.test.ts @@ -14,7 +14,6 @@ import { PrometheusDatasource } from './datasource'; import { exportToAbstractQuery, importFromAbstractQuery, - removeQuotesIfExist, PrometheusLanguageProviderInterface, PrometheusLanguageProvider, populateMatchParamsFromQueries, @@ -659,62 +658,6 @@ describe('Query transformation', () => { }); }); -describe('removeQuotesIfExist', () => { - it('removes quotes from a string with double quotes', () => { - const input = '"hello"'; - const result = removeQuotesIfExist(input); - expect(result).toBe('hello'); - }); - - it('returns the original string if it does not start and end with quotes', () => { - const input = 'hello'; - const result = removeQuotesIfExist(input); - expect(result).toBe('hello'); - }); - - it('returns the original string if it has mismatched quotes', () => { - const input = '"hello'; - const result = removeQuotesIfExist(input); - expect(result).toBe('"hello'); - }); - - it('removes quotes for strings with special characters inside quotes', () => { - const input = '"hello, world!"'; - const result = removeQuotesIfExist(input); - expect(result).toBe('hello, world!'); - }); - - it('removes quotes for strings with spaces inside quotes', () => { - const input = '" "'; - const result = removeQuotesIfExist(input); - expect(result).toBe(' '); - }); - - it('returns the original string for an empty string', () => { - const input = ''; - const result = removeQuotesIfExist(input); - expect(result).toBe(''); - }); - - it('returns the original string if the string only has a single quote character', () => { - const input = '"'; - const result = removeQuotesIfExist(input); - expect(result).toBe('"'); - }); - - it('handles strings with nested quotes correctly', () => { - const input = '"nested \"quotes\""'; - const result = removeQuotesIfExist(input); - expect(result).toBe('nested \"quotes\"'); - }); - - it('removes quotes from a numeric string wrapped in quotes', () => { - const input = '"12345"'; - const result = removeQuotesIfExist(input); - expect(result).toBe('12345'); - }); -}); - describe('PrometheusLanguageProvider with feature toggle', () => { const defaultDatasource: PrometheusDatasource = { metadataRequest: () => ({ data: { data: [] } }), diff --git a/packages/grafana-prometheus/src/language_provider.ts b/packages/grafana-prometheus/src/language_provider.ts index 9a64613cf3f..3ff374771d7 100644 --- a/packages/grafana-prometheus/src/language_provider.ts +++ b/packages/grafana-prometheus/src/language_provider.ts @@ -25,6 +25,7 @@ import { fixSummariesMetadata, processHistogramMetrics, processLabels, + removeQuotesIfExist, toPromLikeQuery, } from './language_utils'; import { promqlGrammar } from './promql'; @@ -766,18 +767,6 @@ function isCancelledError(error: unknown): error is { return typeof error === 'object' && error !== null && 'cancelled' in error && error.cancelled === true; } -/** - * Removes quotes from a string if they exist. - * Used to handle utf8 label keys in Prometheus queries. - * - * @param {string} input - Input string that may have surrounding quotes - * @returns {string} String with surrounding quotes removed if they existed - */ -export function removeQuotesIfExist(input: string): string { - const match = input.match(/^"(.*)"$/); // extract the content inside the quotes - return match?.[1] ?? input; -} - function getNameLabelValue(promQuery: string, tokens: Array): string { let nameLabelValue = ''; diff --git a/packages/grafana-prometheus/src/language_utils.test.ts b/packages/grafana-prometheus/src/language_utils.test.ts index e30360b1b69..5ba14363da7 100644 --- a/packages/grafana-prometheus/src/language_utils.test.ts +++ b/packages/grafana-prometheus/src/language_utils.test.ts @@ -10,6 +10,7 @@ import { getPrometheusTime, getRangeSnapInterval, processLabels, + removeQuotesIfExist, toPromLikeQuery, truncateResult, } from './language_utils'; @@ -544,3 +545,59 @@ describe('processLabels', () => { }); }); }); + +describe('removeQuotesIfExist', () => { + it('removes quotes from a string with double quotes', () => { + const input = '"hello"'; + const result = removeQuotesIfExist(input); + expect(result).toBe('hello'); + }); + + it('returns the original string if it does not start and end with quotes', () => { + const input = 'hello'; + const result = removeQuotesIfExist(input); + expect(result).toBe('hello'); + }); + + it('returns the original string if it has mismatched quotes', () => { + const input = '"hello'; + const result = removeQuotesIfExist(input); + expect(result).toBe('"hello'); + }); + + it('removes quotes for strings with special characters inside quotes', () => { + const input = '"hello, world!"'; + const result = removeQuotesIfExist(input); + expect(result).toBe('hello, world!'); + }); + + it('removes quotes for strings with spaces inside quotes', () => { + const input = '" "'; + const result = removeQuotesIfExist(input); + expect(result).toBe(' '); + }); + + it('returns the original string for an empty string', () => { + const input = ''; + const result = removeQuotesIfExist(input); + expect(result).toBe(''); + }); + + it('returns the original string if the string only has a single quote character', () => { + const input = '"'; + const result = removeQuotesIfExist(input); + expect(result).toBe('"'); + }); + + it('handles strings with nested quotes correctly', () => { + const input = '"nested \"quotes\""'; + const result = removeQuotesIfExist(input); + expect(result).toBe('nested \"quotes\"'); + }); + + it('removes quotes from a numeric string wrapped in quotes', () => { + const input = '"12345"'; + const result = removeQuotesIfExist(input); + expect(result).toBe('12345'); + }); +}); diff --git a/packages/grafana-prometheus/src/language_utils.ts b/packages/grafana-prometheus/src/language_utils.ts index 62d7fb2dfa3..ee8090c9d44 100644 --- a/packages/grafana-prometheus/src/language_utils.ts +++ b/packages/grafana-prometheus/src/language_utils.ts @@ -437,3 +437,15 @@ export function truncateResult(array: T[], limit?: number): T[] { array.length = Math.min(array.length, limit); return array; } + +/** + * Removes quotes from a string if they exist. + * Used to handle utf8 label keys in Prometheus queries. + * + * @param {string} input - Input string that may have surrounding quotes + * @returns {string} String with surrounding quotes removed if they existed + */ +export function removeQuotesIfExist(input: string): string { + const match = input.match(/^"(.*)"$/); // extract the content inside the quotes + return match?.[1] ?? input; +} diff --git a/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json index 7885c3d457c..26fecb50168 100644 --- a/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json @@ -356,9 +356,6 @@ "query-builder-hints": { "hint-details": "hint: {{hintDetails}}" }, - "query-editor-hints": { - "hint-details": "hint: {{hintDetails}}" - }, "query-editor-mode-toggle": { "editor-modes": { "label-builder": "Builder", diff --git a/packages/grafana-prometheus/src/promql.ts b/packages/grafana-prometheus/src/promql.ts index 9fd1e4add62..9235777c6a5 100644 --- a/packages/grafana-prometheus/src/promql.ts +++ b/packages/grafana-prometheus/src/promql.ts @@ -3,20 +3,6 @@ import { Grammar } from 'prismjs'; import { CompletionItem } from '@grafana/ui'; -// When changing RATE_RANGES, check if Loki/LogQL ranges should be changed too -// @see public/app/plugins/datasource/loki/LanguageProvider.ts -export const RATE_RANGES: CompletionItem[] = [ - { label: '$__interval', sortValue: '$__interval' }, - { label: '$__rate_interval', sortValue: '$__rate_interval' }, - { label: '$__range', sortValue: '$__range' }, - { label: '1m', sortValue: '00:01:00' }, - { label: '5m', sortValue: '00:05:00' }, - { label: '10m', sortValue: '00:10:00' }, - { label: '30m', sortValue: '00:30:00' }, - { label: '1h', sortValue: '01:00:00' }, - { label: '1d', sortValue: '24:00:00' }, -]; - export const OPERATORS = ['by', 'group_left', 'group_right', 'ignoring', 'on', 'offset', 'without']; export const LOGICAL_OPERATORS = ['or', 'and', 'unless']; @@ -589,8 +575,6 @@ export const FUNCTIONS = [ }, ]; -export const PROM_KEYWORDS = FUNCTIONS.map((keyword) => keyword.label); - export const promqlGrammar: Grammar = { comment: { pattern: /#.*/, diff --git a/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.ts b/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.ts index 0b380d2644f..caf90017526 100644 --- a/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.ts +++ b/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.ts @@ -3,7 +3,7 @@ import { FUNCTIONS } from '../promql'; import { getAggregationOperations } from './aggregations'; import { getOperationDefinitions } from './operations'; -import { LokiAndPromQueryModellerBase } from './shared/LokiAndPromQueryModellerBase'; +import { PromQueryModellerBase } from './shared/PromQueryModellerBase'; import { PromQueryPattern, PromQueryPatternType, @@ -11,7 +11,7 @@ import { PromQueryModellerInterface, } from './types'; -export class PromQueryModeller extends LokiAndPromQueryModellerBase implements PromQueryModellerInterface { +export class PromQueryModeller extends PromQueryModellerBase implements PromQueryModellerInterface { constructor() { super(() => { const allOperations = [...getOperationDefinitions(), ...getAggregationOperations()]; diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx index 8205eede517..29d31ccea35 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx @@ -2,10 +2,10 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { ComponentProps } from 'react'; +import { select } from 'react-select-event'; import { selectors } from '@grafana/e2e-selectors'; -import { selectOptionInTest } from '../../test/helpers/selectOptionInTest'; import { getLabelSelects } from '../testUtils'; import { LabelFilters, MISSING_LABEL_FILTER_ERROR_MESSAGE, LabelFiltersProps } from './LabelFilters'; @@ -71,8 +71,8 @@ describe('LabelFilters', () => { expect(screen.getAllByText('Select label')).toHaveLength(1); expect(screen.getAllByText('Select value')).toHaveLength(1); const { name, value } = getLabelSelects(1); - await selectOptionInTest(name, 'baz'); - await selectOptionInTest(value, 'qux'); + await waitFor(() => select(name, 'baz', { container: document.body })); + await waitFor(() => select(value, 'qux', { container: document.body })); expect(onChange).toHaveBeenCalledWith([ { label: 'foo', op: '=', value: 'bar' }, { label: 'baz', op: '=', value: 'qux' }, diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.tsx index c1547976a4c..21a88427159 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/MetricCombobox.tsx @@ -8,12 +8,12 @@ import { Button, InlineField, InlineFieldRow, Combobox, ComboboxOption } from '@ import { METRIC_LABEL } from '../../constants'; import { PrometheusDatasource } from '../../datasource'; -import { regexifyLabelValuesQueryString } from '../parsingUtils'; import { QueryBuilderLabelFilter } from '../shared/types'; import { PromVisualQuery } from '../types'; import { MetricsModal } from './metrics-modal/MetricsModal'; import { tracking } from './metrics-modal/state/helpers'; +import { formatKeyValueStrings } from './shared/formatter'; export interface MetricComboboxProps { metricLookupDisabled: boolean; @@ -163,27 +163,3 @@ export function MetricCombobox({ ); } - -export const formatPrometheusLabelFiltersToString = ( - queryString: string, - labelsFilters: QueryBuilderLabelFilter[] | undefined -): string => { - const filterArray = labelsFilters ? formatPrometheusLabelFilters(labelsFilters) : []; - - return `{__name__=~".*${queryString}"${filterArray ? filterArray.join('') : ''}}`; -}; - -export const formatPrometheusLabelFilters = (labelsFilters: QueryBuilderLabelFilter[]): string[] => { - return labelsFilters.map((label) => { - return `,${label.label}="${label.value}"`; - }); -}; - -/** - * Reformat the query string and label filters to return all valid results for current query editor state - */ -const formatKeyValueStrings = (query: string, labelsFilters?: QueryBuilderLabelFilter[]): string => { - const queryString = regexifyLabelValuesQueryString(query); - - return formatPrometheusLabelFiltersToString(queryString, labelsFilters); -}; diff --git a/packages/grafana-prometheus/src/querybuilder/components/OperationParamEditorWrapper.tsx b/packages/grafana-prometheus/src/querybuilder/components/OperationParamEditorWrapper.tsx deleted file mode 100644 index c19860dcc8b..00000000000 --- a/packages/grafana-prometheus/src/querybuilder/components/OperationParamEditorWrapper.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { ComponentType } from 'react'; - -import { promQueryModeller } from '../shared/modeller_instance'; -import { QueryBuilderOperationParamEditorProps } from '../shared/types'; -import { PromQueryModellerInterface } from '../types'; - -import { LabelParamEditor } from './LabelParamEditor'; - -/** - * Maps string keys to editor components with the modeller instance injected. - * - * This wrapper is a key part of avoiding circular dependencies: - * - Operation definitions reference editors by string key (no import) - * - The registry maps these keys to editor components - * - This wrapper injects the modeller instance into those components - * - * This creates a clear one-way dependency flow: - * Operation Definitions -> Registry -> Editor Components <- Wrapper <- Modeller Instance - * - * Without this wrapper, we would have a circular dependency: - * Operation Definitions -> Editors -> Modeller -> Operation Definitions - */ -const editorMap: Record< - string, - ComponentType -> = { - LabelParamEditor: (props) => , -}; - -/** - * Wrapper component that resolves and renders the appropriate editor component. - * - * This component: - * 1. Takes a parameter definition that may specify an editor by string key or direct reference - * 2. Resolves the editor component from the map if a string key is used - * 3. Renders the editor with all necessary props, including the modeller instance - * - * This separation of concerns allows operation definitions to be simpler while ensuring - * editors have access to all the dependencies they need, without creating circular dependencies. - */ -export function OperationParamEditorWrapper(props: QueryBuilderOperationParamEditorProps) { - const { paramDef } = props; - const EditorComponent = typeof paramDef.editor === 'string' ? editorMap[paramDef.editor] : paramDef.editor; - - if (!EditorComponent) { - return null; - } - - // Type assertion is safe here because we know the editorMap only contains components - // that require the modeller instance - return ; -} diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx index 61d6c4dfda2..abd7f21ee3d 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx @@ -1,10 +1,10 @@ // Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.test.tsx -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { select } from 'react-select-event'; import { CoreApp } from '@grafana/data'; -import { selectOptionInTest } from '../../test/helpers/selectOptionInTest'; import { PromQuery } from '../../types'; import { getQueryWithDefaults } from '../state'; @@ -56,7 +56,7 @@ describe('PromQueryBuilderOptions', () => { let legendModeSelect = screen.getByText('Auto').parentElement!; await userEvent.click(legendModeSelect); - await selectOptionInTest(legendModeSelect, 'Verbose'); + await waitFor(() => select(legendModeSelect, 'Verbose', { container: document.body })); expect(props.onChange).toHaveBeenCalledWith({ ...props.query, @@ -72,7 +72,7 @@ describe('PromQueryBuilderOptions', () => { let legendModeSelect = screen.getByText('Auto').parentElement!; await userEvent.click(legendModeSelect); - await selectOptionInTest(legendModeSelect, 'Custom'); + await waitFor(() => select(legendModeSelect, 'Custom', { container: document.body })); expect(props.onChange).toHaveBeenCalledWith({ ...props.query, diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx index ae35490c097..c85089657cb 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx @@ -11,7 +11,8 @@ import { getMockTimeRange } from '../../../test/mocks/datasource'; import { PromOptions } from '../../../types'; import { PromVisualQuery } from '../../types'; -import { MetricsModal, metricsModaltestIds } from './MetricsModal'; +import { MetricsModal } from './MetricsModal'; +import { metricsModaltestIds } from './shared/testIds'; // don't care about interaction tracking in our unit tests jest.mock('@grafana/runtime', () => ({ diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx index f38935ea4ea..0722489b771 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx @@ -22,11 +22,12 @@ import { import { getDebounceTimeInMilliseconds } from '../../../caching'; import { METRIC_LABEL } from '../../../constants'; import { regexifyLabelValuesQueryString } from '../../parsingUtils'; -import { formatPrometheusLabelFilters } from '../MetricCombobox'; +import { formatPrometheusLabelFilters } from '../shared/formatter'; import { AdditionalSettings } from './AdditionalSettings'; import { FeedbackLink } from './FeedbackLink'; import { ResultsTable } from './ResultsTable'; +import { metricsModaltestIds } from './shared/testIds'; import { MetricsModalProps } from './shared/types'; import { calculatePageList, @@ -355,16 +356,3 @@ export const MetricsModal = (props: MetricsModalProps) => { ); }; - -export const metricsModaltestIds = { - metricModal: 'metric-modal', - searchMetric: 'search-metric', - searchWithMetadata: 'search-with-metadata', - selectType: 'select-type', - metricCard: 'metric-card', - useMetric: 'use-metric', - searchPage: 'search-page', - resultsPerPage: 'results-per-page', - setUseBackend: 'set-use-backend', - showAdditionalSettings: 'show-additional-settings', -}; diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/shared/actions.ts b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/shared/actions.ts deleted file mode 100644 index 03154032586..00000000000 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/shared/actions.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { createAction } from '@reduxjs/toolkit'; - -export const setFilteredMetricCount = createAction('metrics-modal/setFilteredMetricCount'); diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/shared/state.ts b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/shared/state.ts deleted file mode 100644 index 5a0b11cf365..00000000000 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/shared/state.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { SelectableValue } from '@grafana/data'; - -import { MetricsData } from '../types'; - -export interface MetricsModalStateModel { - isLoading: boolean; - metrics: MetricsData; - hasMetadata: boolean; - selectedTypes: Array>; -} - -export const initialState = (query: unknown): MetricsModalStateModel => ({ - isLoading: true, - metrics: [], - hasMetadata: false, - selectedTypes: [], -}); diff --git a/packages/grafana-prometheus/src/querybuilder/components/shared/BaseQueryBuilder.tsx b/packages/grafana-prometheus/src/querybuilder/components/shared/BaseQueryBuilder.tsx index 551b9c063db..03787aad88a 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/shared/BaseQueryBuilder.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/shared/BaseQueryBuilder.tsx @@ -2,8 +2,8 @@ import { memo } from 'react'; import { NestedQueryList } from '../NestedQueryList'; -import { BaseQueryBuilderProps } from './BaseQueryBuilderProps'; import { QueryBuilderContent } from './QueryBuilderContent'; +import { BaseQueryBuilderProps } from './types'; export const BaseQueryBuilder = memo((props) => { const { query, datasource, onChange, onRunQuery, showExplain } = props; diff --git a/packages/grafana-prometheus/src/querybuilder/components/shared/BaseQueryBuilderProps.ts b/packages/grafana-prometheus/src/querybuilder/components/shared/BaseQueryBuilderProps.ts deleted file mode 100644 index 626e6606259..00000000000 --- a/packages/grafana-prometheus/src/querybuilder/components/shared/BaseQueryBuilderProps.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { PanelData } from '@grafana/data'; - -import { PrometheusDatasource } from '../../../datasource'; -import { PromVisualQuery } from '../../types'; - -export interface BaseQueryBuilderProps { - query: PromVisualQuery; - datasource: PrometheusDatasource; - onChange: (update: PromVisualQuery) => void; - onRunQuery: () => void; - data?: PanelData; - showExplain: boolean; -} diff --git a/packages/grafana-prometheus/src/querybuilder/components/shared/QueryBuilderContent.tsx b/packages/grafana-prometheus/src/querybuilder/components/shared/QueryBuilderContent.tsx index 69b73a2484b..ce00f36cbb9 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/shared/QueryBuilderContent.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/shared/QueryBuilderContent.tsx @@ -20,7 +20,7 @@ import { PromVisualQuery } from '../../types'; import { MetricsLabelsSection } from '../MetricsLabelsSection'; import { EXPLAIN_LABEL_FILTER_CONTENT } from '../PromQueryBuilderExplained'; -import { BaseQueryBuilderProps } from './BaseQueryBuilderProps'; +import { BaseQueryBuilderProps } from './types'; export const QueryBuilderContent = memo((props) => { const { datasource, query, onChange, onRunQuery, data, showExplain } = props; diff --git a/packages/grafana-prometheus/src/querybuilder/components/shared/formatter.ts b/packages/grafana-prometheus/src/querybuilder/components/shared/formatter.ts new file mode 100644 index 00000000000..baf8228c573 --- /dev/null +++ b/packages/grafana-prometheus/src/querybuilder/components/shared/formatter.ts @@ -0,0 +1,26 @@ +import { regexifyLabelValuesQueryString } from '../../parsingUtils'; +import { QueryBuilderLabelFilter } from '../../shared/types'; + +export const formatPrometheusLabelFiltersToString = ( + queryString: string, + labelsFilters: QueryBuilderLabelFilter[] | undefined +): string => { + const filterArray = labelsFilters ? formatPrometheusLabelFilters(labelsFilters) : []; + + return `{__name__=~".*${queryString}"${filterArray ? filterArray.join('') : ''}}`; +}; + +export const formatPrometheusLabelFilters = (labelsFilters: QueryBuilderLabelFilter[]): string[] => { + return labelsFilters.map((label) => { + return `,${label.label}="${label.value}"`; + }); +}; + +/** + * Reformat the query string and label filters to return all valid results for current query editor state + */ +export const formatKeyValueStrings = (query: string, labelsFilters?: QueryBuilderLabelFilter[]): string => { + const queryString = regexifyLabelValuesQueryString(query); + + return formatPrometheusLabelFiltersToString(queryString, labelsFilters); +}; diff --git a/packages/grafana-prometheus/src/querybuilder/components/shared/types.ts b/packages/grafana-prometheus/src/querybuilder/components/shared/types.ts index cedf1dd4ed7..626e6606259 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/shared/types.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/shared/types.ts @@ -1,20 +1,12 @@ -import { DataSourceApi, PanelData } from '@grafana/data'; +import { PanelData } from '@grafana/data'; import { PrometheusDatasource } from '../../../datasource'; import { PromVisualQuery } from '../../types'; -export interface NestedQueryProps { - query: PromVisualQuery; - datasource: DataSourceApi; - onChange: (query: PromVisualQuery) => void; - onRunQuery: () => void; - showExplain: boolean; -} - -export interface QueryBuilderProps { +export interface BaseQueryBuilderProps { query: PromVisualQuery; datasource: PrometheusDatasource; - onChange: (query: PromVisualQuery) => void; + onChange: (update: PromVisualQuery) => void; onRunQuery: () => void; data?: PanelData; showExplain: boolean; diff --git a/packages/grafana-prometheus/src/querybuilder/operationDefinitions.ts b/packages/grafana-prometheus/src/querybuilder/operationDefinitions.ts deleted file mode 100644 index 2ce70a18637..00000000000 --- a/packages/grafana-prometheus/src/querybuilder/operationDefinitions.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { capitalize } from 'lodash'; - -import { SelectableValue } from '@grafana/data'; - -import { - functionRendererLeft, - getOnLabelAddedHandler, - getAggregationExplainer, - defaultAddOperationHandler, - getAggregationByRenderer, - getLastLabelRemovedHandler, -} from './operationUtils'; -import { QueryBuilderOperationDef, QueryBuilderOperationParamDef } from './shared/types'; -import { PromVisualQueryOperationCategory } from './types'; - -export function getRangeVectorParamDef(withRateInterval = false): QueryBuilderOperationParamDef { - const options: Array> = [ - { - label: '$__interval', - value: '$__interval', - }, - { label: '1m', value: '1m' }, - { label: '5m', value: '5m' }, - { label: '10m', value: '10m' }, - { label: '1h', value: '1h' }, - { label: '24h', value: '24h' }, - ]; - - if (withRateInterval) { - options.unshift({ - label: '$__rate_interval', - value: '$__rate_interval', - }); - } - - const param: QueryBuilderOperationParamDef = { - name: 'Range', - type: 'string', - options, - }; - - return param; -} - -export function createAggregationOperation( - name: string, - overrides: Partial = {} -): QueryBuilderOperationDef[] { - const operations: QueryBuilderOperationDef[] = [ - { - id: name, - name: getPromOperationDisplayName(name), - params: [ - { - name: 'By label', - type: 'string', - restParam: true, - optional: true, - }, - ], - defaultParams: [], - alternativesKey: 'plain aggregations', - category: PromVisualQueryOperationCategory.Aggregations, - renderer: functionRendererLeft, - paramChangedHandler: getOnLabelAddedHandler(`__${name}_by`), - explainHandler: getAggregationExplainer(name, ''), - addOperationHandler: defaultAddOperationHandler, - ...overrides, - }, - { - id: `__${name}_by`, - name: `${getPromOperationDisplayName(name)} by`, - params: [ - { - name: 'Label', - type: 'string', - restParam: true, - optional: true, - }, - ], - defaultParams: [''], - alternativesKey: 'aggregations by', - category: PromVisualQueryOperationCategory.Aggregations, - renderer: getAggregationByRenderer(name), - paramChangedHandler: getLastLabelRemovedHandler(name), - explainHandler: getAggregationExplainer(name, 'by'), - addOperationHandler: defaultAddOperationHandler, - hideFromList: true, - ...overrides, - }, - ]; - - return operations; -} - -function getPromOperationDisplayName(funcName: string) { - return capitalize(funcName.replace(/_/g, ' ')); -} diff --git a/packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts b/packages/grafana-prometheus/src/querybuilder/shared/PromQueryModellerBase.ts similarity index 75% rename from packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts rename to packages/grafana-prometheus/src/querybuilder/shared/PromQueryModellerBase.ts index 7f66476e4f8..634e82f6db8 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts +++ b/packages/grafana-prometheus/src/querybuilder/shared/PromQueryModellerBase.ts @@ -4,23 +4,16 @@ import { Registry } from '@grafana/data'; import { renderLabels } from './rendering/labels'; import { hasBinaryOp, renderOperations } from './rendering/operations'; import { renderQuery, renderBinaryQueries } from './rendering/query'; -import { QueryBuilderLabelFilter, QueryBuilderOperation, QueryBuilderOperationDef, VisualQueryModeller } from './types'; +import { + PrometheusVisualQuery, + QueryBuilderLabelFilter, + QueryBuilderOperation, + QueryBuilderOperationDef, + VisualQueryBinary, + VisualQueryModeller, +} from './types'; -export interface VisualQueryBinary { - operator: string; - vectorMatchesType?: 'on' | 'ignoring'; - vectorMatches?: string; - query: T; -} - -export interface PromLokiVisualQuery { - metric?: string; - labels: QueryBuilderLabelFilter[]; - operations: QueryBuilderOperation[]; - binaryQueries?: Array>; -} - -export abstract class LokiAndPromQueryModellerBase implements VisualQueryModeller { +export abstract class PromQueryModellerBase implements VisualQueryModeller { protected operationsRegistry: Registry; private categories: string[] = []; private operationsMapCache: Map | null = null; @@ -63,7 +56,7 @@ export abstract class LokiAndPromQueryModellerBase implements VisualQueryModelle return renderOperations(queryString, operations, this.getOperationsMap()); } - renderBinaryQueries(queryString: string, binaryQueries?: Array>) { + renderBinaryQueries(queryString: string, binaryQueries?: Array>) { return renderBinaryQueries(queryString, binaryQueries); } @@ -71,11 +64,11 @@ export abstract class LokiAndPromQueryModellerBase implements VisualQueryModelle return renderLabels(labels); } - renderQuery(query: PromLokiVisualQuery, nested?: boolean) { + renderQuery(query: PrometheusVisualQuery, nested?: boolean) { return renderQuery(query, nested, this.getOperationsMap()); } - hasBinaryOp(query: PromLokiVisualQuery): boolean { + hasBinaryOp(query: PrometheusVisualQuery): boolean { return hasBinaryOp(query, this.getOperationsMap()); } } diff --git a/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorHints.tsx b/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorHints.tsx deleted file mode 100644 index f10e0f245a9..00000000000 --- a/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorHints.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { css } from '@emotion/css'; -import { useEffect, useState } from 'react'; - -import { GrafanaTheme2, QueryHint } from '@grafana/data'; -import { Trans } from '@grafana/i18n'; -import { reportInteraction } from '@grafana/runtime'; -import { Button, Tooltip, useStyles2 } from '@grafana/ui'; - -import { PromQueryEditorProps } from '../../components/types'; - -export function QueryEditorHints(props: PromQueryEditorProps) { - const [hints, setHints] = useState([]); - const { query, data, datasource } = props; - const styles = useStyles2(getStyles); - - useEffect(() => { - const promQuery = { expr: query.expr, refId: query.refId }; - const hints = datasource.getQueryHints(promQuery, data?.series || []).filter((hint) => hint.fix?.action); - setHints(hints); - }, [datasource, data, query]); - - return ( - <> - {hints.length > 0 && ( -
- {hints.map((hint) => { - return ( - // eslint-disable-next-line @grafana/i18n/no-untranslated-strings - - - - ); - })} -
- )} - - ); -} - -function onHintButtonClick(hint: QueryHint, props: PromQueryEditorProps) { - reportInteraction('grafana_query_builder_hints_clicked', { - hint: hint.type, - datasourceType: props.datasource.type, - }); - - if (hint.fix?.action) { - const newQuery = props.datasource.modifyQuery(props.query, hint.fix.action); - return props.onChange(newQuery); - } -} - -const getStyles = (theme: GrafanaTheme2) => { - return { - container: css({ - display: 'flex', - alignItems: 'start', - }), - hint: css({ - marginRight: theme.spacing(1), - padEnd: theme.spacing(2), - }), - }; -}; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/query_builder_utils.ts b/packages/grafana-prometheus/src/querybuilder/shared/query_builder_utils.ts deleted file mode 100644 index 04cfbd26669..00000000000 --- a/packages/grafana-prometheus/src/querybuilder/shared/query_builder_utils.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { QueryBuilderLabelFilter } from './types'; - -export function buildMetricQuery(metric: string, labels: QueryBuilderLabelFilter[]) { - let expr = metric; - if (labels.length > 0) { - expr = `${metric}{${labels.map(renderLabelFilter).join(',')}}`; - } - return expr; -} - -function renderLabelFilter(label: QueryBuilderLabelFilter): string { - if (label.value === '') { - return `${label.label}=""`; - } - return `${label.label}${label.op}"${label.value}"`; -} diff --git a/packages/grafana-prometheus/src/querybuilder/shared/rendering/operations.ts b/packages/grafana-prometheus/src/querybuilder/shared/rendering/operations.ts index 9c8f4650203..0c567adab2e 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/rendering/operations.ts +++ b/packages/grafana-prometheus/src/querybuilder/shared/rendering/operations.ts @@ -1,6 +1,5 @@ import { PromVisualQueryOperationCategory } from '../../types'; -import { PromLokiVisualQuery } from '../LokiAndPromQueryModellerBase'; -import { QueryBuilderOperation, QueryBuilderOperationDef } from '../types'; +import { PrometheusVisualQuery, QueryBuilderOperation, QueryBuilderOperationDef } from '../types'; /** * Renders operations @@ -25,7 +24,7 @@ export function renderOperations( * Checks if query has binary operation */ export function hasBinaryOp( - query: PromLokiVisualQuery, + query: PrometheusVisualQuery, operationsRegistry: Map ): boolean { return ( diff --git a/packages/grafana-prometheus/src/querybuilder/shared/rendering/query.ts b/packages/grafana-prometheus/src/querybuilder/shared/rendering/query.ts index 936ce22dc9a..8ca62efd886 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/rendering/query.ts +++ b/packages/grafana-prometheus/src/querybuilder/shared/rendering/query.ts @@ -1,6 +1,5 @@ import { isValidLegacyName } from '../../../utf8_support'; -import { PromLokiVisualQuery, VisualQueryBinary } from '../LokiAndPromQueryModellerBase'; -import { QueryBuilderOperationDef } from '../types'; +import { PrometheusVisualQuery, QueryBuilderOperationDef, VisualQueryBinary } from '../types'; import { renderLabels } from './labels'; import { hasBinaryOp, renderOperations } from './operations'; @@ -10,7 +9,7 @@ import { hasBinaryOp, renderOperations } from './operations'; */ export function renderBinaryQueries( queryString: string, - binaryQueries?: Array> + binaryQueries?: Array> ): string { if (binaryQueries) { for (const binQuery of binaryQueries) { @@ -23,7 +22,7 @@ export function renderBinaryQueries( /** * Renders a binary query */ -function renderBinaryQuery(leftOperand: string, binaryQuery: VisualQueryBinary): string { +function renderBinaryQuery(leftOperand: string, binaryQuery: VisualQueryBinary): string { let result = leftOperand + ` ${binaryQuery.operator} `; if (binaryQuery.vectorMatches) { @@ -37,7 +36,7 @@ function renderBinaryQuery(leftOperand: string, binaryQuery: VisualQueryBinary

): string { @@ -118,7 +117,7 @@ export function renderQuery( * This ensures we only add parentheses when needed */ function renderNestedPart( - query: PromLokiVisualQuery, + query: PrometheusVisualQuery, operationsRegistry?: Map ): string { // First render the query itself diff --git a/packages/grafana-prometheus/src/querybuilder/shared/types.ts b/packages/grafana-prometheus/src/querybuilder/shared/types.ts index a06b0823c80..fa2cfb81998 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/types.ts +++ b/packages/grafana-prometheus/src/querybuilder/shared/types.ts @@ -99,3 +99,17 @@ export interface VisualQueryModeller { getOperationDef(id: string): QueryBuilderOperationDef | undefined; } + +export interface VisualQueryBinary { + operator: string; + vectorMatchesType?: 'on' | 'ignoring'; + vectorMatches?: string; + query: T; +} + +export interface PrometheusVisualQuery { + metric?: string; + labels: QueryBuilderLabelFilter[]; + operations: QueryBuilderOperation[]; + binaryQueries?: Array>; +} diff --git a/packages/grafana-prometheus/src/querybuilder/shared/types/visual_query.ts b/packages/grafana-prometheus/src/querybuilder/shared/types/visual_query.ts deleted file mode 100644 index 12f0c1b6c2e..00000000000 --- a/packages/grafana-prometheus/src/querybuilder/shared/types/visual_query.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { QueryBuilderLabelFilter, QueryBuilderOperation } from '../types'; - -export interface PromLokiVisualQuery { - metric?: string; - labels: QueryBuilderLabelFilter[]; - operations: QueryBuilderOperation[]; -} - -export interface VisualQueryBinary { - operator: string; - vectorMatches?: string; - query: PromLokiVisualQuery; -} diff --git a/packages/grafana-prometheus/src/querybuilder/types.ts b/packages/grafana-prometheus/src/querybuilder/types.ts index 39042a9b975..991cfec8969 100644 --- a/packages/grafana-prometheus/src/querybuilder/types.ts +++ b/packages/grafana-prometheus/src/querybuilder/types.ts @@ -1,6 +1,10 @@ // Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/types.ts -import { VisualQueryBinary } from './shared/LokiAndPromQueryModellerBase'; -import { QueryBuilderLabelFilter, QueryBuilderOperation, QueryBuilderOperationDef } from './shared/types'; +import { + QueryBuilderLabelFilter, + QueryBuilderOperation, + QueryBuilderOperationDef, + VisualQueryBinary, +} from './shared/types'; /** * Visual query model diff --git a/packages/grafana-prometheus/src/resource_clients.ts b/packages/grafana-prometheus/src/resource_clients.ts index 04ab0559274..cc59213cf47 100644 --- a/packages/grafana-prometheus/src/resource_clients.ts +++ b/packages/grafana-prometheus/src/resource_clients.ts @@ -4,8 +4,7 @@ import { BackendSrvRequest } from '@grafana/runtime'; import { getDefaultCacheHeaders } from './caching'; import { DEFAULT_SERIES_LIMIT, EMPTY_SELECTOR, MATCH_ALL_LABELS, METRIC_LABEL } from './constants'; import { PrometheusDatasource } from './datasource'; -import { removeQuotesIfExist } from './language_provider'; -import { getRangeSnapInterval, processHistogramMetrics } from './language_utils'; +import { getRangeSnapInterval, processHistogramMetrics, removeQuotesIfExist } from './language_utils'; import { buildVisualQueryFromString } from './querybuilder/parsing'; import { PrometheusCacheLevel } from './types'; import { escapeForUtf8Support, utf8Support } from './utf8_support'; diff --git a/packages/grafana-prometheus/src/test/helpers/selectOptionInTest.ts b/packages/grafana-prometheus/src/test/helpers/selectOptionInTest.ts deleted file mode 100644 index e902abf315a..00000000000 --- a/packages/grafana-prometheus/src/test/helpers/selectOptionInTest.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/packages/grafana-ui/src/components/Select/SelectBase.tsx -import { waitFor } from '@testing-library/react'; -import { select } from 'react-select-event'; - -// Used to select an option or options from a Select in unit tests -export const selectOptionInTest = async ( - input: HTMLElement, - optionOrOptions: string | RegExp | Array -) => await waitFor(() => select(input, optionOrOptions, { container: document.body }));