mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Prometheus: Remove prometheusMetricEncyclopedia feature toggle (#98414)
* remove toggle from registry * remove from metric combobox * remove toggle from metric select * remove toggle from promQueryBuilderContainer * prettier
This commit is contained in:
parent
d2639f6080
commit
d935fa1ea0
@ -32,7 +32,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
|
||||
| `nestedFolders` | Enable folder nesting | Yes |
|
||||
| `logsContextDatasourceUi` | Allow datasource to provide custom UI for context view | Yes |
|
||||
| `lokiQuerySplitting` | Split large interval queries into subqueries with smaller time intervals | Yes |
|
||||
| `prometheusMetricEncyclopedia` | Adds the metrics explorer component to the Prometheus query builder as an option in metric select | Yes |
|
||||
| `influxdbBackendMigration` | Query InfluxDB InfluxQL without the proxy | Yes |
|
||||
| `dataplaneFrontendFallback` | Support dataplane contract field name change for transformations and field name matchers where the name is different | Yes |
|
||||
| `unifiedRequestLog` | Writes error logs to the request logger | Yes |
|
||||
|
@ -53,7 +53,6 @@ export interface FeatureToggles {
|
||||
lokiQuerySplitting?: boolean;
|
||||
lokiQuerySplittingConfig?: boolean;
|
||||
individualCookiePreferences?: boolean;
|
||||
prometheusMetricEncyclopedia?: boolean;
|
||||
influxdbBackendMigration?: boolean;
|
||||
influxqlStreamingParser?: boolean;
|
||||
influxdbRunQueriesInParallel?: boolean;
|
||||
|
@ -4,7 +4,6 @@ import userEvent from '@testing-library/user-event';
|
||||
import '@testing-library/jest-dom';
|
||||
|
||||
import { DataSourceInstanceSettings, MetricFindValue } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { PrometheusDatasource } from '../../datasource';
|
||||
import { PromOptions } from '../../types';
|
||||
@ -125,29 +124,17 @@ describe('MetricCombobox', () => {
|
||||
expect(mockOnChange).toHaveBeenCalledWith({ metric: 'random_metric', labels: [], operations: [] });
|
||||
});
|
||||
|
||||
it("doesn't show the metrics explorer button by default", () => {
|
||||
it('shows the metrics explorer button by default', () => {
|
||||
render(<MetricCombobox {...defaultProps} />);
|
||||
expect(screen.queryByRole('button', { name: /open metrics explorer/i })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: /open metrics explorer/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe('when metrics explorer toggle is enabled', () => {
|
||||
beforeAll(() => {
|
||||
jest.replaceProperty(config, 'featureToggles', {
|
||||
prometheusMetricEncyclopedia: true,
|
||||
});
|
||||
});
|
||||
it('opens the metrics explorer when the button is clicked', async () => {
|
||||
render(<MetricCombobox {...defaultProps} onGetMetrics={() => Promise.resolve([])} />);
|
||||
|
||||
afterAll(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
const button = screen.getByRole('button', { name: /open metrics explorer/i });
|
||||
await userEvent.click(button);
|
||||
|
||||
it('opens the metrics explorer when the button is clicked', async () => {
|
||||
render(<MetricCombobox {...defaultProps} onGetMetrics={() => Promise.resolve([])} />);
|
||||
|
||||
const button = screen.getByRole('button', { name: /open metrics explorer/i });
|
||||
await userEvent.click(button);
|
||||
|
||||
expect(screen.getByText('Metrics explorer')).toBeInTheDocument();
|
||||
});
|
||||
expect(screen.getByText('Metrics explorer')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -3,7 +3,6 @@ import { useCallback, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||
import { EditorField, EditorFieldGroup, InputGroup } from '@grafana/experimental';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { Button, ComponentSize, InlineField, InlineFieldRow, useStyles2 } from '@grafana/ui';
|
||||
import { Combobox, ComboboxOption } from '@grafana/ui/src/components/Combobox/Combobox';
|
||||
import { getPropertiesForButtonSize } from '@grafana/ui/src/components/Forms/commonStyles';
|
||||
@ -89,8 +88,6 @@ export function MetricCombobox({
|
||||
return metrics;
|
||||
}, [onGetMetrics]);
|
||||
|
||||
const metricsExplorerEnabled = config.featureToggles.prometheusMetricEncyclopedia;
|
||||
|
||||
const styles = useStyles2(getMectricComboboxStyles);
|
||||
|
||||
const asyncSelect = () => {
|
||||
@ -105,29 +102,24 @@ export function MetricCombobox({
|
||||
onChange={onComboboxChange}
|
||||
createCustomValue
|
||||
/>
|
||||
|
||||
{metricsExplorerEnabled ? (
|
||||
<Button
|
||||
size={BUTTON_SIZE}
|
||||
tooltip="Open metrics explorer"
|
||||
aria-label="Open metrics explorer"
|
||||
variant="secondary"
|
||||
icon="book-open"
|
||||
onClick={() => {
|
||||
tracking('grafana_prometheus_metric_encyclopedia_open', null, '', query);
|
||||
setMetricsModalOpen(true);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<Button
|
||||
size={BUTTON_SIZE}
|
||||
tooltip="Open metrics explorer"
|
||||
aria-label="Open metrics explorer"
|
||||
variant="secondary"
|
||||
icon="book-open"
|
||||
onClick={() => {
|
||||
tracking('grafana_prometheus_metric_encyclopedia_open', null, '', query);
|
||||
setMetricsModalOpen(true);
|
||||
}}
|
||||
/>
|
||||
</InputGroup>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{metricsExplorerEnabled && !datasource.lookupsDisabled && metricsModalOpen && (
|
||||
{!datasource.lookupsDisabled && metricsModalOpen && (
|
||||
<MetricsModal
|
||||
datasource={datasource}
|
||||
isOpen={metricsModalOpen}
|
||||
|
@ -25,7 +25,6 @@ const instanceSettings = {
|
||||
|
||||
const dataSourceMock = new PrometheusDatasource(instanceSettings);
|
||||
const mockValues = [{ label: 'random_metric' }, { label: 'unique_metric' }, { label: 'more_unique_metric' }];
|
||||
|
||||
// Mock metricFindQuery which will call backend API
|
||||
//@ts-ignore
|
||||
dataSourceMock.metricFindQuery = jest.fn((query: string) => {
|
||||
@ -69,7 +68,8 @@ describe('MetricSelect', () => {
|
||||
await waitFor(() => expect(screen.getByText('random_metric')).toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.getByText('unique_metric')).toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.getByText('more_unique_metric')).toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.getAllByTestId(selectors.components.Select.option)).toHaveLength(3));
|
||||
await waitFor(() => expect(screen.getByText('Metrics explorer')).toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.getAllByTestId(selectors.components.Select.option)).toHaveLength(4));
|
||||
});
|
||||
|
||||
it('truncates list of metrics to 1000', async () => {
|
||||
@ -81,7 +81,10 @@ describe('MetricSelect', () => {
|
||||
|
||||
render(<MetricSelect {...props} />);
|
||||
await openMetricSelect();
|
||||
await waitFor(() => expect(screen.getAllByTestId(selectors.components.Select.option)).toHaveLength(1000));
|
||||
// the metrics explorer is added as a custom option
|
||||
const optionsLength = screen.getAllByTestId(selectors.components.Select.option).length;
|
||||
const optionsLengthMinusMetricsExplorer = optionsLength - 1;
|
||||
await waitFor(() => expect(optionsLengthMinusMetricsExplorer).toBe(1000));
|
||||
});
|
||||
|
||||
it('shows option to set custom value when typing', async () => {
|
||||
@ -97,7 +100,8 @@ describe('MetricSelect', () => {
|
||||
await openMetricSelect();
|
||||
const input = screen.getByRole('combobox');
|
||||
await userEvent.type(input, 'unique');
|
||||
await waitFor(() => expect(screen.getAllByTestId(selectors.components.Select.option)).toHaveLength(3));
|
||||
const optionsLength = mockValues.length + 1; // the metrics explorer is added as a custom option
|
||||
await waitFor(() => expect(screen.getAllByTestId(selectors.components.Select.option)).toHaveLength(optionsLength));
|
||||
});
|
||||
|
||||
it('searches on split words', async () => {
|
||||
@ -105,7 +109,8 @@ describe('MetricSelect', () => {
|
||||
await openMetricSelect();
|
||||
const input = screen.getByRole('combobox');
|
||||
await userEvent.type(input, 'more unique');
|
||||
await waitFor(() => expect(screen.getAllByTestId(selectors.components.Select.option)).toHaveLength(2));
|
||||
// the metrics explorer is added as a custom option
|
||||
await waitFor(() => expect(screen.getAllByTestId(selectors.components.Select.option)).toHaveLength(3));
|
||||
});
|
||||
|
||||
it('searches on multiple split words', async () => {
|
||||
@ -113,7 +118,8 @@ describe('MetricSelect', () => {
|
||||
await openMetricSelect();
|
||||
const input = screen.getByRole('combobox');
|
||||
await userEvent.type(input, 'more unique metric');
|
||||
await waitFor(() => expect(screen.getAllByTestId(selectors.components.Select.option)).toHaveLength(2));
|
||||
// the metrics explorer is added as a custom option
|
||||
await waitFor(() => expect(screen.getAllByTestId(selectors.components.Select.option)).toHaveLength(3));
|
||||
});
|
||||
|
||||
it('highlights matching string', async () => {
|
||||
|
@ -8,7 +8,6 @@ import Highlighter from 'react-highlight-words';
|
||||
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { EditorField, EditorFieldGroup } from '@grafana/experimental';
|
||||
import { config } from '@grafana/runtime';
|
||||
import {
|
||||
AsyncSelect,
|
||||
Button,
|
||||
@ -67,8 +66,6 @@ export function MetricSelect({
|
||||
resultsTruncated?: boolean;
|
||||
}>({});
|
||||
|
||||
const prometheusMetricEncyclopedia = config.featureToggles.prometheusMetricEncyclopedia;
|
||||
|
||||
const metricsModalOption: SelectableValue[] = [
|
||||
{
|
||||
value: 'BrowseMetrics',
|
||||
@ -77,33 +74,25 @@ export function MetricSelect({
|
||||
},
|
||||
];
|
||||
|
||||
const customFilterOption = useCallback(
|
||||
(option: SelectableValue, searchQuery: string) => {
|
||||
const label = option.label ?? option.value;
|
||||
if (!label) {
|
||||
return false;
|
||||
}
|
||||
const customFilterOption = useCallback((option: SelectableValue, searchQuery: string) => {
|
||||
const label = option.label ?? option.value;
|
||||
if (!label) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// custom value is not a string label but a react node
|
||||
if (!label.toLowerCase) {
|
||||
return true;
|
||||
}
|
||||
// custom value is not a string label but a react node
|
||||
if (!label.toLowerCase) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const searchWords = searchQuery.split(splitSeparator);
|
||||
const searchWords = searchQuery.split(splitSeparator);
|
||||
|
||||
return searchWords.reduce((acc, cur) => {
|
||||
const matcheSearch = label.toLowerCase().includes(cur.toLowerCase());
|
||||
|
||||
let browseOption = false;
|
||||
if (prometheusMetricEncyclopedia) {
|
||||
browseOption = label === 'Metrics explorer';
|
||||
}
|
||||
|
||||
return acc && (matcheSearch || browseOption);
|
||||
}, true);
|
||||
},
|
||||
[prometheusMetricEncyclopedia]
|
||||
);
|
||||
return searchWords.reduce((acc, cur) => {
|
||||
const matcheSearch = label.toLowerCase().includes(cur.toLowerCase());
|
||||
const browseOption = label === 'Metrics explorer';
|
||||
return acc && (matcheSearch || browseOption);
|
||||
}, true);
|
||||
}, []);
|
||||
|
||||
const formatOptionLabel = useCallback(
|
||||
(option: SelectableValue, meta: FormatOptionLabelMeta<any>) => {
|
||||
@ -159,11 +148,7 @@ export function MetricSelect({
|
||||
};
|
||||
});
|
||||
|
||||
if (prometheusMetricEncyclopedia) {
|
||||
return [...metricsModalOption, ...resultsOptions];
|
||||
} else {
|
||||
return resultsOptions;
|
||||
}
|
||||
return [...metricsModalOption, ...resultsOptions];
|
||||
});
|
||||
};
|
||||
|
||||
@ -286,22 +271,14 @@ export function MetricSelect({
|
||||
truncateResult(metrics);
|
||||
}
|
||||
|
||||
if (prometheusMetricEncyclopedia) {
|
||||
setState({
|
||||
// add the modal button option to the options
|
||||
metrics: [...metricsModalOption, ...metrics],
|
||||
isLoading: undefined,
|
||||
// pass the initial metrics into the metrics explorer
|
||||
initialMetrics: initialMetrics,
|
||||
resultsTruncated: resultsLength > metrics.length,
|
||||
});
|
||||
} else {
|
||||
setState({
|
||||
metrics,
|
||||
isLoading: undefined,
|
||||
resultsTruncated: resultsLength > metrics.length,
|
||||
});
|
||||
}
|
||||
setState({
|
||||
// add the modal button option to the options
|
||||
metrics: [...metricsModalOption, ...metrics],
|
||||
isLoading: undefined,
|
||||
// pass the initial metrics into the metrics explorer
|
||||
initialMetrics: initialMetrics,
|
||||
resultsTruncated: resultsLength > metrics.length,
|
||||
});
|
||||
}}
|
||||
loadOptions={metricLookupDisabled ? metricLookupDisabledSearch : debouncedSearch}
|
||||
isLoading={state.isLoading}
|
||||
@ -309,8 +286,8 @@ export function MetricSelect({
|
||||
onChange={(input) => {
|
||||
const value = input?.value;
|
||||
if (value) {
|
||||
// if there is no metric and the m.e. is enabled, open the modal
|
||||
if (prometheusMetricEncyclopedia && value === 'BrowseMetrics') {
|
||||
// if there is no metric and the value is the custom m.e. option, open the modal
|
||||
if (value === 'BrowseMetrics') {
|
||||
tracking('grafana_prometheus_metric_encyclopedia_open', null, '', query);
|
||||
setState({ ...state, metricsModalOpen: true });
|
||||
} else {
|
||||
@ -320,9 +297,7 @@ export function MetricSelect({
|
||||
onChange({ ...query, metric: '' });
|
||||
}
|
||||
}}
|
||||
components={
|
||||
prometheusMetricEncyclopedia ? { Option: CustomOption, MenuList: CustomMenu } : { MenuList: CustomMenu }
|
||||
}
|
||||
components={{ Option: CustomOption, MenuList: CustomMenu }}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
);
|
||||
@ -330,7 +305,7 @@ export function MetricSelect({
|
||||
|
||||
return (
|
||||
<>
|
||||
{prometheusMetricEncyclopedia && !datasource.lookupsDisabled && state.metricsModalOpen && (
|
||||
{!datasource.lookupsDisabled && state.metricsModalOpen && (
|
||||
<MetricsModal
|
||||
datasource={datasource}
|
||||
isOpen={state.metricsModalOpen}
|
||||
|
@ -19,9 +19,14 @@ describe('PromQueryBuilderContainer', () => {
|
||||
|
||||
expect(screen.getByText('metric_test')).toBeInTheDocument();
|
||||
await addOperationInQueryBuilder('Range functions', 'Rate');
|
||||
// extra fields here are for storing metrics explorer settings. Future work: store these in local storage.
|
||||
expect(props.onChange).toHaveBeenCalledWith({
|
||||
disableTextWrap: false,
|
||||
expr: 'rate(metric_test{job="testjob"}[$__rate_interval])',
|
||||
fullMetaSearch: false,
|
||||
includeNullMetadata: true,
|
||||
refId: 'A',
|
||||
useBackend: false,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -3,7 +3,6 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { useEffect, useReducer } from 'react';
|
||||
|
||||
import { PanelData } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { PrometheusDatasource } from '../../datasource';
|
||||
import { PromQuery } from '../../types';
|
||||
@ -29,8 +28,6 @@ export interface State {
|
||||
expr: string;
|
||||
}
|
||||
|
||||
const prometheusMetricEncyclopedia = config.featureToggles.prometheusMetricEncyclopedia;
|
||||
|
||||
/**
|
||||
* This component is here just to contain the translation logic between string query and the visual query builder model.
|
||||
*/
|
||||
@ -40,17 +37,14 @@ export function PromQueryBuilderContainer(props: PromQueryBuilderContainerProps)
|
||||
// Only rebuild visual query if expr changes from outside
|
||||
useEffect(() => {
|
||||
dispatch(exprChanged(query.expr));
|
||||
|
||||
if (prometheusMetricEncyclopedia) {
|
||||
dispatch(
|
||||
setMetricsModalSettings({
|
||||
useBackend: query.useBackend ?? false,
|
||||
disableTextWrap: query.disableTextWrap ?? false,
|
||||
fullMetaSearch: query.fullMetaSearch ?? false,
|
||||
includeNullMetadata: query.includeNullMetadata ?? true,
|
||||
})
|
||||
);
|
||||
}
|
||||
dispatch(
|
||||
setMetricsModalSettings({
|
||||
useBackend: query.useBackend ?? false,
|
||||
disableTextWrap: query.disableTextWrap ?? false,
|
||||
fullMetaSearch: query.fullMetaSearch ?? false,
|
||||
includeNullMetadata: query.includeNullMetadata ?? true,
|
||||
})
|
||||
);
|
||||
}, [query]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -61,12 +55,8 @@ export function PromQueryBuilderContainer(props: PromQueryBuilderContainerProps)
|
||||
const expr = promQueryModeller.renderQuery(visQuery);
|
||||
dispatch(visualQueryChange({ visQuery, expr }));
|
||||
|
||||
if (prometheusMetricEncyclopedia) {
|
||||
const metricsModalSettings = getSettings(visQuery);
|
||||
onChange({ ...props.query, expr: expr, ...metricsModalSettings });
|
||||
} else {
|
||||
onChange({ ...props.query, expr: expr });
|
||||
}
|
||||
const metricsModalSettings = getSettings(visQuery);
|
||||
onChange({ ...props.query, expr: expr, ...metricsModalSettings });
|
||||
};
|
||||
|
||||
if (!state.visQuery) {
|
||||
@ -109,7 +99,7 @@ const stateSlice = createSlice({
|
||||
}
|
||||
},
|
||||
setMetricsModalSettings: (state, action: PayloadAction<MetricsModalSettings>) => {
|
||||
if (state.visQuery && prometheusMetricEncyclopedia) {
|
||||
if (state.visQuery) {
|
||||
state.visQuery.useBackend = action.payload.useBackend;
|
||||
state.visQuery.disableTextWrap = action.payload.disableTextWrap;
|
||||
state.visQuery.fullMetaSearch = action.payload.fullMetaSearch;
|
||||
|
@ -272,15 +272,6 @@ var (
|
||||
Stage: FeatureStageExperimental,
|
||||
Owner: grafanaBackendGroup,
|
||||
},
|
||||
{
|
||||
Name: "prometheusMetricEncyclopedia",
|
||||
Description: "Adds the metrics explorer component to the Prometheus query builder as an option in metric select",
|
||||
Expression: "true",
|
||||
Stage: FeatureStageGeneralAvailability,
|
||||
FrontendOnly: true,
|
||||
Owner: grafanaObservabilityMetricsSquad,
|
||||
AllowSelfServe: true,
|
||||
},
|
||||
{
|
||||
Name: "influxdbBackendMigration",
|
||||
Description: "Query InfluxDB InfluxQL without the proxy",
|
||||
|
@ -34,7 +34,6 @@ lokiShardSplitting,experimental,@grafana/observability-logs,false,false,true
|
||||
lokiQuerySplitting,GA,@grafana/observability-logs,false,false,true
|
||||
lokiQuerySplittingConfig,experimental,@grafana/observability-logs,false,false,true
|
||||
individualCookiePreferences,experimental,@grafana/grafana-backend-group,false,false,false
|
||||
prometheusMetricEncyclopedia,GA,@grafana/observability-metrics,false,false,true
|
||||
influxdbBackendMigration,GA,@grafana/observability-metrics,false,false,true
|
||||
influxqlStreamingParser,experimental,@grafana/observability-metrics,false,false,false
|
||||
influxdbRunQueriesInParallel,privatePreview,@grafana/observability-metrics,false,false,false
|
||||
|
|
@ -147,10 +147,6 @@ const (
|
||||
// Support overriding cookie preferences per user
|
||||
FlagIndividualCookiePreferences = "individualCookiePreferences"
|
||||
|
||||
// FlagPrometheusMetricEncyclopedia
|
||||
// Adds the metrics explorer component to the Prometheus query builder as an option in metric select
|
||||
FlagPrometheusMetricEncyclopedia = "prometheusMetricEncyclopedia"
|
||||
|
||||
// FlagInfluxdbBackendMigration
|
||||
// Query InfluxDB InfluxQL without the proxy
|
||||
FlagInfluxdbBackendMigration = "influxdbBackendMigration"
|
||||
|
@ -2952,6 +2952,7 @@
|
||||
"name": "prometheusMetricEncyclopedia",
|
||||
"resourceVersion": "1720021873452",
|
||||
"creationTimestamp": "2023-03-07T18:41:05Z",
|
||||
"deletionTimestamp": "2024-12-30T14:42:45Z",
|
||||
"annotations": {
|
||||
"grafana.app/updatedTimestamp": "2024-07-03 15:51:13.452477 +0000 UTC"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user