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:
Dominik Prokop
2024-04-04 13:25:21 +02:00
committed by GitHub
parent 4e60f44d98
commit 32b6ef9d15
11 changed files with 164 additions and 7 deletions

View File

@ -177,4 +177,5 @@ export interface FeatureToggles {
ssoSettingsSAML?: boolean;
usePrometheusFrontendPackage?: boolean;
oauthRequireSubClaim?: boolean;
newDashboardWithFiltersAndGroupBy?: boolean;
}

View File

@ -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,
},
}
)

View File

@ -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

1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
158 ssoSettingsSAML experimental @grafana/identity-access-team false false false
159 usePrometheusFrontendPackage experimental @grafana/observability-metrics false false true
160 oauthRequireSubClaim experimental @grafana/identity-access-team false false false
161 newDashboardWithFiltersAndGroupBy experimental @grafana/dashboards-squad false false false

View File

@ -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"
)

View File

@ -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
}
}
]
}

View File

@ -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');

View File

@ -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');
});
});
});

View File

@ -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;
}

View File

@ -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);

View File

@ -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 ?? '';

View File

@ -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 ?? [])];