mirror of
https://github.com/grafana/grafana.git
synced 2025-08-02 21:52:43 +08:00
Feature toggle to add filter and group by variables to all new dashboards by default (#85531)
* Add feature toggle * Add filters and group by variables by default to all new dashboards * Nits * Tests * Rename feature toggle to newDashboardWithFiltersAndGroupBy
This commit is contained in:
@ -177,4 +177,5 @@ export interface FeatureToggles {
|
||||
ssoSettingsSAML?: boolean;
|
||||
usePrometheusFrontendPackage?: boolean;
|
||||
oauthRequireSubClaim?: boolean;
|
||||
newDashboardWithFiltersAndGroupBy?: boolean;
|
||||
}
|
||||
|
@ -1189,6 +1189,15 @@ var (
|
||||
HideFromDocs: true,
|
||||
HideFromAdminPage: true,
|
||||
},
|
||||
{
|
||||
Name: "newDashboardWithFiltersAndGroupBy",
|
||||
Description: "Enables filters and group by variables on all new dashboards. Variables are added only if default data source supports filtering.",
|
||||
Stage: FeatureStageExperimental,
|
||||
Owner: grafanaDashboardsSquad,
|
||||
AllowSelfServe: false,
|
||||
HideFromDocs: true,
|
||||
HideFromAdminPage: true,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -158,3 +158,4 @@ scopeFilters,experimental,@grafana/dashboards-squad,false,false,false
|
||||
ssoSettingsSAML,experimental,@grafana/identity-access-team,false,false,false
|
||||
usePrometheusFrontendPackage,experimental,@grafana/observability-metrics,false,false,true
|
||||
oauthRequireSubClaim,experimental,@grafana/identity-access-team,false,false,false
|
||||
newDashboardWithFiltersAndGroupBy,experimental,@grafana/dashboards-squad,false,false,false
|
||||
|
|
@ -642,4 +642,8 @@ const (
|
||||
// FlagOauthRequireSubClaim
|
||||
// Require that sub claims is present in oauth tokens.
|
||||
FlagOauthRequireSubClaim = "oauthRequireSubClaim"
|
||||
|
||||
// FlagNewDashboardWithFiltersAndGroupBy
|
||||
// Enables filters and group by variables on all new dashboards. Variables are added only if default data source supports filtering.
|
||||
FlagNewDashboardWithFiltersAndGroupBy = "newDashboardWithFiltersAndGroupBy"
|
||||
)
|
||||
|
@ -2078,6 +2078,35 @@
|
||||
"hideFromAdminPage": true,
|
||||
"hideFromDocs": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "filtersOnByDefault",
|
||||
"resourceVersion": "1712149621080",
|
||||
"creationTimestamp": "2024-04-03T13:07:01Z",
|
||||
"deletionTimestamp": "2024-04-04T10:35:56Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Enables filters and group by variables on all new dashboards. Variables are added only if default data source supports filtering.",
|
||||
"stage": "experimental",
|
||||
"codeowner": "@grafana/dashboards-squad",
|
||||
"hideFromAdminPage": true,
|
||||
"hideFromDocs": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "newDashboardWithFiltersAndGroupBy",
|
||||
"resourceVersion": "1712226956055",
|
||||
"creationTimestamp": "2024-04-04T10:35:56Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Enables filters and group by variables on all new dashboards. Variables are added only if default data source supports filtering.",
|
||||
"stage": "experimental",
|
||||
"codeowner": "@grafana/dashboards-squad",
|
||||
"hideFromAdminPage": true,
|
||||
"hideFromDocs": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -84,7 +84,8 @@ export class DashboardScenePageStateManager extends StateManagerBase<DashboardSc
|
||||
try {
|
||||
switch (route) {
|
||||
case DashboardRoutes.New:
|
||||
rsp = buildNewDashboardSaveModel(urlFolderUid);
|
||||
rsp = await buildNewDashboardSaveModel(urlFolderUid);
|
||||
|
||||
break;
|
||||
case DashboardRoutes.Home:
|
||||
rsp = await getBackendSrv().get('/api/dashboards/home');
|
||||
|
@ -0,0 +1,76 @@
|
||||
import { DataSourceApi, PluginType, VariableSupportType } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { buildNewDashboardSaveModel } from './buildNewDashboardSaveModel';
|
||||
|
||||
const fakeDsMock: DataSourceApi = {
|
||||
name: 'fake-std',
|
||||
type: 'fake-std',
|
||||
getRef: () => ({ type: 'fake-std', uid: 'fake-std' }),
|
||||
query: () =>
|
||||
Promise.resolve({
|
||||
data: [],
|
||||
}),
|
||||
testDatasource: () => Promise.resolve({ status: 'success', message: 'abc' }),
|
||||
meta: {
|
||||
id: 'fake-std',
|
||||
type: PluginType.datasource,
|
||||
module: 'fake-std',
|
||||
baseUrl: '',
|
||||
name: 'fake-std',
|
||||
info: {
|
||||
author: { name: '' },
|
||||
description: '',
|
||||
links: [],
|
||||
logos: { large: '', small: '' },
|
||||
updated: '',
|
||||
version: '',
|
||||
screenshots: [],
|
||||
},
|
||||
},
|
||||
// Standard variable support
|
||||
variables: {
|
||||
getType: () => VariableSupportType.Standard,
|
||||
toDataQuery: (q) => ({ ...q, refId: 'FakeDataSource-refId' }),
|
||||
},
|
||||
getTagKeys: jest.fn(),
|
||||
id: 1,
|
||||
uid: 'fake-std',
|
||||
};
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
config: {
|
||||
featureToggles: {
|
||||
newDashboardWithFiltersAndGroupBy: false,
|
||||
},
|
||||
},
|
||||
getDataSourceSrv: () => ({
|
||||
get: (): Promise<DataSourceApi> => {
|
||||
return Promise.resolve(fakeDsMock);
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('buildNewDashboardSaveModel', () => {
|
||||
it('should not have template variables defined by default', async () => {
|
||||
const result = await buildNewDashboardSaveModel();
|
||||
expect(result.dashboard.templating).toBeUndefined();
|
||||
});
|
||||
|
||||
describe('when featureToggles.newDashboardWithFiltersAndGroupBy is true', () => {
|
||||
beforeAll(() => {
|
||||
config.featureToggles.newDashboardWithFiltersAndGroupBy = true;
|
||||
});
|
||||
afterAll(() => {
|
||||
config.featureToggles.newDashboardWithFiltersAndGroupBy = false;
|
||||
});
|
||||
|
||||
it('should add filter and group by variables if the datasource supports it and is set as default', async () => {
|
||||
const result = await buildNewDashboardSaveModel();
|
||||
expect(result.dashboard.templating?.list).toHaveLength(2);
|
||||
expect(result.dashboard.templating?.list?.[0].type).toBe('adhoc');
|
||||
expect(result.dashboard.templating?.list?.[1].type).toBe('groupby');
|
||||
});
|
||||
});
|
||||
});
|
@ -1,7 +1,37 @@
|
||||
import { defaultDashboard } from '@grafana/schema';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { VariableModel, defaultDashboard } from '@grafana/schema';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { DashboardDTO } from 'app/types';
|
||||
|
||||
export function buildNewDashboardSaveModel(urlFolderUid?: string): DashboardDTO {
|
||||
export async function buildNewDashboardSaveModel(urlFolderUid?: string): Promise<DashboardDTO> {
|
||||
let variablesList = defaultDashboard.templating?.list;
|
||||
|
||||
if (config.featureToggles.newDashboardWithFiltersAndGroupBy) {
|
||||
// Add filter and group by variables if the datasource supports it
|
||||
const defaultDs = await getDatasourceSrv().get();
|
||||
|
||||
if (defaultDs.getTagKeys) {
|
||||
const datasourceRef = {
|
||||
type: defaultDs.meta.id,
|
||||
uid: defaultDs.uid,
|
||||
};
|
||||
|
||||
const fitlerVariable: VariableModel = {
|
||||
datasource: datasourceRef,
|
||||
name: 'Filter',
|
||||
type: 'adhoc',
|
||||
};
|
||||
|
||||
const groupByVariable: VariableModel = {
|
||||
datasource: datasourceRef,
|
||||
name: 'Group by',
|
||||
type: 'groupby',
|
||||
};
|
||||
|
||||
variablesList = (variablesList || []).concat([fitlerVariable, groupByVariable]);
|
||||
}
|
||||
}
|
||||
|
||||
const data: DashboardDTO = {
|
||||
meta: {
|
||||
canStar: false,
|
||||
@ -18,6 +48,12 @@ export function buildNewDashboardSaveModel(urlFolderUid?: string): DashboardDTO
|
||||
},
|
||||
};
|
||||
|
||||
if (variablesList) {
|
||||
data.dashboard.templating = {
|
||||
list: variablesList,
|
||||
};
|
||||
}
|
||||
|
||||
if (urlFolderUid) {
|
||||
data.meta.folderUid = urlFolderUid;
|
||||
}
|
||||
|
@ -177,8 +177,8 @@ describe('transformSaveModelToScene', () => {
|
||||
});
|
||||
|
||||
describe('When creating a new dashboard', () => {
|
||||
it('should initialize the DashboardScene in edit mode and dirty', () => {
|
||||
const rsp = buildNewDashboardSaveModel();
|
||||
it('should initialize the DashboardScene in edit mode and dirty', async () => {
|
||||
const rsp = await buildNewDashboardSaveModel();
|
||||
const scene = transformSaveModelToScene(rsp);
|
||||
expect(scene.state.isEditing).toBe(undefined);
|
||||
expect(scene.state.isDirty).toBe(false);
|
||||
|
@ -120,7 +120,7 @@ async function fetchDashboard(
|
||||
if (args.urlFolderUid) {
|
||||
await dispatch(getFolderByUid(args.urlFolderUid));
|
||||
}
|
||||
return buildNewDashboardSaveModel(args.urlFolderUid);
|
||||
return await buildNewDashboardSaveModel(args.urlFolderUid);
|
||||
}
|
||||
case DashboardRoutes.Path: {
|
||||
const path = args.urlSlug ?? '';
|
||||
|
@ -85,7 +85,7 @@ export async function setDashboardInLocalStorage(options: AddPanelToDashboardOpt
|
||||
throw AddToDashboardError.FETCH_DASHBOARD;
|
||||
}
|
||||
} else {
|
||||
dto = buildNewDashboardSaveModel();
|
||||
dto = await buildNewDashboardSaveModel();
|
||||
}
|
||||
|
||||
dto.dashboard.panels = [panel, ...(dto.dashboard.panels ?? [])];
|
||||
|
Reference in New Issue
Block a user