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 dea03f07484..2653da9f879 100644
--- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
+++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
@@ -79,7 +79,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
| `grafanaAssistantInProfilesDrilldown` | Enables integration with Grafana Assistant in Profiles Drilldown | Yes |
| `sharingDashboardImage` | Enables image sharing functionality for dashboards | Yes |
| `tabularNumbers` | Use fixed-width numbers globally in the UI | |
-| `dashboardDsAdHocFiltering` | Enables adhoc filtering support for the dashboard datasource | Yes |
| `adhocFiltersInTooltips` | Enable adhoc filter buttons in visualization tooltips | Yes |
| `tempoSearchBackendMigration` | Run search queries through the tempo backend | |
diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts
index 89e1f8e9aed..d77c6821339 100644
--- a/packages/grafana-data/src/types/featureToggles.gen.ts
+++ b/packages/grafana-data/src/types/featureToggles.gen.ts
@@ -1119,11 +1119,6 @@ export interface FeatureToggles {
*/
unifiedStorageSearchDualReaderEnabled?: boolean;
/**
- * Enables adhoc filtering support for the dashboard datasource
- * @default true
- */
- dashboardDsAdHocFiltering?: boolean;
- /**
* Supports __from and __to macros that always use the dashboard level time range
*/
dashboardLevelTimeMacros?: boolean;
diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go
index 6bc730b8d50..0b4f483e502 100644
--- a/pkg/services/featuremgmt/registry.go
+++ b/pkg/services/featuremgmt/registry.go
@@ -1942,14 +1942,6 @@ var (
HideFromAdminPage: true,
HideFromDocs: true,
},
- {
- Name: "dashboardDsAdHocFiltering",
- Description: "Enables adhoc filtering support for the dashboard datasource",
- Stage: FeatureStageGeneralAvailability,
- Owner: grafanaDataProSquad,
- FrontendOnly: true,
- Expression: "true",
- },
{
Name: "dashboardLevelTimeMacros",
Description: "Supports __from and __to macros that always use the dashboard level time range",
diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv
index 8695ec64f57..3822dfc8c8d 100644
--- a/pkg/services/featuremgmt/toggles_gen.csv
+++ b/pkg/services/featuremgmt/toggles_gen.csv
@@ -250,7 +250,6 @@ foldersAppPlatformAPI,experimental,@grafana/grafana-search-navigate-organise,fal
otelLogsFormatting,experimental,@grafana/observability-logs,false,false,true
alertingNotificationHistory,experimental,@grafana/alerting-squad,false,false,false
unifiedStorageSearchDualReaderEnabled,experimental,@grafana/search-and-storage,false,false,false
-dashboardDsAdHocFiltering,GA,@grafana/datapro,false,false,true
dashboardLevelTimeMacros,experimental,@grafana/dashboards-squad,false,false,true
alertmanagerRemoteSecondaryWithRemoteState,experimental,@grafana/alerting-squad,false,false,false
restrictedPluginApis,experimental,@grafana/plugins-platform-backend,false,false,true
diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go
index fe407b9066f..a1a1be66f54 100644
--- a/pkg/services/featuremgmt/toggles_gen.go
+++ b/pkg/services/featuremgmt/toggles_gen.go
@@ -1010,10 +1010,6 @@ const (
// Enable dual reader for unified storage search
FlagUnifiedStorageSearchDualReaderEnabled = "unifiedStorageSearchDualReaderEnabled"
- // FlagDashboardDsAdHocFiltering
- // Enables adhoc filtering support for the dashboard datasource
- FlagDashboardDsAdHocFiltering = "dashboardDsAdHocFiltering"
-
// FlagDashboardLevelTimeMacros
// Supports __from and __to macros that always use the dashboard level time range
FlagDashboardLevelTimeMacros = "dashboardLevelTimeMacros"
diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json
index dbf4d982629..05c83353ac6 100644
--- a/pkg/services/featuremgmt/toggles_gen.json
+++ b/pkg/services/featuremgmt/toggles_gen.json
@@ -1061,6 +1061,7 @@
"name": "dashboardDsAdHocFiltering",
"resourceVersion": "1756814786992",
"creationTimestamp": "2025-07-23T08:12:25Z",
+ "deletionTimestamp": "2025-09-27T19:59:33Z",
"annotations": {
"grafana.app/updatedTimestamp": "2025-09-02 12:06:26.992384 +0000 UTC"
}
diff --git a/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.tsx
index 29183c79531..5434068f21e 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.tsx
@@ -4,7 +4,6 @@ import { DataSourceInstanceSettings, MetricFindValue, readCSV } from '@grafana/d
import { selectors } from '@grafana/e2e-selectors';
import { Trans, t } from '@grafana/i18n';
import { EditorField } from '@grafana/plugin-ui';
-import { config } from '@grafana/runtime';
import { DataSourceRef } from '@grafana/schema';
import { Alert, CodeEditor, Field, Switch, Box } from '@grafana/ui';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
@@ -67,7 +66,7 @@ export function AdHocVariableForm({
onChange={onDataSourceChange}
width={30}
variables={true}
- dashboard={config.featureToggles.dashboardDsAdHocFiltering}
+ dashboard={true}
noDefault
/>
diff --git a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.test.tsx b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.test.tsx
index 2cbfa311d7b..876e996dbe8 100644
--- a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.test.tsx
@@ -1,8 +1,7 @@
-import { act, render, screen, waitFor } from '@testing-library/react';
+import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { getDefaultTimeRange, LoadingState } from '@grafana/data';
-import config from 'app/core/config';
import { mockDataSource } from 'app/features/alerting/unified/mocks';
import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources';
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
@@ -30,9 +29,6 @@ jest.mock('app/core/config', () => ({
},
},
},
- featureToggles: {
- dashboardDsAdHocFiltering: false, // Default to false, can be overridden in tests
- },
}));
setupDataSources(mockDataSource({ isDefault: true }));
@@ -179,11 +175,7 @@ describe('DashboardQueryEditor', () => {
jest.spyOn(getDashboardSrv(), 'getCurrent').mockImplementation(() => mockDashboard);
});
- it('shows the AdHoc Filters toggle when feature toggle is enabled', async () => {
- await act(async () => {
- config.featureToggles.dashboardDsAdHocFiltering = true;
- });
-
+ it('shows the AdHoc Filters toggle', async () => {
const query: DashboardQuery = { refId: 'A', panelId: 1, adHocFiltersEnabled: false };
await act(async () => {
@@ -201,30 +193,5 @@ describe('DashboardQueryEditor', () => {
const adhocFiltersToggle = await screen.findByText('AdHoc Filters');
expect(adhocFiltersToggle).toBeInTheDocument();
});
-
- it('does not show the AdHoc Filters toggle when feature toggle is disabled', async () => {
- await act(async () => {
- config.featureToggles.dashboardDsAdHocFiltering = false;
- });
-
- const query: DashboardQuery = { refId: 'A', panelId: 1, adHocFiltersEnabled: false };
-
- await act(async () => {
- render(
-
- );
- });
-
- // Wait for any async operations to complete
- await waitFor(() => {
- expect(screen.queryByText('AdHoc Filters')).not.toBeInTheDocument();
- });
- });
});
});
diff --git a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx
index e137069219d..d8e9b952281 100644
--- a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx
+++ b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx
@@ -205,15 +205,13 @@ export function DashboardQueryEditor({ data, query, onChange, onRunQuery }: Prop
)}
- {config.featureToggles.dashboardDsAdHocFiltering && (
-
-
-
- )}
+
+
+
{loadingResults ? (
diff --git a/public/app/plugins/datasource/dashboard/datasource.test.ts b/public/app/plugins/datasource/dashboard/datasource.test.ts
index 55d7a12968d..2dcb17c63db 100644
--- a/public/app/plugins/datasource/dashboard/datasource.test.ts
+++ b/public/app/plugins/datasource/dashboard/datasource.test.ts
@@ -12,7 +12,7 @@ import {
AdHocVariableFilter,
} from '@grafana/data';
import { getPanelPlugin } from '@grafana/data/test';
-import { setPluginImportUtils, config } from '@grafana/runtime';
+import { setPluginImportUtils } from '@grafana/runtime';
import {
SafeSerializableSceneObject,
SceneDataNode,
@@ -178,16 +178,6 @@ describe('DashboardDatasource', () => {
// Test AdHoc filtering via the Public API first, to ensure Integration
describe('Integration (Public API)', () => {
- const originalToggleValue = config.featureToggles.dashboardDsAdHocFiltering;
-
- beforeEach(() => {
- config.featureToggles.dashboardDsAdHocFiltering = true;
- });
-
- afterEach(() => {
- config.featureToggles.dashboardDsAdHocFiltering = originalToggleValue;
- });
-
it('should apply basic filtering end-to-end through public query method', async () => {
const testFrame = createTestFrame([
{ name: 'name', type: FieldType.string, values: ['John', 'Jane', 'Bob'] },
@@ -224,46 +214,6 @@ describe('DashboardDatasource', () => {
expect(result?.data[0].length).toBe(1);
});
- it('should respect feature toggle and not filter when disabled', async () => {
- // Temporarily disable the feature toggle for this test
- config.featureToggles.dashboardDsAdHocFiltering = false;
-
- const testFrame = createTestFrame([
- { name: 'name', type: FieldType.string, values: ['John', 'Jane', 'Bob'] },
- { name: 'age', type: FieldType.number, values: [25, 30, 35] },
- ]);
-
- const scene = new SceneFlexLayout({
- children: [
- new SceneFlexItem({
- body: new VizPanel({
- key: getVizPanelKeyForPanelId(1),
- $data: new SceneDataNode({
- data: {
- series: [testFrame],
- state: LoadingState.Done,
- timeRange: getDefaultTimeRange(),
- },
- }),
- }),
- }),
- ],
- });
-
- const ds = new DashboardDatasource({} as DataSourceInstanceSettings);
- const filters: AdHocVariableFilter[] = [{ key: 'name', operator: '=', value: 'John' }];
-
- const observable = ds.query(createQueryRequest(filters, scene));
-
- let result: DataQueryResponse | undefined;
- observable.subscribe({ next: (data) => (result = data) });
-
- // Should return unfiltered data since feature toggle is disabled
- expect(result?.data[0].fields[0].values).toEqual(['John', 'Jane', 'Bob']);
- expect(result?.data[0].fields[1].values).toEqual([25, 30, 35]);
- expect(result?.data[0].length).toBe(3);
- });
-
it('should respect per-panel adHocFiltersEnabled setting and not filter when disabled', async () => {
const testFrame = createTestFrame([
{ name: 'name', type: FieldType.string, values: ['John', 'Jane', 'Bob'] },
@@ -723,27 +673,8 @@ describe('DashboardDatasource', () => {
});
describe('getDrilldownsApplicability', () => {
- const originalToggleValue = config.featureToggles.dashboardDsAdHocFiltering;
const ds = new DashboardDatasource({} as DataSourceInstanceSettings);
- beforeEach(() => {
- config.featureToggles.dashboardDsAdHocFiltering = true;
- });
-
- afterEach(() => {
- config.featureToggles.dashboardDsAdHocFiltering = originalToggleValue;
- });
-
- it('should return empty array when feature toggle is disabled', async () => {
- config.featureToggles.dashboardDsAdHocFiltering = false;
-
- const result = await ds.getDrilldownsApplicability({
- filters: [{ key: 'name', operator: '=', value: 'test' }],
- });
-
- expect(result).toEqual([]);
- });
-
it('should mark supported operators as applicable', async () => {
const result = await ds.getDrilldownsApplicability({
filters: [
diff --git a/public/app/plugins/datasource/dashboard/datasource.ts b/public/app/plugins/datasource/dashboard/datasource.ts
index 9969c9afe7f..34a1781623f 100644
--- a/public/app/plugins/datasource/dashboard/datasource.ts
+++ b/public/app/plugins/datasource/dashboard/datasource.ts
@@ -20,7 +20,6 @@ import {
DataSourceGetDrilldownsApplicabilityOptions,
DrilldownsApplicability,
} from '@grafana/data';
-import { config } from '@grafana/runtime';
import { isSceneObject, SceneDataProvider, SceneDataTransformer, SceneObject } from '@grafana/scenes';
import {
activateSceneObjectAndParentTree,
@@ -140,11 +139,10 @@ export class DashboardDatasource extends DataSourceApi {
...field,
config: {
...field.config,
- // Enable AdHoc filtering for string and numeric fields only when feature toggle and per-panel setting are enabled
- filterable:
- config.featureToggles.dashboardDsAdHocFiltering && query.adHocFiltersEnabled
- ? field.type === FieldType.string || field.type === FieldType.number
- : field.config.filterable,
+ // Enable AdHoc filtering for string and numeric fields only when per-panel setting is enabled
+ filterable: query.adHocFiltersEnabled
+ ? field.type === FieldType.string || field.type === FieldType.number
+ : field.config.filterable,
},
state: {
...field.state,
@@ -153,7 +151,7 @@ export class DashboardDatasource extends DataSourceApi {
};
});
- if (!config.featureToggles.dashboardDsAdHocFiltering || !query.adHocFiltersEnabled || filters.length === 0) {
+ if (!query.adHocFiltersEnabled || filters.length === 0) {
return [...series, ...annotations];
}
@@ -247,11 +245,9 @@ export class DashboardDatasource extends DataSourceApi {
const field = frame.fields[fieldIndex];
- // Only support string and numeric fields when feature toggle is enabled
- if (config.featureToggles.dashboardDsAdHocFiltering) {
- if (field.type !== FieldType.string && field.type !== FieldType.number) {
- return null;
- }
+ // Only support string and numeric fields
+ if (field.type !== FieldType.string && field.type !== FieldType.number) {
+ return null;
}
// Map operator to matcher ID
@@ -357,10 +353,6 @@ export class DashboardDatasource extends DataSourceApi {
async getDrilldownsApplicability(
options?: DataSourceGetDrilldownsApplicabilityOptions
): Promise {
- if (!config.featureToggles.dashboardDsAdHocFiltering) {
- return [];
- }
-
// Check if any query has adhoc filters enabled
const hasAdHocFiltersEnabled = options?.queries?.some((query) => query.adHocFiltersEnabled);