mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06: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:
parent
4e60f44d98
commit
32b6ef9d15
@ -177,4 +177,5 @@ export interface FeatureToggles {
|
|||||||
ssoSettingsSAML?: boolean;
|
ssoSettingsSAML?: boolean;
|
||||||
usePrometheusFrontendPackage?: boolean;
|
usePrometheusFrontendPackage?: boolean;
|
||||||
oauthRequireSubClaim?: boolean;
|
oauthRequireSubClaim?: boolean;
|
||||||
|
newDashboardWithFiltersAndGroupBy?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -1189,6 +1189,15 @@ var (
|
|||||||
HideFromDocs: true,
|
HideFromDocs: true,
|
||||||
HideFromAdminPage: 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
|
ssoSettingsSAML,experimental,@grafana/identity-access-team,false,false,false
|
||||||
usePrometheusFrontendPackage,experimental,@grafana/observability-metrics,false,false,true
|
usePrometheusFrontendPackage,experimental,@grafana/observability-metrics,false,false,true
|
||||||
oauthRequireSubClaim,experimental,@grafana/identity-access-team,false,false,false
|
oauthRequireSubClaim,experimental,@grafana/identity-access-team,false,false,false
|
||||||
|
newDashboardWithFiltersAndGroupBy,experimental,@grafana/dashboards-squad,false,false,false
|
||||||
|
|
@ -642,4 +642,8 @@ const (
|
|||||||
// FlagOauthRequireSubClaim
|
// FlagOauthRequireSubClaim
|
||||||
// Require that sub claims is present in oauth tokens.
|
// Require that sub claims is present in oauth tokens.
|
||||||
FlagOauthRequireSubClaim = "oauthRequireSubClaim"
|
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,
|
"hideFromAdminPage": true,
|
||||||
"hideFromDocs": 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 {
|
try {
|
||||||
switch (route) {
|
switch (route) {
|
||||||
case DashboardRoutes.New:
|
case DashboardRoutes.New:
|
||||||
rsp = buildNewDashboardSaveModel(urlFolderUid);
|
rsp = await buildNewDashboardSaveModel(urlFolderUid);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DashboardRoutes.Home:
|
case DashboardRoutes.Home:
|
||||||
rsp = await getBackendSrv().get('/api/dashboards/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';
|
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 = {
|
const data: DashboardDTO = {
|
||||||
meta: {
|
meta: {
|
||||||
canStar: false,
|
canStar: false,
|
||||||
@ -18,6 +48,12 @@ export function buildNewDashboardSaveModel(urlFolderUid?: string): DashboardDTO
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (variablesList) {
|
||||||
|
data.dashboard.templating = {
|
||||||
|
list: variablesList,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (urlFolderUid) {
|
if (urlFolderUid) {
|
||||||
data.meta.folderUid = urlFolderUid;
|
data.meta.folderUid = urlFolderUid;
|
||||||
}
|
}
|
||||||
|
@ -177,8 +177,8 @@ describe('transformSaveModelToScene', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('When creating a new dashboard', () => {
|
describe('When creating a new dashboard', () => {
|
||||||
it('should initialize the DashboardScene in edit mode and dirty', () => {
|
it('should initialize the DashboardScene in edit mode and dirty', async () => {
|
||||||
const rsp = buildNewDashboardSaveModel();
|
const rsp = await buildNewDashboardSaveModel();
|
||||||
const scene = transformSaveModelToScene(rsp);
|
const scene = transformSaveModelToScene(rsp);
|
||||||
expect(scene.state.isEditing).toBe(undefined);
|
expect(scene.state.isEditing).toBe(undefined);
|
||||||
expect(scene.state.isDirty).toBe(false);
|
expect(scene.state.isDirty).toBe(false);
|
||||||
|
@ -120,7 +120,7 @@ async function fetchDashboard(
|
|||||||
if (args.urlFolderUid) {
|
if (args.urlFolderUid) {
|
||||||
await dispatch(getFolderByUid(args.urlFolderUid));
|
await dispatch(getFolderByUid(args.urlFolderUid));
|
||||||
}
|
}
|
||||||
return buildNewDashboardSaveModel(args.urlFolderUid);
|
return await buildNewDashboardSaveModel(args.urlFolderUid);
|
||||||
}
|
}
|
||||||
case DashboardRoutes.Path: {
|
case DashboardRoutes.Path: {
|
||||||
const path = args.urlSlug ?? '';
|
const path = args.urlSlug ?? '';
|
||||||
|
@ -85,7 +85,7 @@ export async function setDashboardInLocalStorage(options: AddPanelToDashboardOpt
|
|||||||
throw AddToDashboardError.FETCH_DASHBOARD;
|
throw AddToDashboardError.FETCH_DASHBOARD;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dto = buildNewDashboardSaveModel();
|
dto = await buildNewDashboardSaveModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
dto.dashboard.panels = [panel, ...(dto.dashboard.panels ?? [])];
|
dto.dashboard.panels = [panel, ...(dto.dashboard.panels ?? [])];
|
||||||
|
Loading…
Reference in New Issue
Block a user