From 5cd3ad76ee4ff309aa1ae9b98ee1d65c6c55398b Mon Sep 17 00:00:00 2001 From: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Date: Wed, 2 Jul 2025 12:08:22 +0200 Subject: [PATCH] Loki: Remove `lokiQueryHints` feature toggle (#106620) * Loki: Remove lokiQueryHints feature toggle * Remove unused imports * Fix tests --- .../feature-toggles/index.md | 2 +- .../src/types/featureToggles.gen.ts | 5 ++--- pkg/services/featuremgmt/registry.go | 13 +++++------ pkg/services/featuremgmt/toggles_gen.csv | 2 +- pkg/services/featuremgmt/toggles_gen.go | 6 ++--- pkg/services/featuremgmt/toggles_gen.json | 5 +++-- .../datasource/loki/LanguageProvider.test.ts | 14 ------------ .../datasource/loki/LanguageProvider.ts | 3 --- .../components/LabelParamEditor.test.tsx | 9 -------- .../components/LokiQueryBuilder.test.tsx | 9 -------- .../components/LokiQueryBuilder.tsx | 3 +-- .../LokiQueryBuilderContainer.test.tsx | 22 ++++++++++++++----- .../components/UnwrapParamEditor.test.tsx | 19 ---------------- .../components/UnwrapParamEditor.tsx | 3 +-- 14 files changed, 33 insertions(+), 82 deletions(-) diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index da44ded91fe..ef2ca7ab494 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -53,7 +53,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general- | `ssoSettingsApi` | Enables the SSO settings API and the OAuth configuration UIs in Grafana | Yes | | `logsInfiniteScrolling` | Enables infinite scrolling for the Logs panel in Explore and Dashboards | Yes | | `logRowsPopoverMenu` | Enable filtering menu displayed when text of a log line is selected | Yes | -| `lokiQueryHints` | Enables query hints for Loki | Yes | | `alertingQueryOptimization` | Optimizes eligible queries in order to reduce load on datasources | | | `onPremToCloudMigrations` | Enable the Grafana Migration Assistant, which helps you easily migrate various on-prem resources to your Grafana Cloud stack. | Yes | | `groupToNestedTableTransformation` | Enables the group to nested table transformation | Yes | @@ -103,6 +102,7 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general- | `cloudWatchBatchQueries` | Runs CloudWatch metrics queries as separate batches | | `pdfTables` | Enables generating table data as PDF in reporting | | `canvasPanelPanZoom` | Allow pan and zoom in canvas panel | +| `regressionTransformation` | Enables regression analysis transformation | | `alertingSaveStateCompressed` | Enables the compressed protobuf-based alert state storage | | `tableNextGen` | Allows access to the new react-data-grid based table component. | | `enableSCIM` | Enables SCIM support for user and group management | diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index e76e1b494ae..167962c0745 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -420,10 +420,9 @@ export interface FeatureToggles { */ tableSharedCrosshair?: boolean; /** - * Enables query hints for Loki - * @default true + * Enables regression analysis transformation */ - lokiQueryHints?: boolean; + regressionTransformation?: boolean; /** * Use the kubernetes API for feature toggle management in the frontend */ diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 417d95f0d52..fe6fe7d4fab 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -698,14 +698,11 @@ var ( Owner: grafanaDatavizSquad, }, { - // this is mainly used as a way to quickly disable query hints as a safeguard for our infrastructure - Name: "lokiQueryHints", - Description: "Enables query hints for Loki", - Stage: FeatureStageGeneralAvailability, - FrontendOnly: true, - Expression: "true", - Owner: grafanaObservabilityLogsSquad, - AllowSelfServe: false, + Name: "regressionTransformation", + Description: "Enables regression analysis transformation", + Stage: FeatureStagePublicPreview, + FrontendOnly: true, + Owner: grafanaDatavizSquad, }, { Name: "kubernetesFeatureToggles", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index bbd8023623b..5b44906dfc1 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -92,7 +92,7 @@ logsInfiniteScrolling,GA,@grafana/observability-logs,false,false,true logRowsPopoverMenu,GA,@grafana/observability-logs,false,false,true pluginsSkipHostEnvVars,experimental,@grafana/plugins-platform-backend,false,false,false tableSharedCrosshair,experimental,@grafana/dataviz-squad,false,false,true -lokiQueryHints,GA,@grafana/observability-logs,false,false,true +regressionTransformation,preview,@grafana/dataviz-squad,false,false,true kubernetesFeatureToggles,experimental,@grafana/grafana-operator-experience-squad,false,false,true cloudRBACRoles,preview,@grafana/identity-access-team,false,true,false alertingQueryOptimization,GA,@grafana/alerting-squad,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 47d4562df37..bc513ac82d5 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -379,9 +379,9 @@ const ( // Enables shared crosshair in table panel FlagTableSharedCrosshair = "tableSharedCrosshair" - // FlagLokiQueryHints - // Enables query hints for Loki - FlagLokiQueryHints = "lokiQueryHints" + // FlagRegressionTransformation + // Enables regression analysis transformation + FlagRegressionTransformation = "regressionTransformation" // FlagKubernetesFeatureToggles // Use the kubernetes API for feature toggle management in the frontend diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index ce8ab6502f3..c1cb552b6bb 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -1868,8 +1868,9 @@ { "metadata": { "name": "lokiQueryHints", - "resourceVersion": "1750434297879", - "creationTimestamp": "2023-12-18T20:43:16Z" + "resourceVersion": "1743693517832", + "creationTimestamp": "2023-12-18T20:43:16Z", + "deletionTimestamp": "2025-06-12T12:14:47Z" }, "spec": { "description": "Enables query hints for Loki", diff --git a/public/app/plugins/datasource/loki/LanguageProvider.test.ts b/public/app/plugins/datasource/loki/LanguageProvider.test.ts index dec28df9f0a..eb449333632 100644 --- a/public/app/plugins/datasource/loki/LanguageProvider.test.ts +++ b/public/app/plugins/datasource/loki/LanguageProvider.test.ts @@ -681,14 +681,6 @@ describe('Query imports', () => { }); describe('getParserAndLabelKeys()', () => { - const queryHintsFeatureToggle = config.featureToggles.lokiQueryHints; - beforeAll(() => { - config.featureToggles.lokiQueryHints = true; - }); - afterAll(() => { - config.featureToggles.lokiQueryHints = queryHintsFeatureToggle; - }); - let datasource: LokiDatasource, languageProvider: LanguageProvider; const extractLogParserFromDataFrameMock = jest.mocked(extractLogParserFromDataFrame); const extractedLabelKeys = ['extracted', 'label']; @@ -810,12 +802,6 @@ describe('Query imports', () => { mockTimeRange ); }); - it('does not call dataSample with feature toggle disabled', async () => { - config.featureToggles.lokiQueryHints = false; - jest.spyOn(datasource, 'getDataSamples'); - languageProvider.getParserAndLabelKeys('{place="luna"}', { timeRange: mockTimeRange }); - expect(datasource.getDataSamples).not.toHaveBeenCalled(); - }); }); }); diff --git a/public/app/plugins/datasource/loki/LanguageProvider.ts b/public/app/plugins/datasource/loki/LanguageProvider.ts index d6bae1ea6d1..5607980b557 100644 --- a/public/app/plugins/datasource/loki/LanguageProvider.ts +++ b/public/app/plugins/datasource/loki/LanguageProvider.ts @@ -477,9 +477,6 @@ export default class LokiLanguageProvider extends LanguageProvider { hasLogfmt: false, hasPack: false, }; - if (!config.featureToggles.lokiQueryHints) { - return empty; - } const series = await this.datasource.getDataSamples( { diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.test.tsx index 22dd10dda7a..6439936934d 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.test.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.test.tsx @@ -4,7 +4,6 @@ import { ComponentProps } from 'react'; import { DataSourceApi } from '@grafana/data'; import { QueryBuilderOperation, QueryBuilderOperationParamDef } from '@grafana/plugin-ui'; -import { config } from '@grafana/runtime'; import { LokiDatasource } from '../../datasource'; import { createLokiDatasource } from '../../mocks/datasource'; @@ -14,14 +13,6 @@ import { LokiOperationId } from '../types'; import { LabelParamEditor } from './LabelParamEditor'; describe('LabelParamEditor', () => { - const queryHintsFeatureToggle = config.featureToggles.lokiQueryHints; - beforeAll(() => { - config.featureToggles.lokiQueryHints = true; - }); - afterAll(() => { - config.featureToggles.lokiQueryHints = queryHintsFeatureToggle; - }); - it('shows label options', async () => { const props = createProps({}, ['label1', 'label2']); render(); diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.test.tsx index 2d3d1a73461..dc6dcbce805 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.test.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.test.tsx @@ -2,7 +2,6 @@ import { render, screen, getAllByRole, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { dateTime } from '@grafana/data'; -import { config } from '@grafana/runtime'; import { createLokiDatasource } from '../../mocks/datasource'; import { LokiOperationId, LokiVisualQuery } from '../types'; @@ -40,14 +39,6 @@ const createDefaultProps = () => { }; describe('LokiQueryBuilder', () => { - const originalLokiQueryHints = config.featureToggles.lokiQueryHints; - beforeEach(() => { - config.featureToggles.lokiQueryHints = true; - }); - - afterEach(() => { - config.featureToggles.lokiQueryHints = originalLokiQueryHints; - }); it('tries to load label names', async () => { const props = createDefaultProps(); props.datasource.getDataSamples = jest.fn().mockResolvedValue([]); diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx index 96e7a1fa79c..632ac1f7a11 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx @@ -15,7 +15,6 @@ import { QueryBuilderLabelFilter, QueryBuilderOperation, } from '@grafana/plugin-ui'; -import { config } from '@grafana/runtime'; import { testIds } from '../../components/LokiQueryEditor'; import { LokiDatasource } from '../../datasource'; @@ -126,7 +125,7 @@ export const LokiQueryBuilder = memo(({ datasource, query, onChange, onRu (Math.abs(timeRange.to.valueOf() - prevTimeRange.to.valueOf()) > TIME_SPAN_TO_TRIGGER_SAMPLES || Math.abs(timeRange.from.valueOf() - prevTimeRange.from.valueOf()) > TIME_SPAN_TO_TRIGGER_SAMPLES); const updateBasedOnChangedQuery = !isEqual(prevQuery, query); - if (config.featureToggles.lokiQueryHints && (updateBasedOnChangedTimeRange || updateBasedOnChangedQuery)) { + if (updateBasedOnChangedTimeRange || updateBasedOnChangedQuery) { onGetSampleData().catch(console.error); } }, [datasource, query, timeRange, prevQuery, prevTimeRange]); diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx index 3c8c5c94704..ac1ffe809c0 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx @@ -1,4 +1,4 @@ -import { render, screen, waitFor, findAllByRole } from '@testing-library/react'; +import { render, screen, waitFor, findAllByRole, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { createLokiDatasource } from '../../mocks/datasource'; @@ -19,7 +19,9 @@ describe('LokiQueryBuilderContainer', () => { }; props.datasource.getDataSamples = jest.fn().mockResolvedValue([]); - render(); + await act(async () => { + render(); + }); const selector = await screen.findByLabelText('selector'); expect(selector.textContent).toBe('{job="testjob"}'); await addOperation('Range functions', 'Rate'); @@ -45,7 +47,9 @@ describe('LokiQueryBuilderContainer', () => { props.datasource.languageProvider.fetchLabelValues = jest.fn().mockReturnValue(['grafana', 'loki']); props.onChange = jest.fn(); - render(); + await act(async () => { + render(); + }); await userEvent.click(screen.getByLabelText('Add')); const labels = screen.getByText(/Label filters/); const selects = await findAllByRole(getSelectParent(labels)!, 'combobox'); @@ -78,7 +82,9 @@ describe('LokiQueryBuilderContainer', () => { showExplain: false, }; props.datasource.getDataSamples = jest.fn().mockResolvedValue([]); - render(); + await act(async () => { + render(); + }); expect(screen.getByText('{')).toHaveClass('token punctuation'); expect(screen.getByText('"baz"')).toHaveClass('token label-value attr-value'); expect(screen.getByText('|')).toHaveClass('token pipe-operator operator'); @@ -98,7 +104,9 @@ describe('LokiQueryBuilderContainer', () => { }; props.datasource.getDataSamples = jest.fn().mockResolvedValue([]); - render(); + await act(async () => { + render(); + }); expect(screen.getAllByText('You have conflicting label filters')).toHaveLength(2); }); @@ -115,7 +123,9 @@ describe('LokiQueryBuilderContainer', () => { }; props.datasource.getDataSamples = jest.fn().mockResolvedValue([]); - render(); + await act(async () => { + render(); + }); expect(screen.getByText('<')).toBeInTheDocument(); expect(screen.getByText('expr')).toBeInTheDocument(); expect(screen.getByText('>')).toBeInTheDocument(); diff --git a/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.test.tsx index beacb3736b4..f21d37b2544 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.test.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.test.tsx @@ -4,7 +4,6 @@ import { ComponentProps } from 'react'; import { DataFrame, DataSourceApi, FieldType, toDataFrame } from '@grafana/data'; import { QueryBuilderOperation, QueryBuilderOperationParamDef } from '@grafana/plugin-ui'; -import { config } from '@grafana/runtime'; import { LokiDatasource } from '../../datasource'; import { createLokiDatasource } from '../../mocks/datasource'; @@ -14,14 +13,6 @@ import { LokiOperationId } from '../types'; import { UnwrapParamEditor } from './UnwrapParamEditor'; describe('UnwrapParamEditor', () => { - const queryHintsFeatureToggle = config.featureToggles.lokiQueryHints; - beforeAll(() => { - config.featureToggles.lokiQueryHints = true; - }); - afterAll(() => { - config.featureToggles.lokiQueryHints = queryHintsFeatureToggle; - }); - it('shows value if value present', () => { const props = createProps({ value: 'unique' }); render(); @@ -60,16 +51,6 @@ describe('UnwrapParamEditor', () => { expect(await screen.findByText('status')).toBeInTheDocument(); expect(await screen.findByText('duration')).toBeInTheDocument(); }); - - it('does not show labels with unwrap-friendly values when feature is disabled', async () => { - config.featureToggles.lokiQueryHints = false; - const props = createProps({}, frames); - render(); - const input = screen.getByRole('combobox'); - await userEvent.click(input); - expect(screen.queryByText('status')).not.toBeInTheDocument(); - expect(screen.queryByText('duration')).not.toBeInTheDocument(); - }); }); const createProps = ( diff --git a/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.tsx b/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.tsx index 630cb285568..bfb8306b6f0 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.tsx @@ -2,7 +2,6 @@ import { useState } from 'react'; import { SelectableValue, getDefaultTimeRange, toOption } from '@grafana/data'; import { QueryBuilderOperationParamEditorProps, VisualQueryModeller } from '@grafana/plugin-ui'; -import { config } from '@grafana/runtime'; import { Select } from '@grafana/ui'; import { placeHolderScopedVars } from '../../components/monaco-query-field/monaco-completion-provider/validation'; @@ -32,7 +31,7 @@ export function UnwrapParamEditor({ inputId={getOperationParamId(operationId, index)} onOpenMenu={async () => { // This check is always true, we do it to make typescript happy - if (datasource instanceof LokiDatasource && config.featureToggles.lokiQueryHints) { + if (datasource instanceof LokiDatasource) { setState({ isLoading: true }); const options = await loadUnwrapOptions(query, datasource, queryModeller, timeRange); setState({ options, isLoading: undefined });