Preferences: Use dashboardUID to set the home dashboard (#51919)

This commit is contained in:
Ivan Ortega Alba
2022-07-22 10:44:22 +02:00
committed by GitHub
parent c7f8c2a7e1
commit 2ec01c8d08
8 changed files with 86 additions and 50 deletions
+2 -1
View File
@@ -3144,7 +3144,8 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"] [0, 0, 0, "Unexpected any. Specify a different type.", "0"]
], ],
"public/app/core/components/SharedPreferences/SharedPreferences.tsx:5381": [ "public/app/core/components/SharedPreferences/SharedPreferences.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"] [0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"]
], ],
"public/app/core/components/TagFilter/TagBadge.tsx:5381": [ "public/app/core/components/TagFilter/TagBadge.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
@@ -25,20 +25,32 @@ jest.mock('@grafana/runtime', () => {
jest.mock('app/core/services/backend_srv', () => { jest.mock('app/core/services/backend_srv', () => {
return { return {
backendSrv: { backendSrv: {
getDashboardByUid: jest.fn().mockResolvedValue({
dashboard: {
id: 2,
title: 'My Dashboard',
uid: 'myDash',
templating: {
list: [],
},
panels: [],
},
meta: {},
}),
search: jest.fn().mockResolvedValue([ search: jest.fn().mockResolvedValue([
{ {
id: 2, id: 2,
title: 'My Dashboard', title: 'My Dashboard',
tags: [], tags: [],
type: '', type: '',
uid: '', uid: 'myDash',
uri: '', uri: '',
url: '', url: '',
folderId: 0, folderId: 0,
folderTitle: '', folderTitle: '',
folderUid: '', folderUid: '',
folderUrl: '', folderUrl: '',
isStarred: false, isStarred: true,
slug: '', slug: '',
items: [], items: [],
}, },
@@ -47,14 +59,14 @@ jest.mock('app/core/services/backend_srv', () => {
title: 'Another Dashboard', title: 'Another Dashboard',
tags: [], tags: [],
type: '', type: '',
uid: '', uid: 'anotherDash',
uri: '', uri: '',
url: '', url: '',
folderId: 0, folderId: 0,
folderTitle: '', folderTitle: '',
folderUid: '', folderUid: '',
folderUrl: '', folderUrl: '',
isStarred: false, isStarred: true,
slug: '', slug: '',
items: [], items: [],
}, },
@@ -67,7 +79,7 @@ const mockPreferences: UserPreferencesDTO = {
timezone: 'browser', timezone: 'browser',
weekStart: 'monday', weekStart: 'monday',
theme: 'light', theme: 'light',
homeDashboardId: 2, homeDashboardUID: 'myDash',
queryHistory: { queryHistory: {
homeTab: '', homeTab: '',
}, },
@@ -159,7 +171,7 @@ describe('SharedPreferences', () => {
timezone: 'Australia/Sydney', timezone: 'Australia/Sydney',
weekStart: 'saturday', weekStart: 'saturday',
theme: 'dark', theme: 'dark',
homeDashboardId: 3, homeDashboardUID: 'anotherDash',
queryHistory: { queryHistory: {
homeTab: '', homeTab: '',
}, },
@@ -181,7 +193,7 @@ describe('SharedPreferences', () => {
timezone: 'browser', timezone: 'browser',
weekStart: '', weekStart: '',
theme: '', theme: '',
homeDashboardId: 0, homeDashboardUID: undefined,
queryHistory: { queryHistory: {
homeTab: '', homeTab: '',
}, },
@@ -22,7 +22,7 @@ import {
} from '@grafana/ui'; } from '@grafana/ui';
import { PreferencesService } from 'app/core/services/PreferencesService'; import { PreferencesService } from 'app/core/services/PreferencesService';
import { backendSrv } from 'app/core/services/backend_srv'; import { backendSrv } from 'app/core/services/backend_srv';
import { DashboardSearchHit, DashboardSearchItemType } from 'app/features/search/types'; import { DashboardSearchItem, DashboardSearchItemType } from 'app/features/search/types';
import { UserPreferencesDTO } from '../../../types'; import { UserPreferencesDTO } from '../../../types';
@@ -32,7 +32,7 @@ export interface Props {
} }
export type State = UserPreferencesDTO & { export type State = UserPreferencesDTO & {
dashboards: DashboardSearchHit[]; dashboards: DashboardSearchItem[];
}; };
const themes: SelectableValue[] = [ const themes: SelectableValue[] = [
@@ -74,6 +74,22 @@ const languages: Array<SelectableValue<string>> = [
const i18nFlag = Boolean(config.featureToggles.internationalization); const i18nFlag = Boolean(config.featureToggles.internationalization);
const DEFAULT_DASHBOARD_HOME: DashboardSearchItem = {
title: 'Default',
tags: [],
type: '' as DashboardSearchItemType,
uid: undefined,
uri: '',
url: '',
folderId: 0,
folderTitle: '',
folderUid: '',
folderUrl: '',
isStarred: false,
slug: '',
items: [],
};
export class SharedPreferences extends PureComponent<Props, State> { export class SharedPreferences extends PureComponent<Props, State> {
service: PreferencesService; service: PreferencesService;
@@ -82,7 +98,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
this.service = new PreferencesService(props.resourceUri); this.service = new PreferencesService(props.resourceUri);
this.state = { this.state = {
homeDashboardId: 0, homeDashboardUID: DEFAULT_DASHBOARD_HOME.uid,
theme: '', theme: '',
timezone: '', timezone: '',
weekStart: '', weekStart: '',
@@ -94,45 +110,44 @@ export class SharedPreferences extends PureComponent<Props, State> {
async componentDidMount() { async componentDidMount() {
const prefs = await this.service.load(); const prefs = await this.service.load();
const dashboards = await backendSrv.search({ starred: true }); const dashboards = (await backendSrv.search({ starred: true })) as DashboardSearchItem[];
const defaultDashboardHit: DashboardSearchHit = {
id: 0,
title: 'Default',
tags: [],
type: '' as DashboardSearchItemType,
uid: '',
uri: '',
url: '',
folderId: 0,
folderTitle: '',
folderUid: '',
folderUrl: '',
isStarred: false,
slug: '',
items: [],
};
if (prefs.homeDashboardId > 0 && !dashboards.find((d) => d.id === prefs.homeDashboardId)) { if (prefs.homeDashboardUID && !dashboards.find((d) => d.uid === prefs.homeDashboardUID)) {
const missing = await backendSrv.search({ dashboardIds: [prefs.homeDashboardId] }); const missingDash = await backendSrv.getDashboardByUid(prefs.homeDashboardUID);
if (missing && missing.length > 0) {
dashboards.push(missing[0]); if (missingDash?.dashboard) {
dashboards.push({
title: missingDash.dashboard.title,
tags: [],
type: DashboardSearchItemType.DashDB,
uid: missingDash.dashboard.uid,
uri: '', // uri is not part of dashboard metadata
url: missingDash.meta.url || '',
folderId: missingDash.meta.folderId,
folderTitle: missingDash.meta.folderTitle,
folderUid: missingDash.meta.folderUid,
folderUrl: missingDash.meta.folderUrl,
isStarred: missingDash.meta.isStarred || false,
slug: missingDash.meta.slug,
items: [],
});
} }
} }
this.setState({ this.setState({
homeDashboardId: prefs.homeDashboardId, homeDashboardUID: prefs.homeDashboardUID,
theme: prefs.theme, theme: prefs.theme,
timezone: prefs.timezone, timezone: prefs.timezone,
weekStart: prefs.weekStart, weekStart: prefs.weekStart,
locale: prefs.locale, locale: prefs.locale,
dashboards: [defaultDashboardHit, ...dashboards], dashboards: [DEFAULT_DASHBOARD_HOME, ...dashboards],
queryHistory: prefs.queryHistory, queryHistory: prefs.queryHistory,
}); });
} }
onSubmitForm = async () => { onSubmitForm = async () => {
const { homeDashboardId, theme, timezone, weekStart, locale, queryHistory } = this.state; const { homeDashboardUID, theme, timezone, weekStart, locale, queryHistory } = this.state;
await this.service.update({ homeDashboardId, theme, timezone, weekStart, locale, queryHistory }); await this.service.update({ homeDashboardUID, theme, timezone, weekStart, locale, queryHistory });
window.location.reload(); window.location.reload();
}; };
@@ -151,15 +166,15 @@ export class SharedPreferences extends PureComponent<Props, State> {
this.setState({ weekStart: weekStart }); this.setState({ weekStart: weekStart });
}; };
onHomeDashboardChanged = (dashboardId: number) => { onHomeDashboardChanged = (dashboardUID: string) => {
this.setState({ homeDashboardId: dashboardId }); this.setState({ homeDashboardUID: dashboardUID });
}; };
onLocaleChanged = (locale: string) => { onLocaleChanged = (locale: string) => {
this.setState({ locale }); this.setState({ locale });
}; };
getFullDashName = (dashboard: SelectableValue<DashboardSearchHit>) => { getFullDashName = (dashboard: SelectableValue<DashboardSearchItem>) => {
if (typeof dashboard.folderTitle === 'undefined' || dashboard.folderTitle === '') { if (typeof dashboard.folderTitle === 'undefined' || dashboard.folderTitle === '') {
return dashboard.title; return dashboard.title;
} }
@@ -167,7 +182,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
}; };
render() { render() {
const { theme, timezone, weekStart, homeDashboardId, locale, dashboards } = this.state; const { theme, timezone, weekStart, homeDashboardUID, locale, dashboards } = this.state;
const { disabled } = this.props; const { disabled } = this.props;
const styles = getStyles(); const styles = getStyles();
@@ -209,11 +224,11 @@ export class SharedPreferences extends PureComponent<Props, State> {
data-testid="User preferences home dashboard drop down" data-testid="User preferences home dashboard drop down"
> >
<Select <Select
value={dashboards.find((dashboard) => dashboard.id === homeDashboardId)} value={dashboards.find((dashboard) => dashboard.uid === homeDashboardUID)}
getOptionValue={(i) => i.id} getOptionValue={(i) => i.uid}
getOptionLabel={this.getFullDashName} getOptionLabel={this.getFullDashName}
onChange={(dashboard: SelectableValue<DashboardSearchHit>) => onChange={(dashboard: SelectableValue<DashboardSearchItem>) =>
this.onHomeDashboardChanged(dashboard.id) this.onHomeDashboardChanged(dashboard.uid)
} }
options={dashboards} options={dashboards}
placeholder={t({ placeholder={t({
@@ -35,7 +35,9 @@ const setup = (propOverrides?: object) => {
jest.clearAllMocks(); jest.clearAllMocks();
// needed because SharedPreferences is rendered in the test // needed because SharedPreferences is rendered in the test
jest.spyOn(backendSrv, 'put'); jest.spyOn(backendSrv, 'put');
jest.spyOn(backendSrv, 'get').mockResolvedValue({ timezone: 'UTC', homeDashboardId: 0, theme: 'dark' }); jest
.spyOn(backendSrv, 'get')
.mockResolvedValue({ timezone: 'UTC', homeDashboardUID: 'home-dashboard', theme: 'dark' });
jest.spyOn(backendSrv, 'search').mockResolvedValue([]); jest.spyOn(backendSrv, 'search').mockResolvedValue([]);
const props: Props = { const props: Props = {
@@ -70,7 +72,7 @@ describe('Render', () => {
id: 1, id: 1,
}, },
preferences: { preferences: {
homeDashboardId: 1, homeDashboardUID: 'home-dashboard',
theme: 'Default', theme: 'Default',
timezone: 'Default', timezone: 'Default',
locale: '', locale: '',
@@ -100,7 +100,7 @@ async function getTestContext(overrides: Partial<Props> = {}) {
const putSpy = jest.spyOn(backendSrv, 'put'); const putSpy = jest.spyOn(backendSrv, 'put');
const getSpy = jest const getSpy = jest
.spyOn(backendSrv, 'get') .spyOn(backendSrv, 'get')
.mockResolvedValue({ timezone: 'UTC', homeDashboardId: 0, theme: 'dark' }); .mockResolvedValue({ timezone: 'UTC', homeDashboardUID: 'home-dashboard', theme: 'dark' });
const searchSpy = jest.spyOn(backendSrv, 'search').mockResolvedValue([]); const searchSpy = jest.spyOn(backendSrv, 'search').mockResolvedValue([]);
const props = { ...defaultProps, ...overrides }; const props = { ...defaultProps, ...overrides };
+5
View File
@@ -51,8 +51,13 @@ export interface DashboardSectionItem {
sortMetaName?: string; sortMetaName?: string;
} }
/**
* @deprecated - It uses dashboard ID which is depreacted in favor of dashboard UID. Please, use DashboardSearchItem instead.
*/
export interface DashboardSearchHit extends DashboardSectionItem, DashboardSection, WithAccessControlMetadata {} export interface DashboardSearchHit extends DashboardSectionItem, DashboardSection, WithAccessControlMetadata {}
export interface DashboardSearchItem extends Omit<DashboardSearchHit, 'id'> {}
export interface SearchAction extends Action { export interface SearchAction extends Action {
payload?: any; payload?: any;
} }
+2 -2
View File
@@ -106,7 +106,7 @@ describe('Render', () => {
team: getMockTeam(), team: getMockTeam(),
pageName: 'settings', pageName: 'settings',
preferences: { preferences: {
homeDashboardId: 1, homeDashboardUID: 'home-dashboard',
theme: 'Default', theme: 'Default',
timezone: 'Default', timezone: 'Default',
}, },
@@ -131,7 +131,7 @@ describe('when feature toggle editorsCanAdmin is turned on', () => {
team: getMockTeam(), team: getMockTeam(),
pageName: 'settings', pageName: 'settings',
preferences: { preferences: {
homeDashboardId: 1, homeDashboardUID: 'home-dashboard',
theme: 'Default', theme: 'Default',
timezone: 'Default', timezone: 'Default',
}, },
+2 -1
View File
@@ -4,7 +4,8 @@ export interface UserPreferencesDTO {
timezone: TimeZone; timezone: TimeZone;
weekStart: string; weekStart: string;
locale: string; locale: string;
homeDashboardId: number; // It is undefined when there is not dashboard assigned (default)
homeDashboardUID?: string;
theme: string; theme: string;
queryHistory: { queryHistory: {
homeTab: '' | 'query' | 'starred'; homeTab: '' | 'query' | 'starred';