Chore: Add type info for grafana boot data (#45322)

Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
This commit is contained in:
kay delaney 2022-03-30 10:48:58 +01:00 committed by GitHub
parent 6889e39526
commit f1c3177e79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 142 additions and 65 deletions

View File

@ -200,7 +200,7 @@ exports[`no enzyme tests`] = {
"public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx:1262111696": [
[1, 17, 13, "RegExp match", "2409514259"]
],
"public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx:1044891955": [
"public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx:809006195": [
[1, 35, 13, "RegExp match", "2409514259"]
],
"public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx:1798654441": [

View File

@ -5,6 +5,7 @@ import { SystemDateFormatSettings } from '../datetime';
import { GrafanaTheme2 } from '../themes';
import { MapLayerOptions } from '../geo/layer';
import { FeatureToggles } from './featureToggles.gen';
import { NavLinkDTO, OrgRole } from '.';
/**
* Describes the build information that will be available via the Grafana configuration.
@ -85,10 +86,47 @@ export type OAuth =
*/
export type OAuthSettings = Partial<Record<OAuth, { name: string; icon?: string }>>;
/** Current user info included in bootData
*
* @internal
*/
export interface CurrentUserDTO {
isSignedIn: boolean;
id: number;
login: string;
email: string;
name: string;
lightTheme: boolean;
orgCount: number;
orgId: number;
orgName: string;
orgRole: OrgRole | '';
isGrafanaAdmin: boolean;
gravatarUrl: string;
timezone: string;
weekStart: string;
locale: string;
permissions?: Record<string, boolean>;
}
/** Contains essential user and config info
*
* @internal
*/
export interface BootData {
user: CurrentUserDTO;
settings: GrafanaConfig;
navTree: NavLinkDTO[];
themePaths: {
light: string;
dark: string;
};
}
/**
* Describes all the different Grafana configuration values available for an instance.
*
* @public
* @internal
*/
export interface GrafanaConfig {
datasources: { [str: string]: DataSourceInstanceSettings };
@ -98,7 +136,7 @@ export interface GrafanaConfig {
windowTitlePrefix: string;
buildInfo: BuildInfo;
newPanelTitle: string;
bootData: any;
bootData: BootData;
externalUserMngLinkUrl: string;
externalUserMngLinkName: string;
externalUserMngInfo: string;
@ -120,9 +158,9 @@ export interface GrafanaConfig {
verifyEmailEnabled: boolean;
oauth: OAuthSettings;
disableUserSignUp: boolean;
loginHint: any;
passwordHint: any;
loginError: any;
loginHint: string;
passwordHint: string;
loginError?: string;
navTree: any;
viewersCanEdit: boolean;
editorsCanAdmin: boolean;

View File

@ -36,7 +36,16 @@ export * from './live';
export * from './variables';
export * from './geometry';
export { isUnsignedPluginSignature } from './pluginSignature';
export { OAuth, OAuthSettings, GrafanaConfig, BuildInfo, LicenseInfo, PreloadPlugin } from './config';
export {
CurrentUserDTO,
BootData,
OAuth,
OAuthSettings,
GrafanaConfig,
BuildInfo,
LicenseInfo,
PreloadPlugin,
} from './config';
export { FeatureToggles } from './featureToggles.gen';
export * from './alerts';
export * from './slider';

View File

@ -1,21 +1,28 @@
import { ComponentType } from 'react';
export interface NavModelItem {
export interface NavLinkDTO {
id?: string;
text: string;
url?: string;
description?: string;
section?: NavSection;
subTitle?: string;
icon?: string;
img?: string;
id?: string;
active?: boolean;
hideFromTabs?: boolean;
hideFromMenu?: boolean;
divider?: boolean;
children?: NavModelItem[];
breadcrumbs?: NavModelBreadcrumb[];
url?: string;
target?: string;
sortWeight?: number;
divider?: boolean;
hideFromMenu?: boolean;
hideFromTabs?: boolean;
children?: NavLinkDTO[];
highlightText?: string;
}
export interface NavModelItem extends NavLinkDTO {
children?: NavModelItem[];
active?: boolean;
breadcrumbs?: NavModelBreadcrumb[];
parentItem?: NavModelItem;
section?: NavSection;
showOrgSwitcher?: boolean;
onClick?: () => void;
menuItemType?: NavMenuItemType;

View File

@ -1,5 +1,6 @@
import { merge } from 'lodash';
import {
BootData,
BuildInfo,
createTheme,
DataSourceInstanceSettings,
@ -28,9 +29,9 @@ export class GrafanaBootConfig implements GrafanaConfig {
appUrl = '';
appSubUrl = '';
windowTitlePrefix = '';
buildInfo: BuildInfo = {} as BuildInfo;
buildInfo: BuildInfo;
newPanelTitle = '';
bootData: any;
bootData: BootData;
externalUserMngLinkUrl = '';
externalUserMngLinkName = '';
externalUserMngInfo = '';
@ -54,9 +55,9 @@ export class GrafanaBootConfig implements GrafanaConfig {
verifyEmailEnabled = false;
oauth: OAuthSettings = {};
disableUserSignUp = false;
loginHint: any;
passwordHint: any;
loginError: any;
loginHint = '';
passwordHint = '';
loginError = undefined;
navTree: any;
viewersCanEdit = false;
editorsCanAdmin = false;
@ -117,6 +118,8 @@ export class GrafanaBootConfig implements GrafanaConfig {
const mode = options.bootData.user.lightTheme ? 'light' : 'dark';
this.theme2 = createTheme({ colors: { mode } });
this.theme = this.theme2.v1;
this.bootData = options.bootData;
this.buildInfo = options.buildInfo;
const defaults = {
datasources: {},

View File

@ -57,7 +57,7 @@ const (
type NavLink struct {
Id string `json:"id,omitempty"`
Text string `json:"text,omitempty"`
Text string `json:"text"`
Description string `json:"description,omitempty"`
Section string `json:"section,omitempty"`
SubTitle string `json:"subTitle,omitempty"`

View File

@ -1,46 +1,49 @@
import coreModule from 'app/angular/core_module';
import config from 'app/core/config';
import { find, isNumber } from 'lodash';
import { NavModel } from '@grafana/data';
import { NavModel, NavModelItem } from '@grafana/data';
interface Nav {
breadcrumbs: NavModelItem[];
node?: NavModelItem;
main?: NavModelItem;
}
export class NavModelSrv {
navItems: any;
navItems: NavModelItem[];
constructor() {
this.navItems = config.bootData.navTree;
}
getCfgNode() {
return find(this.navItems, { id: 'cfg' });
return this.navItems.find((navItem) => navItem.id === 'cfg');
}
getNav(...args: Array<string | number>) {
let children = this.navItems;
const nav = {
const nav: Nav = {
breadcrumbs: [],
} as any;
};
for (const id of args) {
// if its a number then it's the index to use for main
if (isNumber(id)) {
if (typeof id === 'number') {
nav.main = nav.breadcrumbs[id];
break;
}
const node: any = find(children, { id: id });
nav.breadcrumbs.push(node);
nav.node = node;
nav.main = node;
children = node.children;
const node = children.find((child) => child.id === id);
if (node) {
nav.breadcrumbs.push(node);
nav.node = node;
nav.main = node;
children = node.children ?? [];
}
}
if (nav.main.children) {
if (nav.main?.children) {
for (const item of nav.main.children) {
item.active = false;
if (item.url === nav.node.url) {
item.active = true;
}
item.active = item.url === nav.node?.url;
}
}

View File

@ -1,25 +1,30 @@
import config from '../../core/config';
import { extend } from 'lodash';
import { rangeUtil, WithAccessControlMetadata } from '@grafana/data';
import { OrgRole, rangeUtil, WithAccessControlMetadata } from '@grafana/data';
import { AccessControlAction, UserPermission } from 'app/types';
import { featureEnabled, getBackendSrv } from '@grafana/runtime';
import { CurrentUserInternal } from 'app/types/config';
export class User {
export class User implements CurrentUserInternal {
isSignedIn: boolean;
id: number;
isGrafanaAdmin: any;
isSignedIn: any;
orgRole: any;
login: string;
email: string;
name: string;
lightTheme: boolean;
orgCount: number;
orgId: number;
orgName: string;
login: string;
orgCount: number;
orgRole: OrgRole | '';
isGrafanaAdmin: boolean;
gravatarUrl: string;
timezone: string;
fiscalYearStartMonth: number;
weekStart: string;
locale: string;
helpFlags1: number;
lightTheme: boolean;
hasEditPermissionInFolders: boolean;
email?: string;
permissions?: UserPermission;
fiscalYearStartMonth: number;
constructor() {
this.id = 0;
@ -35,7 +40,12 @@ export class User {
this.helpFlags1 = 0;
this.lightTheme = false;
this.hasEditPermissionInFolders = false;
this.email = undefined;
this.email = '';
this.name = '';
this.locale = '';
this.weekStart = '';
this.gravatarUrl = '';
if (config.bootData.user) {
extend(this, config.bootData.user);
}
@ -55,7 +65,7 @@ export class ContextSrv {
constructor() {
if (!config.bootData) {
config.bootData = { user: {}, settings: {} };
config.bootData = { user: {}, settings: {} } as any;
}
this.user = new User();
@ -180,7 +190,7 @@ export { contextSrv };
export const setContextSrv = (override: ContextSrv) => {
if (process.env.NODE_ENV !== 'test') {
throw new Error('contextSrv can be only overriden in test environment');
throw new Error('contextSrv can be only overridden in test environment');
}
contextSrv = override;
};

View File

@ -53,7 +53,7 @@ describe('ShareEmbed', () => {
user: {
orgId: 1,
},
};
} as any;
});
afterAll(() => {

View File

@ -110,7 +110,7 @@ describe('ShareModal', () => {
user: {
orgId: 1,
},
};
} as any;
ctx.mount({
panel: new PanelModel({ id: 22, options: {}, fieldConfig: { defaults: {}, overrides: [] } }),
});
@ -202,7 +202,7 @@ describe('when default_home_dashboard_path is set in the grafana config', () =>
user: {
orgId: 1,
},
};
} as any;
});
afterAll(() => {

View File

@ -36,7 +36,7 @@ describe('buildParams', () => {
to: 2000,
raw: { from: 'now-6h', to: 'now' },
} as unknown as TimeRange;
const orgId = '2';
const orgId = 2;
const result = buildParams({ useCurrentTimeRange, selectedTheme, panel, search, range, orgId });
expect(result.toString()).toEqual(expected);

View File

@ -9,7 +9,7 @@ export interface BuildParamsArgs {
panel?: PanelModel;
search?: string;
range?: TimeRange;
orgId?: string;
orgId?: number;
}
export function buildParams({
@ -24,7 +24,7 @@ export function buildParams({
searchParams.set('from', String(range.from.valueOf()));
searchParams.set('to', String(range.to.valueOf()));
searchParams.set('orgId', orgId);
searchParams.set('orgId', String(orgId));
if (!useCurrentTimeRange) {
searchParams.delete('from');

View File

@ -44,7 +44,7 @@ describe('grafanaGraph', () => {
user: {
lightTheme: false,
},
};
} as any;
Object.assign(GraphCtrl.prototype, {
...MetricsPanelCtrl.prototype,
...PanelCtrl.prototype,

View File

@ -1,12 +1,10 @@
/**
* UserPermission is a map storing permissions in a form of
* {
* action: { scope: scope }
* action: true;
* }
*/
export type UserPermission = {
[key: string]: { [key: string]: string };
};
export type UserPermission = Record<string, boolean>;
// Permission actions
export enum AccessControlAction {

View File

@ -0,0 +1,9 @@
import { CurrentUserDTO } from '@grafana/data';
/**
* Extends `CurrentUserDTO` with some properties meant only for internal use.
*/
export interface CurrentUserInternal extends CurrentUserDTO {
helpFlags1: number;
hasEditPermissionInFolders: boolean;
}