mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
schema: Use generated dashboard model in frontend (#55769)
Co-authored-by: Ivan Ortega <ivanortegaalba@gmail.com> Co-authored-by: Josh Hunt <joshhunt@users.noreply.github.com> Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com> Co-authored-by: polinaboneva <polina.boneva@grafana.com>
This commit is contained in:
parent
a553040441
commit
f86abf096d
@ -991,6 +991,11 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Do not use any type assertions.", "3"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "4"]
|
||||
],
|
||||
"packages/grafana-schema/src/veneer/dashboard.types.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"]
|
||||
],
|
||||
"packages/grafana-toolkit/src/cli/tasks/component.create.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
@ -3110,17 +3115,18 @@ exports[`better eslint`] = {
|
||||
],
|
||||
"public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.test.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
],
|
||||
"public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "3"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
|
||||
[0, 0, 0, "Do not use any type assertions.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "7"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "8"]
|
||||
],
|
||||
"public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
@ -3469,15 +3475,14 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "26"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "27"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "28"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "29"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "30"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "29"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "30"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "31"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "32"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "33"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "34"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "35"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "36"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "37"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "36"]
|
||||
],
|
||||
"public/app/features/dashboard/state/PanelModel.test.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
@ -3560,7 +3565,8 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/features/dashboard/state/reducers.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
],
|
||||
"public/app/features/dashboard/utils/getPanelMenu.test.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
|
@ -90,13 +90,7 @@
|
||||
"id": 4,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
"show": true
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 2,
|
||||
@ -233,13 +227,7 @@
|
||||
"id": 7,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
"show": true
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 2,
|
||||
@ -399,13 +387,7 @@
|
||||
"id": 6,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
"show": true
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 2,
|
||||
@ -537,13 +519,7 @@
|
||||
"id": 3,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
"show": true
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 2,
|
||||
@ -679,13 +655,7 @@
|
||||
"id": 5,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
"show": true
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 2,
|
||||
|
@ -21,6 +21,9 @@ lineage: seqs: [
|
||||
// Description of dashboard.
|
||||
description?: string
|
||||
|
||||
// Version of the current dashboard data
|
||||
revision: int64 | *-1 @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
gnetId?: string @grafanamaturity(NeedsExpertReview)
|
||||
// Tags associated with dashboard.
|
||||
tags?: [...string] @grafanamaturity(NeedsExpertReview)
|
||||
@ -69,15 +72,17 @@ lineage: seqs: [
|
||||
panels?: [...(#Panel | #RowPanel | #GraphPanel | #HeatmapPanel)] @grafanamaturity(NeedsExpertReview)
|
||||
// TODO docs
|
||||
templating?: {
|
||||
list: [...#VariableModel] @grafanamaturity(NeedsExpertReview)
|
||||
list?: [...#VariableModel] @grafanamaturity(NeedsExpertReview)
|
||||
}
|
||||
// TODO docs
|
||||
annotations?: {
|
||||
list: [...#AnnotationQuery] @grafanamaturity(NeedsExpertReview)
|
||||
list?: [...#AnnotationQuery] @grafanamaturity(NeedsExpertReview)
|
||||
}
|
||||
// TODO docs
|
||||
links?: [...#DashboardLink] @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
snapshot?: #Snapshot @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
///////////////////////////////////////
|
||||
// Definitions (referenced above) are declared below
|
||||
|
||||
@ -119,20 +124,42 @@ lineage: seqs: [
|
||||
// TODO what about what's in public/app/features/types.ts?
|
||||
// TODO there appear to be a lot of different kinds of [template] vars here? if so need a disjunction
|
||||
#VariableModel: {
|
||||
id: string | *"00000000-0000-0000-0000-000000000000"
|
||||
type: #VariableType
|
||||
name: string
|
||||
label?: string
|
||||
rootStateKey?: string
|
||||
global: bool | *false
|
||||
hide: #VariableHide
|
||||
skipUrlSync: bool | *false
|
||||
index: int32 | *-1
|
||||
state: #LoadingState
|
||||
error?: {...}
|
||||
description?: string
|
||||
// TODO: Move this into a separated QueryVariableModel type
|
||||
query?: string | {...}
|
||||
datasource?: #DataSourceRef
|
||||
...
|
||||
} @cuetsy(kind="interface") @grafanamaturity(NeedsExpertReview)
|
||||
} @cuetsy(kind="interface") @grafana(TSVeneer="type") @grafanamaturity(NeedsExpertReview)
|
||||
// TODO: There is a bug generating the names, they are always title case
|
||||
#VariableHide: 0 | 1 | 2 @cuetsy(kind="enum",memberNames="dontHide|hideLabel|hideVariable") @grafana(TSVeneer="type") @grafanamaturity(NeedsExpertReview)
|
||||
#LoadingState: "NotStarted" | "Loading" | "Streaming" | "Done" | "Error" @cuetsy(kind="enum") @grafanamaturity(NeedsExpertReview)
|
||||
// Ref to a DataSource instance
|
||||
#DataSourceRef: {
|
||||
// The plugin type-id
|
||||
type?: string @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// Specific datasource instance
|
||||
uid?: string @grafanamaturity(NeedsExpertReview)
|
||||
} @cuetsy(kind="interface") @grafanamaturity(NeedsExpertReview)
|
||||
// FROM public/app/features/dashboard/state/DashboardModels.ts - ish
|
||||
// TODO docs
|
||||
#DashboardLink: {
|
||||
title: string @grafanamaturity(NeedsExpertReview)
|
||||
type: #DashboardLinkType @grafanamaturity(NeedsExpertReview)
|
||||
icon?: string @grafanamaturity(NeedsExpertReview)
|
||||
tooltip?: string @grafanamaturity(NeedsExpertReview)
|
||||
url?: string @grafanamaturity(NeedsExpertReview)
|
||||
icon: string @grafanamaturity(NeedsExpertReview)
|
||||
tooltip: string @grafanamaturity(NeedsExpertReview)
|
||||
url: string @grafanamaturity(NeedsExpertReview)
|
||||
tags: [...string] @grafanamaturity(NeedsExpertReview)
|
||||
asDropdown: bool | *false @grafanamaturity(NeedsExpertReview)
|
||||
targetBlank: bool | *false @grafanamaturity(NeedsExpertReview)
|
||||
@ -273,6 +300,43 @@ lineage: seqs: [
|
||||
// type directly to achieve the same effect.
|
||||
#Target: {...} @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
#Snapshot: {
|
||||
|
||||
// TODO docs
|
||||
created: string @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
expires: string @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
external: bool @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
externalUrl: string @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
id: uint32 @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
key: string @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
name: string @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
orgId: uint32 @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
updated: string @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
url?: string @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
userId: uint32 @grafanamaturity(NeedsExpertReview)
|
||||
} @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// Dashboard panels. Panels are canonically defined inline
|
||||
// because they share a version timeline with the dashboard
|
||||
// schema; they do not evolve independently.
|
||||
@ -313,7 +377,10 @@ lineage: seqs: [
|
||||
repeat?: string @grafanamaturity(NeedsExpertReview)
|
||||
// Direction to repeat in if 'repeat' is set.
|
||||
// "h" for horizontal, "v" for vertical.
|
||||
// TODO this is probably optional
|
||||
repeatDirection: *"h" | "v" @grafanamaturity(NeedsExpertReview)
|
||||
// Id of the repeating panel.
|
||||
repeatPanelId?: int64 @grafanamaturity(NeedsExpertReview)
|
||||
|
||||
// TODO docs
|
||||
maxDataPoints?: number @grafanamaturity(NeedsExpertReview)
|
||||
@ -441,12 +508,18 @@ lineage: seqs: [
|
||||
// Support for legacy graph and heatmap panels.
|
||||
#GraphPanel: {
|
||||
type: "graph" @grafanamaturity(NeedsExpertReview)
|
||||
// @deprecated this is part of deprecated graph panel
|
||||
legend?: {
|
||||
show: bool | *true
|
||||
sort?: string
|
||||
sortDesc?: bool
|
||||
}
|
||||
...
|
||||
} @grafanamaturity(NeedsExpertReview)
|
||||
} @cuetsy(kind="interface") @grafanamaturity(NeedsExpertReview)
|
||||
#HeatmapPanel: {
|
||||
type: "heatmap" @grafanamaturity(NeedsExpertReview)
|
||||
...
|
||||
} @grafanamaturity(NeedsExpertReview)
|
||||
} @cuetsy(kind="interface") @grafanamaturity(NeedsExpertReview)
|
||||
},
|
||||
]
|
||||
},
|
||||
|
@ -144,10 +144,11 @@ export interface SystemVariable<TProps extends { toString: () => string }> exten
|
||||
current: { value: TProps };
|
||||
}
|
||||
|
||||
export interface BaseVariableModel extends VariableModel {
|
||||
export interface BaseVariableModel {
|
||||
name: string;
|
||||
label?: string;
|
||||
id: string;
|
||||
type: VariableType;
|
||||
rootStateKey: string | null;
|
||||
global: boolean;
|
||||
hide: VariableHide;
|
||||
|
@ -11,38 +11,41 @@
|
||||
export type {
|
||||
AnnotationTarget,
|
||||
AnnotationQuery,
|
||||
VariableModel,
|
||||
DataSourceRef,
|
||||
DashboardLink,
|
||||
DashboardLinkType,
|
||||
VariableType,
|
||||
FieldColorModeId,
|
||||
FieldColorSeriesByMode,
|
||||
FieldColor,
|
||||
GridPos,
|
||||
Threshold,
|
||||
ThresholdsMode,
|
||||
ThresholdsConfig,
|
||||
ValueMapping,
|
||||
MappingType,
|
||||
ValueMap,
|
||||
RangeMap,
|
||||
RegexMap,
|
||||
SpecialValueMap,
|
||||
SpecialValueMatch,
|
||||
ValueMappingResult,
|
||||
Transformation,
|
||||
DashboardCursorSync,
|
||||
MatcherConfig,
|
||||
RowPanel
|
||||
RowPanel,
|
||||
GraphPanel,
|
||||
HeatmapPanel
|
||||
} from './raw/dashboard/x/dashboard_types.gen';
|
||||
|
||||
// Raw generated default consts from dashboard kind.
|
||||
// Raw generated enums and default consts from dashboard kind.
|
||||
export {
|
||||
defaultAnnotationTarget,
|
||||
defaultAnnotationQuery,
|
||||
LoadingState,
|
||||
defaultDashboardLink,
|
||||
FieldColorModeId,
|
||||
defaultGridPos,
|
||||
ThresholdsMode,
|
||||
defaultThresholdsConfig,
|
||||
MappingType,
|
||||
SpecialValueMatch,
|
||||
DashboardCursorSync,
|
||||
defaultDashboardCursorSync,
|
||||
defaultMatcherConfig,
|
||||
defaultRowPanel
|
||||
@ -59,6 +62,7 @@ export {
|
||||
// TODO generate code such that tsc enforces type compatibility between raw and veneer decls
|
||||
export type {
|
||||
Dashboard,
|
||||
VariableModel,
|
||||
Panel,
|
||||
FieldConfigSource,
|
||||
FieldConfig
|
||||
@ -75,6 +79,8 @@ export type {
|
||||
// TODO generate code such that tsc enforces type compatibility between raw and veneer decls
|
||||
export {
|
||||
defaultDashboard,
|
||||
defaultVariableModel,
|
||||
VariableHide,
|
||||
defaultPanel,
|
||||
defaultFieldConfigSource,
|
||||
defaultFieldConfig
|
||||
@ -86,11 +92,11 @@ export type {
|
||||
PlaylistItem
|
||||
} from './raw/playlist/x/playlist_types.gen';
|
||||
|
||||
// Raw generated default consts from playlist kind.
|
||||
// Raw generated enums and default consts from playlist kind.
|
||||
export { defaultPlaylist } from './raw/playlist/x/playlist_types.gen';
|
||||
|
||||
// Raw generated types from Team kind.
|
||||
export type {
|
||||
Team,
|
||||
Permission
|
||||
} from './raw/team/x/team_types.gen';
|
||||
export type { Team } from './raw/team/x/team_types.gen';
|
||||
|
||||
// Raw generated enums and default consts from team kind.
|
||||
export { Permission } from './raw/team/x/team_types.gen';
|
||||
|
@ -75,26 +75,78 @@ export const defaultAnnotationQuery: Partial<AnnotationQuery> = {
|
||||
* TODO there appear to be a lot of different kinds of [template] vars here? if so need a disjunction
|
||||
*/
|
||||
export interface VariableModel {
|
||||
datasource?: DataSourceRef;
|
||||
description?: string;
|
||||
error?: Record<string, unknown>;
|
||||
global: boolean;
|
||||
hide: VariableHide;
|
||||
id: string;
|
||||
index: number;
|
||||
label?: string;
|
||||
name: string;
|
||||
/**
|
||||
* TODO: Move this into a separated QueryVariableModel type
|
||||
*/
|
||||
query?: (string | Record<string, unknown>);
|
||||
rootStateKey?: string;
|
||||
skipUrlSync: boolean;
|
||||
state: LoadingState;
|
||||
type: VariableType;
|
||||
}
|
||||
|
||||
export const defaultVariableModel: Partial<VariableModel> = {
|
||||
global: false,
|
||||
id: '00000000-0000-0000-0000-000000000000',
|
||||
index: -1,
|
||||
skipUrlSync: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: There is a bug generating the names, they are always title case
|
||||
*/
|
||||
export enum VariableHide {
|
||||
DontHide = 0,
|
||||
HideLabel = 1,
|
||||
HideVariable = 2,
|
||||
}
|
||||
|
||||
export enum LoadingState {
|
||||
Done = 'Done',
|
||||
Error = 'Error',
|
||||
Loading = 'Loading',
|
||||
NotStarted = 'NotStarted',
|
||||
Streaming = 'Streaming',
|
||||
}
|
||||
|
||||
/**
|
||||
* Ref to a DataSource instance
|
||||
*/
|
||||
export interface DataSourceRef {
|
||||
/**
|
||||
* The plugin type-id
|
||||
*/
|
||||
type?: string;
|
||||
/**
|
||||
* Specific datasource instance
|
||||
*/
|
||||
uid?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* FROM public/app/features/dashboard/state/DashboardModels.ts - ish
|
||||
* TODO docs
|
||||
*/
|
||||
export interface DashboardLink {
|
||||
asDropdown: boolean;
|
||||
icon?: string;
|
||||
icon: string;
|
||||
includeVars: boolean;
|
||||
keepTime: boolean;
|
||||
tags: Array<string>;
|
||||
targetBlank: boolean;
|
||||
title: string;
|
||||
tooltip?: string;
|
||||
tooltip: string;
|
||||
type: DashboardLinkType;
|
||||
url?: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export const defaultDashboardLink: Partial<DashboardLink> = {
|
||||
@ -380,8 +432,13 @@ export interface Panel {
|
||||
/**
|
||||
* Direction to repeat in if 'repeat' is set.
|
||||
* "h" for horizontal, "v" for vertical.
|
||||
* TODO this is probably optional
|
||||
*/
|
||||
repeatDirection: ('h' | 'v');
|
||||
/**
|
||||
* Id of the repeating panel.
|
||||
*/
|
||||
repeatPanelId?: number;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
@ -544,11 +601,7 @@ export interface RowPanel {
|
||||
};
|
||||
gridPos?: GridPos;
|
||||
id: number;
|
||||
panels: Array<(Panel | {
|
||||
type: 'graph';
|
||||
} | {
|
||||
type: 'heatmap';
|
||||
})>;
|
||||
panels: Array<(Panel | GraphPanel | HeatmapPanel)>;
|
||||
/**
|
||||
* Name of template variable to repeat for.
|
||||
*/
|
||||
@ -562,12 +615,31 @@ export const defaultRowPanel: Partial<RowPanel> = {
|
||||
panels: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* Support for legacy graph and heatmap panels.
|
||||
*/
|
||||
export interface GraphPanel {
|
||||
/**
|
||||
* @deprecated this is part of deprecated graph panel
|
||||
*/
|
||||
legend?: {
|
||||
show: boolean;
|
||||
sort?: string;
|
||||
sortDesc?: boolean;
|
||||
};
|
||||
type: 'graph';
|
||||
}
|
||||
|
||||
export interface HeatmapPanel {
|
||||
type: 'heatmap';
|
||||
}
|
||||
|
||||
export interface Dashboard {
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
annotations?: {
|
||||
list: Array<AnnotationQuery>;
|
||||
list?: Array<AnnotationQuery>;
|
||||
};
|
||||
/**
|
||||
* Description of dashboard.
|
||||
@ -596,21 +668,67 @@ export interface Dashboard {
|
||||
* TODO docs
|
||||
*/
|
||||
liveNow?: boolean;
|
||||
panels?: Array<(Panel | RowPanel | {
|
||||
type: 'graph';
|
||||
} | {
|
||||
type: 'heatmap';
|
||||
})>;
|
||||
panels?: Array<(Panel | RowPanel | GraphPanel | HeatmapPanel)>;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
refresh?: (string | false);
|
||||
/**
|
||||
* Version of the current dashboard data
|
||||
*/
|
||||
revision: number;
|
||||
/**
|
||||
* Version of the JSON schema, incremented each time a Grafana update brings
|
||||
* changes to said schema.
|
||||
* TODO this is the existing schema numbering system. It will be replaced by Thema's themaVersion
|
||||
*/
|
||||
schemaVersion: number;
|
||||
snapshot?: {
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
created: string;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
expires: string;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
external: boolean;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
externalUrl: string;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
id: number;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
orgId: number;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
updated: string;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
url?: string;
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
userId: number;
|
||||
};
|
||||
/**
|
||||
* Theme of dashboard.
|
||||
*/
|
||||
@ -623,7 +741,7 @@ export interface Dashboard {
|
||||
* TODO docs
|
||||
*/
|
||||
templating?: {
|
||||
list: Array<VariableModel>;
|
||||
list?: Array<VariableModel>;
|
||||
};
|
||||
/**
|
||||
* Time range for dashboard, e.g. last 6 hours, last 7 days, etc
|
||||
@ -685,6 +803,7 @@ export const defaultDashboard: Partial<Dashboard> = {
|
||||
graphTooltip: DashboardCursorSync.Off,
|
||||
links: [],
|
||||
panels: [],
|
||||
revision: -1,
|
||||
schemaVersion: 36,
|
||||
style: 'dark',
|
||||
tags: [],
|
||||
|
@ -1,23 +1,33 @@
|
||||
import * as raw from '../raw/dashboard/x/dashboard_types.gen';
|
||||
|
||||
export interface Dashboard extends raw.Dashboard {
|
||||
panels?: Array<
|
||||
| Panel
|
||||
| raw.RowPanel
|
||||
| {
|
||||
type: 'graph';
|
||||
}
|
||||
| {
|
||||
type: 'heatmap';
|
||||
}
|
||||
>;
|
||||
}
|
||||
|
||||
export interface Panel<TOptions = Record<string, unknown>, TCustomFieldConfig = Record<string, unknown>>
|
||||
extends raw.Panel {
|
||||
fieldConfig: FieldConfigSource<TCustomFieldConfig>;
|
||||
}
|
||||
|
||||
export enum VariableHide {
|
||||
dontHide,
|
||||
hideLabel,
|
||||
hideVariable,
|
||||
}
|
||||
|
||||
export interface VariableModel
|
||||
extends Omit<raw.VariableModel, 'rootStateKey' | 'error' | 'description' | 'hide' | 'datasource'> {
|
||||
// Overrides nullable properties because CUE doesn't support null values
|
||||
rootStateKey: string | null;
|
||||
error: any | null;
|
||||
description: string | null;
|
||||
hide: VariableHide;
|
||||
datasource: raw.DataSourceRef | null;
|
||||
}
|
||||
|
||||
export interface Dashboard extends Omit<raw.Dashboard, 'templating'> {
|
||||
panels?: Array<Panel | raw.RowPanel | raw.GraphPanel | raw.HeatmapPanel>;
|
||||
templating?: {
|
||||
list?: VariableModel[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface FieldConfig<TOptions = Record<string, unknown>> extends raw.FieldConfig {
|
||||
custom?: TOptions & Record<string, unknown>;
|
||||
}
|
||||
@ -26,7 +36,16 @@ export interface FieldConfigSource<TOptions = Record<string, unknown>> extends r
|
||||
defaults: FieldConfig<TOptions>;
|
||||
}
|
||||
|
||||
export const defaultDashboard: Partial<Dashboard> = raw.defaultDashboard;
|
||||
export const defaultDashboard = raw.defaultDashboard as Dashboard;
|
||||
export const defaultVariableModel = {
|
||||
...raw.defaultVariableModel,
|
||||
rootStateKey: null,
|
||||
error: null,
|
||||
description: null,
|
||||
hide: VariableHide.dontHide,
|
||||
state: raw.LoadingState.NotStarted,
|
||||
datasource: null,
|
||||
} as VariableModel;
|
||||
export const defaultPanel: Partial<Panel> = raw.defaultPanel;
|
||||
export const defaultFieldConfig: Partial<FieldConfig> = raw.defaultFieldConfig;
|
||||
export const defaultFieldConfigSource: Partial<FieldConfigSource> = raw.defaultFieldConfigSource;
|
||||
|
@ -79,7 +79,7 @@ func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(decl *DeclForGen, tf *
|
||||
sels := p.Selectors()
|
||||
switch len(sels) {
|
||||
case 0:
|
||||
name = strings.Title(lin.Name())
|
||||
name = comm.Name
|
||||
fallthrough
|
||||
case 1:
|
||||
// Only deal with subpaths that are definitions, for now
|
||||
@ -110,12 +110,24 @@ func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(decl *DeclForGen, tf *
|
||||
has = has || tgt.target == "type"
|
||||
}
|
||||
if has {
|
||||
custom = append(custom, *pair.T)
|
||||
// enums can't use 'export type'
|
||||
if pair.isEnum {
|
||||
customD = append(customD, *pair.T)
|
||||
} else {
|
||||
custom = append(custom, *pair.T)
|
||||
}
|
||||
|
||||
if pair.D != nil {
|
||||
customD = append(customD, *pair.D)
|
||||
}
|
||||
} else {
|
||||
raw = append(raw, *pair.T)
|
||||
// enums can't use 'export type'
|
||||
if pair.isEnum {
|
||||
rawD = append(rawD, *pair.T)
|
||||
} else {
|
||||
raw = append(raw, *pair.T)
|
||||
}
|
||||
|
||||
if pair.D != nil {
|
||||
rawD = append(rawD, *pair.D)
|
||||
}
|
||||
@ -146,7 +158,7 @@ func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(decl *DeclForGen, tf *
|
||||
}
|
||||
if len(rawD) > 0 {
|
||||
ret = append(ret, ast.ExportSet{
|
||||
CommentList: []ast.Comment{ts.CommentFromString(fmt.Sprintf("Raw generated default consts from %s kind.", lin.Name()), 80, false)},
|
||||
CommentList: []ast.Comment{ts.CommentFromString(fmt.Sprintf("Raw generated enums and default consts from %s kind.", lin.Name()), 80, false)},
|
||||
TypeOnly: false,
|
||||
Exports: rawD,
|
||||
From: ast.Str{Value: fmt.Sprintf("./raw/%s/%s/%s_types.gen", comm.MachineName, vpath, comm.MachineName)},
|
||||
@ -187,7 +199,8 @@ func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(decl *DeclForGen, tf *
|
||||
}
|
||||
|
||||
type declPair struct {
|
||||
T, D *ast.Ident
|
||||
T, D *ast.Ident
|
||||
isEnum bool
|
||||
}
|
||||
|
||||
type tsVeneerAttr struct {
|
||||
@ -206,6 +219,7 @@ func findDeclNode(name string, tf *ast.File) declPair {
|
||||
case ast.TypeDecl:
|
||||
if x.Name.Name == name {
|
||||
p.T = &x.Name
|
||||
_, p.isEnum = x.Type.(ast.EnumType)
|
||||
}
|
||||
case ast.VarDecl:
|
||||
if x.Names.Idents[0].Name == "default"+name {
|
||||
|
@ -83,6 +83,19 @@ const (
|
||||
HeatmapPanelTypeHeatmap HeatmapPanelType = "heatmap"
|
||||
)
|
||||
|
||||
// Defines values for LoadingState.
|
||||
const (
|
||||
LoadingStateDone LoadingState = "Done"
|
||||
|
||||
LoadingStateError LoadingState = "Error"
|
||||
|
||||
LoadingStateLoading LoadingState = "Loading"
|
||||
|
||||
LoadingStateNotStarted LoadingState = "NotStarted"
|
||||
|
||||
LoadingStateStreaming LoadingState = "Streaming"
|
||||
)
|
||||
|
||||
// Defines values for MappingType.
|
||||
const (
|
||||
MappingTypeRange MappingType = "range"
|
||||
@ -162,6 +175,37 @@ const (
|
||||
ValueMapTypeValue ValueMapType = "value"
|
||||
)
|
||||
|
||||
// Defines values for VariableHide.
|
||||
const (
|
||||
VariableHideN0 VariableHide = 0
|
||||
|
||||
VariableHideN1 VariableHide = 1
|
||||
|
||||
VariableHideN2 VariableHide = 2
|
||||
)
|
||||
|
||||
// Defines values for VariableModelHide.
|
||||
const (
|
||||
VariableModelHideN0 VariableModelHide = 0
|
||||
|
||||
VariableModelHideN1 VariableModelHide = 1
|
||||
|
||||
VariableModelHideN2 VariableModelHide = 2
|
||||
)
|
||||
|
||||
// Defines values for VariableModelState.
|
||||
const (
|
||||
VariableModelStateDone VariableModelState = "Done"
|
||||
|
||||
VariableModelStateError VariableModelState = "Error"
|
||||
|
||||
VariableModelStateLoading VariableModelState = "Loading"
|
||||
|
||||
VariableModelStateNotStarted VariableModelState = "NotStarted"
|
||||
|
||||
VariableModelStateStreaming VariableModelState = "Streaming"
|
||||
)
|
||||
|
||||
// Defines values for VariableModelType.
|
||||
const (
|
||||
VariableModelTypeAdhoc VariableModelType = "adhoc"
|
||||
@ -204,7 +248,7 @@ const (
|
||||
type Dashboard struct {
|
||||
Annotations *struct {
|
||||
// TODO docs
|
||||
List []AnnotationQuery `json:"list"`
|
||||
List *[]AnnotationQuery `json:"list,omitempty"`
|
||||
} `json:"annotations,omitempty"`
|
||||
|
||||
// Description of dashboard.
|
||||
@ -232,11 +276,17 @@ type Dashboard struct {
|
||||
// TODO docs
|
||||
Refresh *interface{} `json:"refresh,omitempty"`
|
||||
|
||||
// Version of the current dashboard data
|
||||
Revision int `json:"revision"`
|
||||
|
||||
// Version of the JSON schema, incremented each time a Grafana update brings
|
||||
// changes to said schema.
|
||||
// TODO this is the existing schema numbering system. It will be replaced by Thema's themaVersion
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
|
||||
// TODO docs
|
||||
Snapshot *Snapshot `json:"snapshot,omitempty"`
|
||||
|
||||
// Theme of dashboard.
|
||||
Style Style `json:"style"`
|
||||
|
||||
@ -244,7 +294,7 @@ type Dashboard struct {
|
||||
Tags *[]string `json:"tags,omitempty"`
|
||||
Templating *struct {
|
||||
// TODO docs
|
||||
List []VariableModel `json:"list"`
|
||||
List *[]VariableModel `json:"list,omitempty"`
|
||||
} `json:"templating,omitempty"`
|
||||
|
||||
// Time range for dashboard, e.g. last 6 hours, last 7 days, etc
|
||||
@ -346,20 +396,29 @@ type DashboardCursorSync int
|
||||
// TODO docs
|
||||
type DashboardLink struct {
|
||||
AsDropdown bool `json:"asDropdown"`
|
||||
Icon *string `json:"icon,omitempty"`
|
||||
Icon string `json:"icon"`
|
||||
IncludeVars bool `json:"includeVars"`
|
||||
KeepTime bool `json:"keepTime"`
|
||||
Tags []string `json:"tags"`
|
||||
TargetBlank bool `json:"targetBlank"`
|
||||
Title string `json:"title"`
|
||||
Tooltip *string `json:"tooltip,omitempty"`
|
||||
Tooltip string `json:"tooltip"`
|
||||
Type DashboardLinkType `json:"type"`
|
||||
Url *string `json:"url,omitempty"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
// DashboardLinkType defines model for DashboardLink.Type.
|
||||
type DashboardLinkType string
|
||||
|
||||
// Ref to a DataSource instance
|
||||
type DataSourceRef struct {
|
||||
// The plugin type-id
|
||||
Type *string `json:"type,omitempty"`
|
||||
|
||||
// Specific datasource instance
|
||||
Uid *string `json:"uid,omitempty"`
|
||||
}
|
||||
|
||||
// DynamicConfigValue defines model for dashboard.DynamicConfigValue.
|
||||
type DynamicConfigValue struct {
|
||||
Id string `json:"id"`
|
||||
@ -498,13 +557,18 @@ type FieldConfigSource struct {
|
||||
} `json:"overrides"`
|
||||
}
|
||||
|
||||
// GraphPanel defines model for dashboard.GraphPanel.
|
||||
// Support for legacy graph and heatmap panels.
|
||||
type GraphPanel struct {
|
||||
// Support for legacy graph and heatmap panels.
|
||||
// @deprecated this is part of deprecated graph panel
|
||||
Legend *struct {
|
||||
Show bool `json:"show"`
|
||||
Sort *string `json:"sort,omitempty"`
|
||||
SortDesc *bool `json:"sortDesc,omitempty"`
|
||||
} `json:"legend,omitempty"`
|
||||
Type GraphPanelType `json:"type"`
|
||||
}
|
||||
|
||||
// Support for legacy graph and heatmap panels.
|
||||
// GraphPanelType defines model for GraphPanel.Type.
|
||||
type GraphPanelType string
|
||||
|
||||
// GridPos defines model for dashboard.GridPos.
|
||||
@ -533,6 +597,9 @@ type HeatmapPanel struct {
|
||||
// HeatmapPanelType defines model for HeatmapPanel.Type.
|
||||
type HeatmapPanelType string
|
||||
|
||||
// LoadingState defines model for dashboard.LoadingState.
|
||||
type LoadingState string
|
||||
|
||||
// TODO docs
|
||||
type MappingType string
|
||||
|
||||
@ -643,8 +710,12 @@ type Panel struct {
|
||||
|
||||
// Direction to repeat in if 'repeat' is set.
|
||||
// "h" for horizontal, "v" for vertical.
|
||||
// TODO this is probably optional
|
||||
RepeatDirection PanelRepeatDirection `json:"repeatDirection"`
|
||||
|
||||
// Id of the repeating panel.
|
||||
RepeatPanelId *int64 `json:"repeatPanelId,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
Tags *[]string `json:"tags,omitempty"`
|
||||
|
||||
@ -681,6 +752,7 @@ type Panel struct {
|
||||
|
||||
// Direction to repeat in if 'repeat' is set.
|
||||
// "h" for horizontal, "v" for vertical.
|
||||
// TODO this is probably optional
|
||||
type PanelRepeatDirection string
|
||||
|
||||
// TODO docs
|
||||
@ -741,6 +813,42 @@ type RowPanel struct {
|
||||
// RowPanelType defines model for RowPanel.Type.
|
||||
type RowPanelType string
|
||||
|
||||
// TODO docs
|
||||
type Snapshot struct {
|
||||
// TODO docs
|
||||
Created string `json:"created"`
|
||||
|
||||
// TODO docs
|
||||
Expires string `json:"expires"`
|
||||
|
||||
// TODO docs
|
||||
External bool `json:"external"`
|
||||
|
||||
// TODO docs
|
||||
ExternalUrl string `json:"externalUrl"`
|
||||
|
||||
// TODO docs
|
||||
Id int `json:"id"`
|
||||
|
||||
// TODO docs
|
||||
Key string `json:"key"`
|
||||
|
||||
// TODO docs
|
||||
Name string `json:"name"`
|
||||
|
||||
// TODO docs
|
||||
OrgId int `json:"orgId"`
|
||||
|
||||
// TODO docs
|
||||
Updated string `json:"updated"`
|
||||
|
||||
// TODO docs
|
||||
Url *string `json:"url,omitempty"`
|
||||
|
||||
// TODO docs
|
||||
UserId int `json:"userId"`
|
||||
}
|
||||
|
||||
// TODO docs
|
||||
type SpecialValueMap struct {
|
||||
Options struct {
|
||||
@ -842,16 +950,39 @@ type ValueMappingResult struct {
|
||||
Text *string `json:"text,omitempty"`
|
||||
}
|
||||
|
||||
// TODO: There is a bug generating the names, they are always title case
|
||||
type VariableHide int
|
||||
|
||||
// FROM: packages/grafana-data/src/types/templateVars.ts
|
||||
// TODO docs
|
||||
// TODO what about what's in public/app/features/types.ts?
|
||||
// TODO there appear to be a lot of different kinds of [template] vars here? if so need a disjunction
|
||||
type VariableModel struct {
|
||||
Label *string `json:"label,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Type VariableModelType `json:"type"`
|
||||
// Ref to a DataSource instance
|
||||
Datasource *DataSourceRef `json:"datasource,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Error *map[string]interface{} `json:"error,omitempty"`
|
||||
Global bool `json:"global"`
|
||||
Hide VariableModelHide `json:"hide"`
|
||||
Id string `json:"id"`
|
||||
Index int `json:"index"`
|
||||
Label *string `json:"label,omitempty"`
|
||||
Name string `json:"name"`
|
||||
|
||||
// TODO: Move this into a separated QueryVariableModel type
|
||||
Query *interface{} `json:"query,omitempty"`
|
||||
RootStateKey *string `json:"rootStateKey,omitempty"`
|
||||
SkipUrlSync bool `json:"skipUrlSync"`
|
||||
State VariableModelState `json:"state"`
|
||||
Type VariableModelType `json:"type"`
|
||||
}
|
||||
|
||||
// VariableModelHide defines model for VariableModel.Hide.
|
||||
type VariableModelHide int
|
||||
|
||||
// VariableModelState defines model for VariableModel.State.
|
||||
type VariableModelState string
|
||||
|
||||
// VariableModelType defines model for VariableModel.Type.
|
||||
type VariableModelType string
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { DashboardModel, PanelModel } from '../dashboard/state';
|
||||
import { PanelModel } from '../dashboard/state';
|
||||
import { createDashboardModelFixture, createPanelJSONFixture } from '../dashboard/state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { TestRuleResult, Props } from './TestRuleResult';
|
||||
|
||||
@ -18,7 +19,9 @@ jest.mock('@grafana/runtime', () => {
|
||||
|
||||
const props: Props = {
|
||||
panel: new PanelModel({ id: 1 }),
|
||||
dashboard: new DashboardModel({ panels: [{ id: 1 }] }),
|
||||
dashboard: createDashboardModelFixture({
|
||||
panels: [createPanelJSONFixture({ id: 1 })],
|
||||
}),
|
||||
};
|
||||
|
||||
describe('TestRuleResult', () => {
|
||||
|
@ -3,7 +3,8 @@ import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
import { logInfo } from '@grafana/runtime';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { LogMessages } from '../../Analytics';
|
||||
|
||||
@ -40,7 +41,7 @@ describe('Analytics', () => {
|
||||
const panel = new PanelModel({
|
||||
id: 123,
|
||||
});
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
id: 1,
|
||||
});
|
||||
render(<NewRuleFromPanelButton panel={panel} dashboard={dashboard} />);
|
||||
|
@ -8,6 +8,7 @@ import { Provider } from 'react-redux';
|
||||
import { byRole, byTestId } from 'testing-library-selector';
|
||||
|
||||
import { setBackendSrv } from '@grafana/runtime';
|
||||
import { defaultDashboard } from '@grafana/schema';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
|
||||
import { DashboardDTO } from '../../../../../types';
|
||||
@ -259,15 +260,12 @@ function mockDashboardSearchItem(searchItem: Partial<DashboardSearchItem>) {
|
||||
};
|
||||
}
|
||||
|
||||
function mockDashboardDto(dashboard: Partial<DashboardDTO['dashboard']>) {
|
||||
function mockDashboardDto(dashboard: Partial<DashboardDTO['dashboard']>): DashboardDTO {
|
||||
return {
|
||||
dashboard: {
|
||||
title: '',
|
||||
uid: '',
|
||||
templating: { list: [] },
|
||||
panels: [],
|
||||
...defaultDashboard,
|
||||
...dashboard,
|
||||
},
|
||||
} as DashboardDTO['dashboard'],
|
||||
meta: {},
|
||||
};
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { DashboardModel, PanelModel } from '../../state';
|
||||
import { PanelModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { AddPanelWidgetUnconnected as AddPanelWidget, Props } from './AddPanelWidget';
|
||||
|
||||
const getTestContext = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
dashboard: new DashboardModel({}),
|
||||
dashboard: createDashboardModelFixture(),
|
||||
panel: new PanelModel({}),
|
||||
addPanel: jest.fn() as any,
|
||||
};
|
||||
|
@ -10,13 +10,13 @@ import { getGrafanaContextMock } from '../../../../../test/mocks/getGrafanaConte
|
||||
import { setStarred } from '../../../../core/reducers/navBarTree';
|
||||
import { configureStore } from '../../../../store/configureStore';
|
||||
import { updateTimeZoneForSession } from '../../../profile/state/reducers';
|
||||
import { DashboardModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { DashNav } from './DashNav';
|
||||
|
||||
describe('Public dashboard title tag', () => {
|
||||
it('will be rendered when publicDashboardEnabled set to true in dashboard meta', async () => {
|
||||
let dashboard = new DashboardModel({}, { publicDashboardEnabled: false });
|
||||
let dashboard = createDashboardModelFixture({}, { publicDashboardEnabled: false });
|
||||
|
||||
const store = configureStore();
|
||||
const context = getGrafanaContextMock();
|
||||
|
@ -1,21 +1,22 @@
|
||||
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
|
||||
|
||||
import { setContextSrv } from '../../../../core/services/context_srv';
|
||||
import { DashboardModel } from '../../state/DashboardModel';
|
||||
import { PanelModel } from '../../state/PanelModel';
|
||||
import { createDashboardModelFixture, createPanelJSONFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { hasChanges, ignoreChanges } from './DashboardPrompt';
|
||||
|
||||
function getDefaultDashboardModel(): DashboardModel {
|
||||
return new DashboardModel({
|
||||
function getDefaultDashboardModel() {
|
||||
return createDashboardModelFixture({
|
||||
refresh: false,
|
||||
panels: [
|
||||
{
|
||||
createPanelJSONFixture({
|
||||
id: 1,
|
||||
type: 'graph',
|
||||
gridPos: { x: 0, y: 0, w: 24, h: 6 },
|
||||
legend: { sortDesc: false },
|
||||
},
|
||||
legend: { show: true, sortDesc: false }, // TODO legend is marked as a non-persisted field
|
||||
}),
|
||||
|
||||
{
|
||||
id: 2,
|
||||
type: 'row',
|
||||
@ -26,7 +27,7 @@ function getDefaultDashboardModel(): DashboardModel {
|
||||
{ id: 4, type: 'graph', gridPos: { x: 12, y: 6, w: 12, h: 2 } },
|
||||
],
|
||||
},
|
||||
{ id: 5, type: 'row', gridPos: { x: 0, y: 6, w: 1, h: 1 } },
|
||||
{ id: 5, type: 'row', gridPos: { x: 0, y: 6, w: 1, h: 1 }, collapsed: false, panels: [] },
|
||||
],
|
||||
});
|
||||
}
|
||||
@ -34,8 +35,8 @@ function getDefaultDashboardModel(): DashboardModel {
|
||||
function getTestContext() {
|
||||
const contextSrv: any = { isSignedIn: true, isEditor: true };
|
||||
setContextSrv(contextSrv);
|
||||
const dash: any = getDefaultDashboardModel();
|
||||
const original: any = dash.getSaveModelClone();
|
||||
const dash = getDefaultDashboardModel();
|
||||
const original = dash.getSaveModelClone();
|
||||
|
||||
return { dash, original, contextSrv };
|
||||
}
|
||||
@ -68,8 +69,8 @@ describe('DashboardPrompt', () => {
|
||||
|
||||
it('Should ignore panel legend changes', () => {
|
||||
const { original, dash } = getTestContext();
|
||||
dash.panels[0].legend.sortDesc = true;
|
||||
dash.panels[0].legend.sort = 'avg';
|
||||
dash.panels[0]!.legend!.sortDesc = true;
|
||||
dash.panels[0]!.legend!.sort = 'avg';
|
||||
expect(hasChanges(dash, original)).toBe(false);
|
||||
});
|
||||
|
||||
@ -90,47 +91,45 @@ describe('DashboardPrompt', () => {
|
||||
describe('when called without current dashboard', () => {
|
||||
it('then it should return true', () => {
|
||||
const { original } = getTestContext();
|
||||
expect(ignoreChanges(null as unknown as DashboardModel, original)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when called without meta in current dashboard', () => {
|
||||
it('then it should return true', () => {
|
||||
const { original, dash } = getTestContext();
|
||||
expect(ignoreChanges({ ...dash, meta: undefined }, original)).toBe(true);
|
||||
expect(ignoreChanges(null, original)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when called for a viewer without save permissions', () => {
|
||||
it('then it should return true', () => {
|
||||
const { original, dash, contextSrv } = getTestContext();
|
||||
const { contextSrv } = getTestContext();
|
||||
const dash = createDashboardModelFixture({}, { canSave: false });
|
||||
const original = dash.getSaveModelClone();
|
||||
contextSrv.isEditor = false;
|
||||
expect(ignoreChanges({ ...dash, meta: { canSave: false } }, original)).toBe(true);
|
||||
expect(ignoreChanges(dash, original)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when called for a viewer with save permissions', () => {
|
||||
it('then it should return undefined', () => {
|
||||
const { original, dash, contextSrv } = getTestContext();
|
||||
const { contextSrv } = getTestContext();
|
||||
const dash = createDashboardModelFixture({}, { canSave: true });
|
||||
const original = dash.getSaveModelClone();
|
||||
contextSrv.isEditor = false;
|
||||
expect(ignoreChanges({ ...dash, meta: { canSave: true } }, original)).toBe(undefined);
|
||||
expect(ignoreChanges(dash, original)).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when called for an user that is not signed in', () => {
|
||||
it('then it should return true', () => {
|
||||
const { original, dash, contextSrv } = getTestContext();
|
||||
const { contextSrv } = getTestContext();
|
||||
const dash = createDashboardModelFixture({}, { canSave: true });
|
||||
const original = dash.getSaveModelClone();
|
||||
contextSrv.isSignedIn = false;
|
||||
expect(ignoreChanges({ ...dash, meta: { canSave: true } }, original)).toBe(true);
|
||||
expect(ignoreChanges(dash, original)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when called with fromScript', () => {
|
||||
it('then it should return true', () => {
|
||||
const { original, dash } = getTestContext();
|
||||
expect(
|
||||
ignoreChanges({ ...dash, meta: { canSave: true, fromScript: true, fromFile: undefined } }, original)
|
||||
).toBe(true);
|
||||
const dash = createDashboardModelFixture({}, { canSave: true, fromScript: true, fromFile: undefined });
|
||||
const original = dash.getSaveModelClone();
|
||||
expect(ignoreChanges(dash, original)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -147,19 +146,17 @@ describe('DashboardPrompt', () => {
|
||||
|
||||
describe('when called with fromFile', () => {
|
||||
it('then it should return true', () => {
|
||||
const { original, dash } = getTestContext();
|
||||
expect(
|
||||
ignoreChanges({ ...dash, meta: { canSave: true, fromScript: undefined, fromFile: true } }, original)
|
||||
).toBe(true);
|
||||
const dash = createDashboardModelFixture({}, { canSave: true, fromScript: undefined, fromFile: true });
|
||||
const original = dash.getSaveModelClone();
|
||||
expect(ignoreChanges(dash, original)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when called with canSave but without fromScript and fromFile', () => {
|
||||
it('then it should return false', () => {
|
||||
const { original, dash } = getTestContext();
|
||||
expect(
|
||||
ignoreChanges({ ...dash, meta: { canSave: true, fromScript: undefined, fromFile: undefined } }, original)
|
||||
).toBe(undefined);
|
||||
const dash = createDashboardModelFixture({}, { canSave: true, fromScript: undefined, fromFile: undefined });
|
||||
const original = dash.getSaveModelClone();
|
||||
expect(ignoreChanges(dash, original)).toBe(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ import React, { useContext, useEffect, useState } from 'react';
|
||||
import { Prompt } from 'react-router-dom';
|
||||
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { Dashboard } from '@grafana/schema';
|
||||
import { ModalsContext } from '@grafana/ui';
|
||||
import { appEvents } from 'app/core/app_events';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
@ -140,7 +141,7 @@ function moveToBlockedLocationAfterReactStateUpdate(location?: H.Location | null
|
||||
/**
|
||||
* For some dashboards and users changes should be ignored *
|
||||
*/
|
||||
export function ignoreChanges(current: DashboardModel, original: object | null) {
|
||||
export function ignoreChanges(current: DashboardModel | null, original: object | null) {
|
||||
if (!original) {
|
||||
return true;
|
||||
}
|
||||
@ -150,7 +151,7 @@ export function ignoreChanges(current: DashboardModel, original: object | null)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!current || !current.meta) {
|
||||
if (!current) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -165,7 +166,7 @@ export function ignoreChanges(current: DashboardModel, original: object | null)
|
||||
/**
|
||||
* Remove stuff that should not count in diff
|
||||
*/
|
||||
function cleanDashboardFromIgnoredChanges(dashData: unknown) {
|
||||
function cleanDashboardFromIgnoredChanges(dashData: Dashboard) {
|
||||
// need to new up the domain model class to get access to expand / collapse row logic
|
||||
const model = new DashboardModel(dashData);
|
||||
|
||||
@ -193,13 +194,14 @@ function cleanDashboardFromIgnoredChanges(dashData: unknown) {
|
||||
return dash;
|
||||
}
|
||||
|
||||
// TODO: Adapt original to be Dashboard type instead
|
||||
export function hasChanges(current: DashboardModel, original: unknown) {
|
||||
if (current.hasUnsavedChanges()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const currentClean = cleanDashboardFromIgnoredChanges(current.getSaveModelClone());
|
||||
const originalClean = cleanDashboardFromIgnoredChanges(original);
|
||||
// TODO: Make getSaveModelClone return Dashboard type instead
|
||||
const currentClean = cleanDashboardFromIgnoredChanges(current.getSaveModelClone() as unknown as Dashboard);
|
||||
const originalClean = cleanDashboardFromIgnoredChanges(original as Dashboard);
|
||||
|
||||
const currentTimepicker = find((currentClean as any).nav, { type: 'timepicker' });
|
||||
const originalTimepicker = find((originalClean as any).nav, { type: 'timepicker' });
|
||||
|
@ -13,6 +13,7 @@ import { mockDataSource, MockDataSourceSrv } from 'app/features/alerting/unified
|
||||
|
||||
import { configureStore } from '../../../../store/configureStore';
|
||||
import { DashboardModel } from '../../state/DashboardModel';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { AnnotationsSettings } from './AnnotationsSettings';
|
||||
|
||||
@ -83,7 +84,7 @@ describe('AnnotationsSettings', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
dashboard = new DashboardModel({
|
||||
dashboard = createDashboardModelFixture({
|
||||
id: 74,
|
||||
version: 7,
|
||||
annotations: {
|
||||
@ -96,6 +97,7 @@ describe('AnnotationsSettings', () => {
|
||||
iconColor: 'rgba(0, 211, 255, 1)',
|
||||
name: 'Annotations & Alerts',
|
||||
type: 'dashboard',
|
||||
showIn: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -9,7 +9,7 @@ import { BackendSrv, setBackendSrv } from '@grafana/runtime';
|
||||
import { GrafanaContext } from 'app/core/context/GrafanaContext';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { DashboardModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { DashboardSettings } from './DashboardSettings';
|
||||
|
||||
@ -27,7 +27,7 @@ setBackendSrv({
|
||||
|
||||
describe('DashboardSettings', () => {
|
||||
it('pressing escape navigates away correctly', async () => {
|
||||
const dashboard = new DashboardModel(
|
||||
const dashboard = createDashboardModelFixture(
|
||||
{
|
||||
title: 'Foo',
|
||||
},
|
||||
|
@ -12,7 +12,7 @@ import { BackendSrv, setBackendSrv } from '@grafana/runtime';
|
||||
import { GrafanaContext } from 'app/core/context/GrafanaContext';
|
||||
|
||||
import { configureStore } from '../../../../store/configureStore';
|
||||
import { DashboardModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { GeneralSettingsUnconnected as GeneralSettings, Props } from './GeneralSettings';
|
||||
|
||||
@ -23,13 +23,16 @@ setBackendSrv({
|
||||
const setupTestContext = (options: Partial<Props>) => {
|
||||
const store = configureStore();
|
||||
const defaults: Props = {
|
||||
dashboard: new DashboardModel(
|
||||
dashboard: createDashboardModelFixture(
|
||||
{
|
||||
title: 'test dashboard title',
|
||||
description: 'test dashboard description',
|
||||
timepicker: {
|
||||
refresh_intervals: ['5s', '10s', '30s', '1m', '5m', '15m', '30m', '1h', '2h', '1d', '2d'],
|
||||
time_options: ['5m', '15m', '1h', '6h', '12h', '24h', '2d', '7d', '30d'],
|
||||
collapse: true,
|
||||
enable: true,
|
||||
hidden: false,
|
||||
},
|
||||
timezone: 'utc',
|
||||
},
|
||||
|
@ -12,6 +12,7 @@ import { GrafanaContext } from 'app/core/context/GrafanaContext';
|
||||
|
||||
import { configureStore } from '../../../../store/configureStore';
|
||||
import { DashboardModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { DashboardSettings } from './DashboardSettings';
|
||||
|
||||
@ -37,7 +38,7 @@ function setup(dashboard: DashboardModel) {
|
||||
}
|
||||
|
||||
function buildTestDashboard() {
|
||||
return new DashboardModel({
|
||||
return createDashboardModelFixture({
|
||||
links: [
|
||||
{
|
||||
asDropdown: false,
|
||||
@ -87,7 +88,7 @@ describe('LinksSettings', () => {
|
||||
};
|
||||
|
||||
test('it renders a header and cta if no links', () => {
|
||||
const linklessDashboard = new DashboardModel({ links: [] });
|
||||
const linklessDashboard = createDashboardModelFixture({ links: [] });
|
||||
setup(linklessDashboard);
|
||||
|
||||
expect(screen.getByRole('heading', { name: 'Links' })).toBeInTheDocument();
|
||||
|
@ -9,7 +9,7 @@ import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
|
||||
import { GrafanaContext } from 'app/core/context/GrafanaContext';
|
||||
|
||||
import { configureStore } from '../../../../store/configureStore';
|
||||
import { DashboardModel } from '../../state/DashboardModel';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
import { historySrv } from '../VersionHistory/HistorySrv';
|
||||
|
||||
import { VersionsSettings, VERSIONS_FETCH_LIMIT } from './VersionsSettings';
|
||||
@ -30,11 +30,11 @@ const queryByFullText = (text: string) =>
|
||||
|
||||
function setup() {
|
||||
const store = configureStore();
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
id: 74,
|
||||
version: 11,
|
||||
formatDate: jest.fn(() => 'date'),
|
||||
getRelativeTime: jest.fn(() => 'time ago'),
|
||||
// formatDate: jest.fn(() => 'date'),
|
||||
// getRelativeTime: jest.fn(() => 'time ago'),
|
||||
});
|
||||
|
||||
const sectionNav = {
|
||||
|
@ -16,7 +16,8 @@ import { selectors } from '@grafana/e2e-selectors';
|
||||
import { getAllOptionEditors, getAllStandardFieldConfigs } from 'app/core/components/OptionsUI/registry';
|
||||
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
|
||||
|
||||
import { DashboardModel, PanelModel } from '../../state';
|
||||
import { PanelModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { OptionsPaneOptions } from './OptionsPaneOptions';
|
||||
import { dataOverrideTooltipDescription, overrideRuleTooltipDescription } from './state/getOptionOverrides';
|
||||
@ -88,7 +89,7 @@ class OptionsPaneOptionsTestScenario {
|
||||
options: {},
|
||||
});
|
||||
|
||||
dashboard = new DashboardModel({});
|
||||
dashboard = createDashboardModelFixture();
|
||||
store = mockStore({
|
||||
dashboard: { panels: [] },
|
||||
templating: {
|
||||
|
@ -18,7 +18,8 @@ import {
|
||||
import { getTimeSrv, TimeSrv, setTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
|
||||
import { PanelQueryRunner } from '../../../query/state/PanelQueryRunner';
|
||||
import { DashboardModel, PanelModel } from '../../state';
|
||||
import { PanelModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { PanelEditorTableView, Props } from './PanelEditorTableView';
|
||||
|
||||
@ -53,14 +54,11 @@ function setupTestContext(options: Partial<Props> = {}) {
|
||||
getDisplayTitle: jest.fn(),
|
||||
runAllPanelQueries: jest.fn(),
|
||||
}),
|
||||
dashboard: new DashboardModel({
|
||||
dashboard: createDashboardModelFixture({
|
||||
id: 1,
|
||||
uid: 'super-unique-id',
|
||||
panelInitialized: jest.fn(),
|
||||
events: new EventBusSrv(),
|
||||
meta: {
|
||||
isPublic: false,
|
||||
},
|
||||
// panelInitialized: jest.fn(),
|
||||
// events: new EventBusSrv(),
|
||||
panels: [],
|
||||
}),
|
||||
plugin: {
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
|
||||
import { panelModelAndPluginReady, removePanel } from 'app/features/panel/state/reducers';
|
||||
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
|
||||
|
||||
import { thunkTester } from '../../../../../../test/core/thunk/thunkTester';
|
||||
import { DashboardModel, PanelModel } from '../../../state';
|
||||
import { PanelModel } from '../../../state';
|
||||
|
||||
import { exitPanelEditor, initPanelEditor, skipPanelUpdate } from './actions';
|
||||
import { closeEditor, initialState, PanelEditorState } from './reducers';
|
||||
@ -10,7 +11,7 @@ import { closeEditor, initialState, PanelEditorState } from './reducers';
|
||||
describe('panelEditor actions', () => {
|
||||
describe('initPanelEditor', () => {
|
||||
it('initPanelEditor should create edit panel model as clone', async () => {
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [{ id: 12, type: 'graph' }],
|
||||
});
|
||||
const sourcePanel = new PanelModel({ id: 12, type: 'graph' });
|
||||
@ -34,7 +35,7 @@ describe('panelEditor actions', () => {
|
||||
describe('panelEditorCleanUp', () => {
|
||||
it('should update source panel', async () => {
|
||||
const sourcePanel = new PanelModel({ id: 12, type: 'graph' });
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [{ id: 12, type: 'graph' }],
|
||||
});
|
||||
|
||||
@ -66,7 +67,7 @@ describe('panelEditor actions', () => {
|
||||
|
||||
it('should dispatch panelModelAndPluginReady if type changed', async () => {
|
||||
const sourcePanel = new PanelModel({ id: 12, type: 'graph' });
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [{ id: 12, type: 'graph' }],
|
||||
});
|
||||
|
||||
@ -105,7 +106,7 @@ describe('panelEditor actions', () => {
|
||||
customFieldConfigs: {},
|
||||
} as any;
|
||||
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [{ id: 12, type: 'graph' }],
|
||||
});
|
||||
|
||||
@ -138,7 +139,7 @@ describe('panelEditor actions', () => {
|
||||
sourcePanel.plugin = getPanelPlugin({});
|
||||
sourcePanel.plugin.angularPanelCtrl = undefined;
|
||||
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [{ id: 12, type: 'graph' }],
|
||||
});
|
||||
|
||||
@ -168,7 +169,7 @@ describe('panelEditor actions', () => {
|
||||
sourcePanel.plugin = getPanelPlugin({});
|
||||
sourcePanel.plugin.angularPanelCtrl = undefined;
|
||||
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [{ id: 12, type: 'graph' }],
|
||||
});
|
||||
|
||||
@ -207,7 +208,7 @@ describe('panelEditor actions', () => {
|
||||
sourcePanel.plugin = getPanelPlugin({});
|
||||
sourcePanel.plugin.angularPanelCtrl = {};
|
||||
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [{ id: 12, type: 'graph' }],
|
||||
});
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { Provider } from 'react-redux';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { DashboardModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { SaveDashboardDrawer } from './SaveDashboardDrawer';
|
||||
|
||||
@ -30,7 +31,7 @@ jest.mock('app/core/services/backend_srv', () => ({
|
||||
const store = configureStore();
|
||||
const mockPost = jest.fn();
|
||||
const buildMocks = () => ({
|
||||
dashboard: new DashboardModel({
|
||||
dashboard: createDashboardModelFixture({
|
||||
uid: 'mockDashboardUid',
|
||||
version: 1,
|
||||
}),
|
||||
|
@ -31,7 +31,6 @@ const getSaveAsDashboardClone = (dashboard: DashboardModel) => {
|
||||
});
|
||||
}
|
||||
|
||||
delete clone.autoUpdate;
|
||||
return clone;
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@ import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { SaveDashboardOptions } from '../types';
|
||||
|
||||
@ -123,14 +124,14 @@ describe('SaveDashboardAsForm', () => {
|
||||
it('renders saved message draft if it was filled before', () => {
|
||||
render(
|
||||
<SaveDashboardForm
|
||||
dashboard={new DashboardModel({})}
|
||||
dashboard={createDashboardModelFixture()}
|
||||
onCancel={() => {}}
|
||||
onSuccess={() => {}}
|
||||
onSubmit={async () => {
|
||||
return {};
|
||||
}}
|
||||
saveModel={{
|
||||
clone: new DashboardModel({}),
|
||||
clone: createDashboardModelFixture(),
|
||||
diff: {},
|
||||
diffCount: 0,
|
||||
hasChanges: true,
|
||||
|
@ -6,7 +6,8 @@ import { setEchoSrv } from '@grafana/runtime/src';
|
||||
import config from 'app/core/config';
|
||||
|
||||
import { Echo } from '../../../../core/services/echo/Echo';
|
||||
import { DashboardModel, PanelModel } from '../../state';
|
||||
import { PanelModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { ShareEmbed } from './ShareEmbed';
|
||||
|
||||
@ -68,7 +69,7 @@ describe('ShareEmbed', () => {
|
||||
});
|
||||
|
||||
it('generates the correct embed url for a dashboard', () => {
|
||||
const mockDashboard = new DashboardModel({
|
||||
const mockDashboard = createDashboardModelFixture({
|
||||
uid: 'mockDashboardUid',
|
||||
});
|
||||
const mockPanel = new PanelModel({
|
||||
@ -86,7 +87,7 @@ describe('ShareEmbed', () => {
|
||||
|
||||
it('generates the correct embed url for a dashboard set to the homepage in the grafana config', () => {
|
||||
mockLocationHref('http://dashboards.grafana.com/?orgId=1');
|
||||
const mockDashboard = new DashboardModel({
|
||||
const mockDashboard = createDashboardModelFixture({
|
||||
uid: 'mockDashboardUid',
|
||||
});
|
||||
const mockPanel = new PanelModel({
|
||||
@ -104,7 +105,7 @@ describe('ShareEmbed', () => {
|
||||
it('generates the correct embed url for a snapshot', () => {
|
||||
const mockSlug = 'mockSlug';
|
||||
mockLocationHref(`http://dashboards.grafana.com/dashboard/snapshot/${mockSlug}?orgId=1`);
|
||||
const mockDashboard = new DashboardModel({
|
||||
const mockDashboard = createDashboardModelFixture({
|
||||
uid: 'mockDashboardUid',
|
||||
});
|
||||
const mockPanel = new PanelModel({
|
||||
@ -122,7 +123,7 @@ describe('ShareEmbed', () => {
|
||||
it('generates the correct embed url for a scripted dashboard', () => {
|
||||
const mockSlug = 'scripted.js';
|
||||
mockLocationHref(`http://dashboards.grafana.com/dashboard/script/${mockSlug}?orgId=1`);
|
||||
const mockDashboard = new DashboardModel({
|
||||
const mockDashboard = createDashboardModelFixture({
|
||||
uid: 'mockDashboardUid',
|
||||
});
|
||||
const mockPanel = new PanelModel({
|
||||
|
@ -11,7 +11,8 @@ import { initTemplateSrv } from '../../../../../test/helpers/initTemplateSrv';
|
||||
import { Echo } from '../../../../core/services/echo/Echo';
|
||||
import { variableAdapters } from '../../../variables/adapters';
|
||||
import { createQueryVariableAdapter } from '../../../variables/query/adapter';
|
||||
import { DashboardModel, PanelModel } from '../../state';
|
||||
import { PanelModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { Props, ShareLink } from './ShareLink';
|
||||
|
||||
@ -78,13 +79,20 @@ describe('ShareModal', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
const defaultTimeRange = getDefaultTimeRange();
|
||||
setUTCTimeZone();
|
||||
mockLocationHref('http://server/#!/test');
|
||||
config.rendererAvailable = true;
|
||||
config.bootData.user.orgId = 1;
|
||||
props = {
|
||||
panel: new PanelModel({ id: 22, options: {}, fieldConfig: { defaults: {}, overrides: [] } }),
|
||||
dashboard: new DashboardModel({ time: getDefaultTimeRange(), id: 1 }),
|
||||
dashboard: createDashboardModelFixture({
|
||||
time: {
|
||||
from: defaultTimeRange.from.toISOString(),
|
||||
to: defaultTimeRange.to.toISOString(),
|
||||
},
|
||||
id: 1,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
@ -175,7 +183,7 @@ describe('when appUrl is set in the grafana config', () => {
|
||||
});
|
||||
|
||||
it('should render the correct link', async () => {
|
||||
const mockDashboard = new DashboardModel({
|
||||
const mockDashboard = createDashboardModelFixture({
|
||||
uid: 'mockDashboardUid',
|
||||
id: 1,
|
||||
});
|
||||
|
@ -8,11 +8,13 @@ import 'whatwg-fetch';
|
||||
import { BootData, DataQuery } from '@grafana/data/src';
|
||||
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
|
||||
import { setEchoSrv } from '@grafana/runtime/src';
|
||||
import { Panel } from '@grafana/schema';
|
||||
import config from 'app/core/config';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { Echo } from 'app/core/services/echo/Echo';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { ShareModal } from '../ShareModal';
|
||||
@ -71,7 +73,7 @@ beforeAll(() => {
|
||||
|
||||
beforeEach(() => {
|
||||
config.featureToggles.publicDashboards = true;
|
||||
mockDashboard = new DashboardModel({
|
||||
mockDashboard = createDashboardModelFixture({
|
||||
uid: 'mockDashboardUid',
|
||||
});
|
||||
|
||||
@ -203,8 +205,8 @@ describe('SharePublic - New config setup', () => {
|
||||
datasource: { type: 'notSupportedDatasource', uid: 'abc123' },
|
||||
} as DataQuery,
|
||||
] as DataQuery[],
|
||||
} as PanelModel;
|
||||
const dashboard = new DashboardModel({
|
||||
} as unknown as Panel;
|
||||
const dashboard = createDashboardModelFixture({
|
||||
id: 1,
|
||||
panels: [panelModel],
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { DashboardModel } from '../../state/DashboardModel';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { HistorySrv } from './HistorySrv';
|
||||
import { restore, versions } from './__mocks__/dashboardHistoryMocks';
|
||||
@ -25,8 +26,8 @@ describe('historySrv', () => {
|
||||
|
||||
let historySrv = new HistorySrv();
|
||||
|
||||
const dash = new DashboardModel({ uid: '_U4zObQMz' });
|
||||
const emptyDash = new DashboardModel({});
|
||||
const dash = createDashboardModelFixture({ uid: '_U4zObQMz' });
|
||||
const emptyDash = createDashboardModelFixture();
|
||||
const historyListOpts = { limit: 10, start: 0 };
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -2,7 +2,8 @@ import { render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { createEmptyQueryResponse } from '../../../explore/state/utils';
|
||||
import { DashboardModel, PanelModel } from '../../state';
|
||||
import { PanelModel } from '../../state';
|
||||
import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { PanelHeader } from './PanelHeader';
|
||||
|
||||
@ -16,7 +17,7 @@ let panelModel = new PanelModel({
|
||||
let panelData = createEmptyQueryResponse();
|
||||
|
||||
describe('Panel Header', () => {
|
||||
const dashboardModel = new DashboardModel({}, { publicDashboardAccessToken: 'abc123' });
|
||||
const dashboardModel = createDashboardModelFixture({}, { publicDashboardAccessToken: 'abc123' });
|
||||
it('will render header title but not render dropdown icon when dashboard is being viewed publicly', () => {
|
||||
window.history.pushState({}, 'Test Title', '/public-dashboards/abc123');
|
||||
|
||||
@ -29,7 +30,7 @@ describe('Panel Header', () => {
|
||||
});
|
||||
|
||||
it('will render header title and dropdown icon when dashboard is not being viewed publicly', () => {
|
||||
const dashboardModel = new DashboardModel({}, { publicDashboardAccessToken: '' });
|
||||
const dashboardModel = createDashboardModelFixture({}, { publicDashboardAccessToken: '' });
|
||||
window.history.pushState({}, 'Test Title', '/d/abc/123');
|
||||
|
||||
render(
|
||||
|
@ -64,6 +64,7 @@ describe('DashboardModel', () => {
|
||||
{ type: 'annotations', enable: true, annotations: [{ name: 'old' }] },
|
||||
],
|
||||
panels: [
|
||||
// @ts-expect-error
|
||||
{
|
||||
type: 'graph',
|
||||
legend: true,
|
||||
@ -87,6 +88,7 @@ describe('DashboardModel', () => {
|
||||
{
|
||||
type: 'singlestat',
|
||||
legend: true,
|
||||
// @ts-expect-error
|
||||
thresholds: '10,20,30',
|
||||
colors: ['#FF0000', 'green', 'orange'],
|
||||
aliasYAxis: { test: 2 },
|
||||
@ -95,6 +97,7 @@ describe('DashboardModel', () => {
|
||||
},
|
||||
{
|
||||
type: 'singlestat',
|
||||
// @ts-expect-error
|
||||
thresholds: '10,20,30',
|
||||
colors: ['#FF0000', 'green', 'orange'],
|
||||
gauge: {
|
||||
@ -106,6 +109,7 @@ describe('DashboardModel', () => {
|
||||
},
|
||||
{
|
||||
type: 'table',
|
||||
// @ts-expect-error
|
||||
legend: true,
|
||||
styles: [{ thresholds: ['10', '20', '30'] }, { thresholds: ['100', '200', '300'] }],
|
||||
targets: [{ refId: 'A' }, {}],
|
||||
@ -210,6 +214,7 @@ describe('DashboardModel', () => {
|
||||
panels: [
|
||||
{
|
||||
type: 'graph',
|
||||
// @ts-expect-error
|
||||
y_formats: ['kbyte', 'ms'],
|
||||
grid: {
|
||||
threshold1: 200,
|
||||
@ -468,6 +473,7 @@ describe('DashboardModel', () => {
|
||||
const model = {
|
||||
panels: [{ minSpan: 8 }],
|
||||
};
|
||||
// @ts-expect-error
|
||||
const dashboard = new DashboardModel(model);
|
||||
expect(dashboard.panels[0].maxPerRow).toBe(3);
|
||||
});
|
||||
@ -481,6 +487,7 @@ describe('DashboardModel', () => {
|
||||
panels: [
|
||||
{
|
||||
links: [
|
||||
// @ts-expect-error
|
||||
{
|
||||
url: 'http://mylink.com',
|
||||
keepTime: true,
|
||||
@ -488,23 +495,28 @@ describe('DashboardModel', () => {
|
||||
},
|
||||
{
|
||||
url: 'http://mylink.com?existingParam',
|
||||
// @ts-expect-error
|
||||
params: 'customParam',
|
||||
title: 'test',
|
||||
},
|
||||
// @ts-expect-error
|
||||
{
|
||||
url: 'http://mylink.com?existingParam',
|
||||
includeVars: true,
|
||||
title: 'test',
|
||||
},
|
||||
{
|
||||
// @ts-expect-error
|
||||
dashboard: 'my other dashboard',
|
||||
title: 'test',
|
||||
},
|
||||
{
|
||||
// @ts-expect-error
|
||||
dashUri: '',
|
||||
title: 'test',
|
||||
},
|
||||
{
|
||||
// @ts-expect-error
|
||||
type: 'dashboard',
|
||||
keepTime: true,
|
||||
},
|
||||
@ -536,6 +548,7 @@ describe('DashboardModel', () => {
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({
|
||||
panels: [
|
||||
// @ts-expect-error
|
||||
{
|
||||
//graph panel
|
||||
options: {
|
||||
@ -549,6 +562,7 @@ describe('DashboardModel', () => {
|
||||
],
|
||||
},
|
||||
},
|
||||
// @ts-expect-error
|
||||
{
|
||||
// panel with field options
|
||||
options: {
|
||||
@ -601,6 +615,7 @@ describe('DashboardModel', () => {
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({
|
||||
panels: [
|
||||
// @ts-expect-error
|
||||
{
|
||||
//graph panel
|
||||
options: {
|
||||
@ -611,6 +626,7 @@ describe('DashboardModel', () => {
|
||||
],
|
||||
},
|
||||
},
|
||||
// @ts-expect-error
|
||||
{
|
||||
// panel with field options
|
||||
options: {
|
||||
@ -649,6 +665,7 @@ describe('DashboardModel', () => {
|
||||
templating: {
|
||||
list: [
|
||||
{
|
||||
// @ts-expect-error
|
||||
multi: false,
|
||||
current: {
|
||||
value: ['value'],
|
||||
@ -656,6 +673,7 @@ describe('DashboardModel', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
// @ts-expect-error
|
||||
multi: true,
|
||||
current: {
|
||||
value: ['value'],
|
||||
@ -697,6 +715,7 @@ describe('DashboardModel', () => {
|
||||
list: [
|
||||
{
|
||||
type: 'query',
|
||||
// @ts-expect-error
|
||||
tags: ['Africa', 'America', 'Asia', 'Europe'],
|
||||
tagsQuery: 'select datacenter from x',
|
||||
tagValuesQuery: 'select value from x where datacenter = xyz',
|
||||
@ -704,6 +723,7 @@ describe('DashboardModel', () => {
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
// @ts-expect-error
|
||||
current: {
|
||||
tags: [
|
||||
{
|
||||
@ -729,6 +749,7 @@ describe('DashboardModel', () => {
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
// @ts-expect-error
|
||||
tags: [
|
||||
{ text: 'Africa', selected: false },
|
||||
{ text: 'America', selected: true },
|
||||
@ -783,10 +804,12 @@ describe('DashboardModel', () => {
|
||||
id: 2,
|
||||
type: 'text',
|
||||
title: 'Angular Text Panel',
|
||||
// @ts-expect-error
|
||||
content:
|
||||
'# Angular Text Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n\n',
|
||||
mode: 'markdown',
|
||||
},
|
||||
// @ts-expect-error
|
||||
{
|
||||
id: 3,
|
||||
type: 'text2',
|
||||
@ -797,6 +820,7 @@ describe('DashboardModel', () => {
|
||||
'# React Text Panel from scratch\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text',
|
||||
},
|
||||
},
|
||||
// @ts-expect-error
|
||||
{
|
||||
id: 4,
|
||||
type: 'text2',
|
||||
@ -867,24 +891,28 @@ describe('DashboardModel', () => {
|
||||
type: 'query',
|
||||
hide: VariableHide.dontHide,
|
||||
datasource: null,
|
||||
// @ts-expect-error
|
||||
allFormat: '',
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
hide: VariableHide.hideLabel,
|
||||
datasource: null,
|
||||
// @ts-expect-error
|
||||
allFormat: '',
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
hide: VariableHide.hideVariable,
|
||||
datasource: null,
|
||||
// @ts-expect-error
|
||||
allFormat: '',
|
||||
},
|
||||
{
|
||||
type: 'constant',
|
||||
hide: VariableHide.dontHide,
|
||||
query: 'default value',
|
||||
// @ts-expect-error
|
||||
current: { selected: true, text: 'A', value: 'B' },
|
||||
options: [{ selected: true, text: 'A', value: 'B' }],
|
||||
datasource: null,
|
||||
@ -894,6 +922,7 @@ describe('DashboardModel', () => {
|
||||
type: 'constant',
|
||||
hide: VariableHide.hideLabel,
|
||||
query: 'default value',
|
||||
// @ts-expect-error
|
||||
current: { selected: true, text: 'A', value: 'B' },
|
||||
options: [{ selected: true, text: 'A', value: 'B' }],
|
||||
datasource: null,
|
||||
@ -903,6 +932,7 @@ describe('DashboardModel', () => {
|
||||
type: 'constant',
|
||||
hide: VariableHide.hideVariable,
|
||||
query: 'default value',
|
||||
// @ts-expect-error
|
||||
current: { selected: true, text: 'A', value: 'B' },
|
||||
options: [{ selected: true, text: 'A', value: 'B' }],
|
||||
datasource: null,
|
||||
@ -967,79 +997,93 @@ describe('DashboardModel', () => {
|
||||
{
|
||||
type: 'query',
|
||||
name: 'variable_with_never_refresh_with_options',
|
||||
// @ts-expect-error
|
||||
options: [{ text: 'A', value: 'A' }],
|
||||
refresh: 0,
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
name: 'variable_with_never_refresh_without_options',
|
||||
// @ts-expect-error
|
||||
options: [],
|
||||
refresh: 0,
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
name: 'variable_with_dashboard_refresh_with_options',
|
||||
// @ts-expect-error
|
||||
options: [{ text: 'A', value: 'A' }],
|
||||
refresh: 1,
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
name: 'variable_with_dashboard_refresh_without_options',
|
||||
// @ts-expect-error
|
||||
options: [],
|
||||
refresh: 1,
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
name: 'variable_with_timerange_refresh_with_options',
|
||||
// @ts-expect-error
|
||||
options: [{ text: 'A', value: 'A' }],
|
||||
refresh: 2,
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
name: 'variable_with_timerange_refresh_without_options',
|
||||
// @ts-expect-error
|
||||
options: [],
|
||||
refresh: 2,
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
name: 'variable_with_no_refresh_with_options',
|
||||
// @ts-expect-error
|
||||
options: [{ text: 'A', value: 'A' }],
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
name: 'variable_with_no_refresh_without_options',
|
||||
// @ts-expect-error
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
name: 'variable_with_unknown_refresh_with_options',
|
||||
// @ts-expect-error
|
||||
options: [{ text: 'A', value: 'A' }],
|
||||
refresh: 2001,
|
||||
},
|
||||
{
|
||||
type: 'query',
|
||||
name: 'variable_with_unknown_refresh_without_options',
|
||||
// @ts-expect-error
|
||||
options: [],
|
||||
refresh: 2001,
|
||||
},
|
||||
{
|
||||
type: 'custom',
|
||||
name: 'custom',
|
||||
// @ts-expect-error
|
||||
options: [{ text: 'custom', value: 'custom' }],
|
||||
},
|
||||
{
|
||||
type: 'textbox',
|
||||
name: 'textbox',
|
||||
// @ts-expect-error
|
||||
options: [{ text: 'Hello', value: 'World' }],
|
||||
},
|
||||
{
|
||||
type: 'datasource',
|
||||
name: 'datasource',
|
||||
// @ts-expect-error
|
||||
options: [{ text: 'ds', value: 'ds' }], // fake example doesn't exist
|
||||
},
|
||||
{
|
||||
type: 'interval',
|
||||
name: 'interval',
|
||||
// @ts-expect-error
|
||||
options: [{ text: '1m', value: '1m' }],
|
||||
},
|
||||
],
|
||||
@ -1112,10 +1156,12 @@ describe('DashboardModel', () => {
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
thresholds: {
|
||||
// @ts-expect-error
|
||||
mode: 'absolute',
|
||||
steps: [
|
||||
{
|
||||
color: 'green',
|
||||
// @ts-expect-error
|
||||
value: null,
|
||||
},
|
||||
{
|
||||
@ -1128,12 +1174,14 @@ describe('DashboardModel', () => {
|
||||
{
|
||||
id: 0,
|
||||
text: '1',
|
||||
// @ts-expect-error
|
||||
type: 1,
|
||||
value: 'up',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
text: 'BAD',
|
||||
// @ts-expect-error
|
||||
type: 1,
|
||||
value: 'down',
|
||||
},
|
||||
@ -1142,6 +1190,7 @@ describe('DashboardModel', () => {
|
||||
id: 2,
|
||||
text: 'below 30',
|
||||
to: '30',
|
||||
// @ts-expect-error
|
||||
type: 2,
|
||||
},
|
||||
{
|
||||
@ -1149,9 +1198,11 @@ describe('DashboardModel', () => {
|
||||
id: 3,
|
||||
text: '100',
|
||||
to: '100',
|
||||
// @ts-expect-error
|
||||
type: 2,
|
||||
},
|
||||
{
|
||||
// @ts-expect-error
|
||||
type: 1,
|
||||
value: 'null',
|
||||
text: 'it is null',
|
||||
@ -1243,6 +1294,7 @@ describe('DashboardModel', () => {
|
||||
panels: [
|
||||
{
|
||||
type: 'timeseries',
|
||||
// @ts-expect-error
|
||||
legend: true,
|
||||
options: {
|
||||
tooltipOptions: { mode: 'multi' },
|
||||
@ -1250,6 +1302,7 @@ describe('DashboardModel', () => {
|
||||
},
|
||||
{
|
||||
type: 'xychart',
|
||||
// @ts-expect-error
|
||||
legend: true,
|
||||
options: {
|
||||
tooltipOptions: { mode: 'single' },
|
||||
@ -1281,6 +1334,7 @@ describe('DashboardModel', () => {
|
||||
{
|
||||
type: 'singlestat',
|
||||
legend: true,
|
||||
// @ts-expect-error
|
||||
thresholds: '10,20,30',
|
||||
colors: ['#FF0000', 'green', 'orange'],
|
||||
aliasYAxis: { test: 2 },
|
||||
@ -1342,6 +1396,7 @@ describe('DashboardModel', () => {
|
||||
{
|
||||
type: 'singlestat',
|
||||
legend: true,
|
||||
// @ts-expect-error
|
||||
thresholds: '10,20,30',
|
||||
colors: ['#FF0000', 'green', 'orange'],
|
||||
aliasYAxis: { test: 2 },
|
||||
@ -1424,6 +1479,7 @@ describe('DashboardModel', () => {
|
||||
{
|
||||
id: 1,
|
||||
type: 'timeseries',
|
||||
// @ts-expect-error
|
||||
panels: [
|
||||
{
|
||||
id: 2,
|
||||
@ -1462,6 +1518,7 @@ describe('DashboardModel', () => {
|
||||
{
|
||||
id: 1,
|
||||
type: 'timeseries',
|
||||
// @ts-expect-error
|
||||
transformations: [{ id: 'labelsToFields' }],
|
||||
},
|
||||
],
|
||||
@ -1493,6 +1550,7 @@ describe('DashboardModel', () => {
|
||||
annotations: {
|
||||
list: [
|
||||
{
|
||||
// @ts-expect-error
|
||||
actionPrefix: '',
|
||||
alarmNamePrefix: '',
|
||||
alias: '',
|
||||
@ -1515,6 +1573,7 @@ describe('DashboardModel', () => {
|
||||
],
|
||||
},
|
||||
panels: [
|
||||
// @ts-expect-error
|
||||
{
|
||||
gridPos: {
|
||||
h: 8,
|
||||
@ -1602,6 +1661,7 @@ describe('DashboardModel', () => {
|
||||
annotations: {
|
||||
list: [
|
||||
{
|
||||
// @ts-expect-error
|
||||
actionPrefix: '',
|
||||
alarmNamePrefix: '',
|
||||
alias: '',
|
||||
@ -1636,6 +1696,7 @@ describe('DashboardModel', () => {
|
||||
title: 'DynamoDB',
|
||||
type: 'row',
|
||||
panels: [
|
||||
// @ts-expect-error
|
||||
{
|
||||
gridPos: {
|
||||
h: 8,
|
||||
@ -1690,6 +1751,7 @@ describe('DashboardModel', () => {
|
||||
title: 'Panel Title',
|
||||
type: 'timeseries',
|
||||
},
|
||||
// @ts-expect-error
|
||||
{
|
||||
gridPos: {
|
||||
h: 8,
|
||||
@ -1793,6 +1855,7 @@ describe('DashboardModel', () => {
|
||||
name: 'var',
|
||||
options: [{ text: 'A', value: 'A' }],
|
||||
refresh: 0,
|
||||
// @ts-expect-error
|
||||
datasource: 'prom',
|
||||
},
|
||||
],
|
||||
@ -1800,14 +1863,17 @@ describe('DashboardModel', () => {
|
||||
panels: [
|
||||
{
|
||||
id: 1,
|
||||
// @ts-expect-error
|
||||
datasource: 'prom',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
// @ts-expect-error
|
||||
datasource: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
// @ts-expect-error
|
||||
datasource: MIXED_DATASOURCE_NAME,
|
||||
targets: [
|
||||
{
|
||||
@ -1827,6 +1893,7 @@ describe('DashboardModel', () => {
|
||||
panels: [
|
||||
{
|
||||
id: 6,
|
||||
// @ts-expect-error
|
||||
datasource: 'prom',
|
||||
},
|
||||
],
|
||||
@ -1873,6 +1940,7 @@ describe('DashboardModel', () => {
|
||||
panels: [
|
||||
{
|
||||
id: 2,
|
||||
// @ts-expect-error
|
||||
datasource: null,
|
||||
targets: [
|
||||
{
|
||||
@ -1894,6 +1962,7 @@ describe('DashboardModel', () => {
|
||||
test('preserves x axis visibility', () => {
|
||||
const model = new DashboardModel({
|
||||
panels: [
|
||||
// @ts-expect-error
|
||||
{
|
||||
type: 'timeseries',
|
||||
fieldConfig: {
|
||||
@ -1937,6 +2006,7 @@ describe('DashboardModel', () => {
|
||||
{
|
||||
type: 'query',
|
||||
name: 'var',
|
||||
// @ts-expect-error
|
||||
options: [{ text: 'A', value: 'A' }],
|
||||
refresh: 0,
|
||||
datasource: null,
|
||||
@ -1946,9 +2016,11 @@ describe('DashboardModel', () => {
|
||||
annotations: {
|
||||
list: [
|
||||
{
|
||||
// @ts-expect-error
|
||||
datasource: null,
|
||||
},
|
||||
{
|
||||
// @ts-expect-error
|
||||
datasource: 'prom',
|
||||
},
|
||||
],
|
||||
@ -1956,6 +2028,7 @@ describe('DashboardModel', () => {
|
||||
panels: [
|
||||
{
|
||||
id: 2,
|
||||
// @ts-expect-error
|
||||
datasource: null,
|
||||
targets: [
|
||||
{
|
||||
@ -1963,6 +2036,7 @@ describe('DashboardModel', () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
// @ts-expect-error
|
||||
{
|
||||
id: 3,
|
||||
targets: [
|
||||
@ -2007,6 +2081,7 @@ describe('DashboardModel', () => {
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({
|
||||
panels: [
|
||||
// @ts-expect-error
|
||||
{
|
||||
id: 2,
|
||||
targets: [
|
||||
@ -2040,6 +2115,7 @@ describe('when generating the legend for a panel', () => {
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({
|
||||
panels: [
|
||||
// @ts-expect-error
|
||||
{
|
||||
id: 0,
|
||||
options: {
|
||||
@ -2052,6 +2128,7 @@ describe('when generating the legend for a panel', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
// @ts-expect-error
|
||||
{
|
||||
id: 1,
|
||||
options: {
|
||||
@ -2064,6 +2141,7 @@ describe('when generating the legend for a panel', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
// @ts-expect-error
|
||||
{
|
||||
id: 2,
|
||||
options: {
|
||||
|
@ -2,8 +2,8 @@ import { appEvents } from '../../../core/core';
|
||||
import { VariablesChanged } from '../../variables/types';
|
||||
import { getTimeSrv, setTimeSrv } from '../services/TimeSrv';
|
||||
|
||||
import { DashboardModel } from './DashboardModel';
|
||||
import { PanelModel } from './PanelModel';
|
||||
import { createDashboardModelFixture } from './__fixtures__/dashboardFixtures';
|
||||
|
||||
function getTestContext({
|
||||
usePanelInEdit,
|
||||
@ -12,7 +12,7 @@ function getTestContext({
|
||||
}: { usePanelInEdit?: boolean; usePanelInView?: boolean; refreshAll?: boolean } = {}) {
|
||||
jest.clearAllMocks();
|
||||
|
||||
const dashboard = new DashboardModel({});
|
||||
const dashboard = createDashboardModelFixture();
|
||||
const startRefreshMock = jest.fn();
|
||||
dashboard.startRefresh = startRefreshMock;
|
||||
const panelInView = new PanelModel({ id: 99 });
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { keys as _keys } from 'lodash';
|
||||
|
||||
import { VariableHide } from '@grafana/data';
|
||||
import { defaultVariableModel } from '@grafana/schema';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
|
||||
import { getDashboardModel } from '../../../../test/helpers/getDashboardModel';
|
||||
@ -11,6 +13,13 @@ import { setTimeSrv, TimeSrv } from '../services/TimeSrv';
|
||||
import { DashboardModel } from '../state/DashboardModel';
|
||||
import { PanelModel } from '../state/PanelModel';
|
||||
|
||||
import {
|
||||
createAnnotationJSONFixture,
|
||||
createDashboardModelFixture,
|
||||
createPanelJSONFixture,
|
||||
createVariableJSONFixture,
|
||||
} from './__fixtures__/dashboardFixtures';
|
||||
|
||||
jest.mock('app/core/services/context_srv');
|
||||
|
||||
const mockContextSrv = jest.mocked(contextSrv);
|
||||
@ -26,7 +35,7 @@ describe('DashboardModel', () => {
|
||||
let model: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({}, {});
|
||||
model = createDashboardModelFixture();
|
||||
});
|
||||
|
||||
it('should have title', () => {
|
||||
@ -47,8 +56,8 @@ describe('DashboardModel', () => {
|
||||
let model: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({
|
||||
panels: [{ id: 5 }],
|
||||
model = createDashboardModelFixture({
|
||||
panels: [createPanelJSONFixture({ id: 5 })],
|
||||
});
|
||||
});
|
||||
|
||||
@ -59,8 +68,7 @@ describe('DashboardModel', () => {
|
||||
|
||||
describe('getSaveModelClone', () => {
|
||||
it('should sort keys', () => {
|
||||
const model = new DashboardModel({});
|
||||
model.autoUpdate = null;
|
||||
const model = createDashboardModelFixture();
|
||||
|
||||
const saveModel = model.getSaveModelClone();
|
||||
const keys = _keys(saveModel);
|
||||
@ -70,7 +78,7 @@ describe('DashboardModel', () => {
|
||||
});
|
||||
|
||||
it('should remove add panel panels', () => {
|
||||
const model = new DashboardModel({});
|
||||
const model = createDashboardModelFixture();
|
||||
model.addPanel({
|
||||
type: 'add-panel',
|
||||
});
|
||||
@ -87,7 +95,7 @@ describe('DashboardModel', () => {
|
||||
});
|
||||
|
||||
it('should save model in edit mode', () => {
|
||||
const model = new DashboardModel({});
|
||||
const model = createDashboardModelFixture();
|
||||
model.addPanel({ type: 'graph' });
|
||||
|
||||
const panel = model.initEditPanel(model.panels[0]);
|
||||
@ -105,7 +113,7 @@ describe('DashboardModel', () => {
|
||||
let dashboard: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
dashboard = new DashboardModel({});
|
||||
dashboard = createDashboardModelFixture();
|
||||
});
|
||||
|
||||
it('adding panel should new up panel model', () => {
|
||||
@ -148,7 +156,7 @@ describe('DashboardModel', () => {
|
||||
let model: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({ editable: false });
|
||||
model = createDashboardModelFixture({ editable: false });
|
||||
});
|
||||
|
||||
it('Should set meta canEdit and canSave to false', () => {
|
||||
@ -167,12 +175,11 @@ describe('DashboardModel', () => {
|
||||
let target: any;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({
|
||||
model = createDashboardModelFixture({
|
||||
schemaVersion: 1,
|
||||
panels: [
|
||||
{
|
||||
createPanelJSONFixture({
|
||||
type: 'graph',
|
||||
grid: {},
|
||||
yaxes: [{}, {}],
|
||||
targets: [
|
||||
{
|
||||
alias: '$tag_datacenter $tag_source $col',
|
||||
@ -211,7 +218,7 @@ describe('DashboardModel', () => {
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
@ -233,13 +240,9 @@ describe('DashboardModel', () => {
|
||||
let model: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({
|
||||
annotations: {
|
||||
enable: true,
|
||||
},
|
||||
templating: {
|
||||
enable: true,
|
||||
},
|
||||
model = createDashboardModelFixture({
|
||||
annotations: {},
|
||||
templating: {},
|
||||
});
|
||||
});
|
||||
|
||||
@ -258,7 +261,7 @@ describe('DashboardModel', () => {
|
||||
let dashboard: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
dashboard = new DashboardModel({ timezone: 'utc' });
|
||||
dashboard = createDashboardModelFixture({ timezone: 'utc' });
|
||||
});
|
||||
|
||||
it('Should format timestamp with second resolution by default', () => {
|
||||
@ -278,7 +281,7 @@ describe('DashboardModel', () => {
|
||||
let model: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({});
|
||||
model = createDashboardModelFixture();
|
||||
});
|
||||
|
||||
it('should not show submenu', () => {
|
||||
@ -290,9 +293,21 @@ describe('DashboardModel', () => {
|
||||
let model: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({
|
||||
model = createDashboardModelFixture({
|
||||
schemaVersion: 30,
|
||||
annotations: {
|
||||
list: [{}],
|
||||
list: [
|
||||
{
|
||||
datasource: { uid: 'fake-uid', type: 'prometheus' },
|
||||
showIn: 0,
|
||||
name: 'Fake annotation',
|
||||
type: 'dashboard',
|
||||
iconColor: 'rgba(0, 211, 255, 1)',
|
||||
enable: true,
|
||||
hide: false,
|
||||
builtIn: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -306,10 +321,10 @@ describe('DashboardModel', () => {
|
||||
let model: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel(
|
||||
model = createDashboardModelFixture(
|
||||
{
|
||||
templating: {
|
||||
list: [{}],
|
||||
list: [createVariableJSONFixture({})],
|
||||
},
|
||||
},
|
||||
{},
|
||||
@ -327,9 +342,14 @@ describe('DashboardModel', () => {
|
||||
let model: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({
|
||||
model = createDashboardModelFixture({
|
||||
templating: {
|
||||
list: [{ hide: 2 }],
|
||||
list: [
|
||||
{
|
||||
...defaultVariableModel,
|
||||
hide: VariableHide.hideVariable,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -343,9 +363,9 @@ describe('DashboardModel', () => {
|
||||
let dashboard: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
dashboard = new DashboardModel({
|
||||
dashboard = createDashboardModelFixture({
|
||||
annotations: {
|
||||
list: [{ hide: true }],
|
||||
list: [createAnnotationJSONFixture({ hide: true })],
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -359,13 +379,13 @@ describe('DashboardModel', () => {
|
||||
let dashboard: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
dashboard = new DashboardModel({
|
||||
dashboard = createDashboardModelFixture({
|
||||
panels: [
|
||||
{ id: 1, type: 'graph', gridPos: { x: 0, y: 0, w: 24, h: 2 } },
|
||||
{ id: 2, type: 'row', gridPos: { x: 0, y: 2, w: 24, h: 2 } },
|
||||
{ id: 3, type: 'graph', gridPos: { x: 0, y: 4, w: 12, h: 2 } },
|
||||
{ id: 4, type: 'graph', gridPos: { x: 12, y: 4, w: 12, h: 2 } },
|
||||
{ id: 5, type: 'row', gridPos: { x: 0, y: 6, w: 24, h: 2 } },
|
||||
createPanelJSONFixture({ id: 1, type: 'graph', gridPos: { x: 0, y: 0, w: 24, h: 2 } }),
|
||||
createPanelJSONFixture({ id: 2, type: 'row', gridPos: { x: 0, y: 2, w: 24, h: 2 } }),
|
||||
createPanelJSONFixture({ id: 3, type: 'graph', gridPos: { x: 0, y: 4, w: 12, h: 2 } }),
|
||||
createPanelJSONFixture({ id: 4, type: 'graph', gridPos: { x: 12, y: 4, w: 12, h: 2 } }),
|
||||
createPanelJSONFixture({ id: 5, type: 'row', gridPos: { x: 0, y: 6, w: 24, h: 2 } }),
|
||||
],
|
||||
});
|
||||
dashboard.toggleRow(dashboard.panels[1]);
|
||||
@ -410,7 +430,7 @@ describe('DashboardModel', () => {
|
||||
let dashboard: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
dashboard = new DashboardModel({
|
||||
dashboard = createDashboardModelFixture({
|
||||
panels: [
|
||||
{ id: 1, type: 'graph', gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{
|
||||
@ -423,7 +443,7 @@ describe('DashboardModel', () => {
|
||||
{ id: 4, type: 'graph', gridPos: { x: 12, y: 7, w: 12, h: 2 } },
|
||||
],
|
||||
},
|
||||
{ id: 5, type: 'row', gridPos: { x: 0, y: 7, w: 1, h: 1 } },
|
||||
{ id: 5, type: 'row', collapsed: false, panels: [], gridPos: { x: 0, y: 7, w: 1, h: 1 } },
|
||||
],
|
||||
});
|
||||
dashboard.toggleRow(dashboard.panels[1]);
|
||||
@ -481,7 +501,7 @@ describe('DashboardModel', () => {
|
||||
let dashboard: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
dashboard = new DashboardModel({
|
||||
dashboard = createDashboardModelFixture({
|
||||
panels: [
|
||||
{ id: 1, type: 'graph', gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{
|
||||
@ -490,11 +510,14 @@ describe('DashboardModel', () => {
|
||||
gridPos: { x: 0, y: 6, w: 24, h: 1 },
|
||||
collapsed: true,
|
||||
panels: [
|
||||
// this whole test is about dealing with out-of-spec (or at least ambigious) data...
|
||||
//@ts-expect-error
|
||||
{ id: 3, type: 'graph', gridPos: { w: 12, h: 2 } },
|
||||
//@ts-expect-error
|
||||
{ id: 4, type: 'graph', gridPos: { w: 12, h: 2 } },
|
||||
],
|
||||
},
|
||||
{ id: 5, type: 'row', gridPos: { x: 0, y: 7, w: 1, h: 1 } },
|
||||
{ id: 5, type: 'row', collapsed: false, panels: [], gridPos: { x: 0, y: 7, w: 1, h: 1 } },
|
||||
],
|
||||
});
|
||||
dashboard.toggleRow(dashboard.panels[1]);
|
||||
@ -523,7 +546,7 @@ describe('DashboardModel', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
model = new DashboardModel({
|
||||
model = createDashboardModelFixture({
|
||||
time: {
|
||||
from: 'now-6h',
|
||||
to: 'now',
|
||||
@ -838,14 +861,13 @@ describe('DashboardModel', () => {
|
||||
let model: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
const data = {
|
||||
model = createDashboardModelFixture({
|
||||
panels: [
|
||||
{ id: 1, type: 'graph', gridPos: { x: 0, y: 0, w: 24, h: 2 }, legend: { show: true } },
|
||||
{ id: 3, type: 'graph', gridPos: { x: 0, y: 4, w: 12, h: 2 }, legend: { show: false } },
|
||||
{ id: 4, type: 'graph', gridPos: { x: 12, y: 4, w: 12, h: 2 }, legend: { show: false } },
|
||||
],
|
||||
};
|
||||
model = new DashboardModel(data);
|
||||
});
|
||||
});
|
||||
|
||||
it('toggleLegendsForAll should toggle all legends on on first execution', () => {
|
||||
@ -876,7 +898,7 @@ describe('DashboardModel', () => {
|
||||
`(
|
||||
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable}, canAdd:{$canAdd} and expected:{$expected}',
|
||||
({ canEdit, canMakeEditable, canAdd, expected }) => {
|
||||
const dashboard = new DashboardModel(
|
||||
const dashboard = createDashboardModelFixture(
|
||||
{},
|
||||
{
|
||||
annotationsPermissions: {
|
||||
@ -909,7 +931,7 @@ describe('DashboardModel', () => {
|
||||
`(
|
||||
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable}, canEditWithOrgPermission:{$canEditWithOrgPermission} and expected:{$expected}',
|
||||
({ canEdit, canMakeEditable, canEditWithOrgPermission, expected }) => {
|
||||
const dashboard = new DashboardModel(
|
||||
const dashboard = createDashboardModelFixture(
|
||||
{},
|
||||
{
|
||||
annotationsPermissions: {
|
||||
@ -940,7 +962,7 @@ describe('DashboardModel', () => {
|
||||
`(
|
||||
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable}, canEditWithDashboardPermission:{$canEditWithDashboardPermission} and expected:{$expected}',
|
||||
({ canEdit, canMakeEditable, canEditWithDashboardPermission, expected }) => {
|
||||
const dashboard = new DashboardModel(
|
||||
const dashboard = createDashboardModelFixture(
|
||||
{},
|
||||
{
|
||||
annotationsPermissions: {
|
||||
@ -973,7 +995,7 @@ describe('DashboardModel', () => {
|
||||
`(
|
||||
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable}, canDeleteWithOrgPermission:{$canDeleteWithOrgPermission} and expected:{$expected}',
|
||||
({ canEdit, canMakeEditable, canDeleteWithOrgPermission, expected }) => {
|
||||
const dashboard = new DashboardModel(
|
||||
const dashboard = createDashboardModelFixture(
|
||||
{},
|
||||
{
|
||||
annotationsPermissions: {
|
||||
@ -1004,7 +1026,7 @@ describe('DashboardModel', () => {
|
||||
`(
|
||||
'when called with canEdit:{$canEdit}, canMakeEditable:{$canMakeEditable}, canDeleteWithDashboardPermission:{$canDeleteWithDashboardPermission} and expected:{$expected}',
|
||||
({ canEdit, canMakeEditable, canDeleteWithDashboardPermission, expected }) => {
|
||||
const dashboard = new DashboardModel(
|
||||
const dashboard = createDashboardModelFixture(
|
||||
{},
|
||||
{
|
||||
annotationsPermissions: {
|
||||
@ -1025,9 +1047,9 @@ describe('DashboardModel', () => {
|
||||
|
||||
describe('canEditPanel', () => {
|
||||
it('returns false if the dashboard cannot be edited', () => {
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [
|
||||
{ id: 1, type: 'row', gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{ id: 1, type: 'row', collapsed: false, panels: [], gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{ id: 2, type: 'graph', gridPos: { x: 0, y: 7, w: 12, h: 2 } },
|
||||
],
|
||||
});
|
||||
@ -1037,9 +1059,9 @@ describe('DashboardModel', () => {
|
||||
});
|
||||
|
||||
it('returns false if no panel is passed in', () => {
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [
|
||||
{ id: 1, type: 'row', gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{ id: 1, type: 'row', collapsed: false, panels: [], gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{ id: 2, type: 'graph', gridPos: { x: 0, y: 7, w: 12, h: 2 } },
|
||||
],
|
||||
});
|
||||
@ -1047,9 +1069,9 @@ describe('DashboardModel', () => {
|
||||
});
|
||||
|
||||
it('returns false if the panel is a repeat', () => {
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [
|
||||
{ id: 1, type: 'row', gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{ id: 1, type: 'row', collapsed: false, panels: [], gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{ id: 2, type: 'graph', gridPos: { x: 0, y: 7, w: 12, h: 2 } },
|
||||
{ id: 3, type: 'graph', gridPos: { x: 0, y: 7, w: 12, h: 2 }, repeatPanelId: 2 },
|
||||
],
|
||||
@ -1059,9 +1081,9 @@ describe('DashboardModel', () => {
|
||||
});
|
||||
|
||||
it('returns false if the panel is a row', () => {
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [
|
||||
{ id: 1, type: 'row', gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{ id: 1, type: 'row', collapsed: false, panels: [], gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{ id: 2, type: 'graph', gridPos: { x: 0, y: 7, w: 12, h: 2 } },
|
||||
],
|
||||
});
|
||||
@ -1070,9 +1092,9 @@ describe('DashboardModel', () => {
|
||||
});
|
||||
|
||||
it('returns true otherwise', () => {
|
||||
const dashboard = new DashboardModel({
|
||||
const dashboard = createDashboardModelFixture({
|
||||
panels: [
|
||||
{ id: 1, type: 'row', gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{ id: 1, type: 'row', collapsed: false, panels: [], gridPos: { x: 0, y: 0, w: 24, h: 6 } },
|
||||
{ id: 2, type: 'graph', gridPos: { x: 0, y: 7, w: 12, h: 2 } },
|
||||
],
|
||||
});
|
||||
@ -1085,7 +1107,7 @@ describe('DashboardModel', () => {
|
||||
describe('exitViewPanel', () => {
|
||||
function getTestContext() {
|
||||
const panel: any = { setIsViewing: jest.fn() };
|
||||
const dashboard = new DashboardModel({});
|
||||
const dashboard = createDashboardModelFixture();
|
||||
dashboard.startRefresh = jest.fn();
|
||||
dashboard.panelInView = panel;
|
||||
|
||||
@ -1122,7 +1144,7 @@ describe('exitViewPanel', () => {
|
||||
describe('exitPanelEditor', () => {
|
||||
function getTestContext(pauseAutoRefresh = false) {
|
||||
const panel: any = { destroy: jest.fn() };
|
||||
const dashboard = new DashboardModel({});
|
||||
const dashboard = createDashboardModelFixture();
|
||||
const timeSrvMock = {
|
||||
pauseAutoRefresh: jest.fn(),
|
||||
resumeAutoRefresh: jest.fn(),
|
||||
@ -1172,7 +1194,7 @@ describe('exitPanelEditor', () => {
|
||||
|
||||
describe('initEditPanel', () => {
|
||||
function getTestContext() {
|
||||
const dashboard = new DashboardModel({});
|
||||
const dashboard = createDashboardModelFixture();
|
||||
const timeSrvMock = {
|
||||
pauseAutoRefresh: jest.fn(),
|
||||
resumeAutoRefresh: jest.fn(),
|
||||
|
@ -17,6 +17,7 @@ import {
|
||||
UrlQueryValue,
|
||||
} from '@grafana/data';
|
||||
import { RefreshEvent, TimeRangeUpdatedEvent } from '@grafana/runtime';
|
||||
import { Dashboard } from '@grafana/schema';
|
||||
import { DEFAULT_ANNOTATION_COLOR } from '@grafana/ui';
|
||||
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT, REPEAT_DIR_VERTICAL } from 'app/core/constants';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
@ -68,9 +69,9 @@ export interface DashboardLink {
|
||||
|
||||
export class DashboardModel implements TimeModel {
|
||||
id: any;
|
||||
uid: string;
|
||||
// TODO: use propert type and fix all the places where uid is set to null
|
||||
uid: any;
|
||||
title: string;
|
||||
autoUpdate: any;
|
||||
description: any;
|
||||
tags: any;
|
||||
style: any;
|
||||
@ -125,17 +126,13 @@ export class DashboardModel implements TimeModel {
|
||||
lastRefresh: true,
|
||||
};
|
||||
|
||||
constructor(data: any, meta?: DashboardMeta, private getVariablesFromState: GetVariables = getVariablesByKey) {
|
||||
if (!data) {
|
||||
data = {};
|
||||
}
|
||||
|
||||
constructor(data: Dashboard, meta?: DashboardMeta, private getVariablesFromState: GetVariables = getVariablesByKey) {
|
||||
this.events = new EventBusSrv();
|
||||
this.id = data.id || null;
|
||||
// UID is not there for newly created dashboards
|
||||
this.uid = data.uid || null;
|
||||
this.revision = data.revision;
|
||||
this.revision = data.revision || 1;
|
||||
this.title = data.title ?? 'No Title';
|
||||
this.autoUpdate = data.autoUpdate;
|
||||
this.description = data.description;
|
||||
this.tags = data.tags ?? [];
|
||||
this.style = data.style ?? 'dark';
|
||||
|
@ -0,0 +1,68 @@
|
||||
import {
|
||||
AnnotationQuery,
|
||||
Dashboard,
|
||||
defaultDashboardCursorSync,
|
||||
defaultVariableModel,
|
||||
GraphPanel,
|
||||
Panel,
|
||||
VariableModel,
|
||||
} from '@grafana/schema';
|
||||
import { GetVariables } from 'app/features/variables/state/selectors';
|
||||
import { DashboardMeta } from 'app/types';
|
||||
|
||||
import { DashboardModel } from '../DashboardModel';
|
||||
|
||||
export function createDashboardModelFixture(
|
||||
dashboardInput: Partial<Dashboard> = {},
|
||||
meta?: DashboardMeta,
|
||||
getVariablesFromState?: GetVariables
|
||||
): DashboardModel {
|
||||
const dashboardJson: Dashboard = {
|
||||
editable: true,
|
||||
graphTooltip: defaultDashboardCursorSync,
|
||||
schemaVersion: 1,
|
||||
revision: 1,
|
||||
style: 'dark',
|
||||
...dashboardInput,
|
||||
};
|
||||
|
||||
return new DashboardModel(dashboardJson, meta, getVariablesFromState);
|
||||
}
|
||||
|
||||
export function createPanelJSONFixture(panelInput: Partial<Panel | GraphPanel> = {}): Panel {
|
||||
return {
|
||||
fieldConfig: {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
},
|
||||
options: {},
|
||||
repeatDirection: 'h',
|
||||
transformations: [],
|
||||
transparent: false,
|
||||
type: 'timeseries',
|
||||
...panelInput,
|
||||
};
|
||||
}
|
||||
|
||||
export function createAnnotationJSONFixture(annotationInput: Partial<AnnotationQuery>): AnnotationQuery {
|
||||
return {
|
||||
builtIn: 0, // ??
|
||||
datasource: {
|
||||
type: 'foo',
|
||||
uid: 'bar',
|
||||
},
|
||||
showIn: 2,
|
||||
enable: true,
|
||||
type: 'anno',
|
||||
...annotationInput,
|
||||
};
|
||||
}
|
||||
|
||||
export function createVariableJSONFixture(annotationInput: Partial<VariableModel>): VariableModel {
|
||||
return {
|
||||
...defaultVariableModel,
|
||||
name: 'foo.variable',
|
||||
type: 'constant',
|
||||
...annotationInput,
|
||||
};
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { DashboardInitPhase, DashboardState, OrgRole, PermissionLevel } from 'app/types';
|
||||
|
||||
import { DashboardModel } from './DashboardModel';
|
||||
import { createDashboardModelFixture, createPanelJSONFixture } from './__fixtures__/dashboardFixtures';
|
||||
import {
|
||||
dashboardInitCompleted,
|
||||
dashboardInitFailed,
|
||||
@ -35,9 +35,9 @@ describe('dashboard reducer', () => {
|
||||
state = dashboardReducer(
|
||||
state,
|
||||
dashboardInitCompleted(
|
||||
new DashboardModel({
|
||||
createDashboardModelFixture({
|
||||
title: 'My dashboard',
|
||||
panels: [{ id: 1 }, { id: 2 }],
|
||||
panels: [createPanelJSONFixture({ id: 1 }), createPanelJSONFixture({ id: 2 })],
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
import { AngularComponent } from '@grafana/runtime';
|
||||
import { Dashboard, defaultDashboard } from '@grafana/schema';
|
||||
import { processAclItems } from 'app/core/utils/acl';
|
||||
import { DashboardAclDTO, DashboardInitError, DashboardInitPhase, DashboardState } from 'app/types';
|
||||
|
||||
@ -36,7 +37,12 @@ const dashboardSlice = createSlice({
|
||||
state.initPhase = DashboardInitPhase.Failed;
|
||||
state.initError = action.payload;
|
||||
state.getModel = () => {
|
||||
return new DashboardModel({ title: 'Dashboard init failed' }, { canSave: false, canEdit: false });
|
||||
// TODO this is a type conflict,
|
||||
// we need to fix the defaultDashboard init type when generated by cue
|
||||
return new DashboardModel(
|
||||
{ ...(defaultDashboard as Dashboard), title: 'Dashboard init failed' },
|
||||
{ canSave: false, canEdit: false }
|
||||
);
|
||||
};
|
||||
},
|
||||
cleanUpDashboard: (state) => {
|
||||
|
@ -3,7 +3,8 @@ import config from 'app/core/config';
|
||||
import * as actions from 'app/features/explore/state/main';
|
||||
import { setStore } from 'app/store/store';
|
||||
|
||||
import { DashboardModel, PanelModel } from '../state';
|
||||
import { PanelModel } from '../state';
|
||||
import { createDashboardModelFixture } from '../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { getPanelMenu } from './getPanelMenu';
|
||||
|
||||
@ -16,7 +17,7 @@ jest.mock('app/core/services/context_srv', () => ({
|
||||
describe('getPanelMenu', () => {
|
||||
it('should return the correct panel menu items', () => {
|
||||
const panel = new PanelModel({});
|
||||
const dashboard = new DashboardModel({});
|
||||
const dashboard = createDashboardModelFixture({});
|
||||
|
||||
const menuItems = getPanelMenu(dashboard, panel);
|
||||
expect(menuItems).toMatchInlineSnapshot(`
|
||||
@ -100,7 +101,7 @@ describe('getPanelMenu', () => {
|
||||
const scope: any = { $$childHead: { ctrl } };
|
||||
const angularComponent: any = { getScope: () => scope };
|
||||
const panel = new PanelModel({ isViewing: true });
|
||||
const dashboard = new DashboardModel({});
|
||||
const dashboard = createDashboardModelFixture({});
|
||||
|
||||
const menuItems = getPanelMenu(dashboard, panel, angularComponent);
|
||||
expect(menuItems).toMatchInlineSnapshot(`
|
||||
@ -171,7 +172,7 @@ describe('getPanelMenu', () => {
|
||||
|
||||
beforeAll(() => {
|
||||
const panel = new PanelModel({});
|
||||
const dashboard = new DashboardModel({});
|
||||
const dashboard = createDashboardModelFixture({});
|
||||
const menuItems = getPanelMenu(dashboard, panel);
|
||||
explore = menuItems.find((item) => item.text === 'Explore') as PanelMenuItem;
|
||||
navigateSpy = jest.spyOn(actions, 'navigateToExplore');
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { PanelModel } from '@grafana/data';
|
||||
import { FieldColorModeId, ThresholdsMode } from '@grafana/schema/src';
|
||||
|
||||
import { DashboardModel } from '../state/DashboardModel';
|
||||
import { createDashboardModelFixture, createPanelJSONFixture } from '../state/__fixtures__/dashboardFixtures';
|
||||
|
||||
describe('Merge dashbaord panels', () => {
|
||||
describe('simple changes', () => {
|
||||
@ -8,35 +10,35 @@ describe('Merge dashbaord panels', () => {
|
||||
let rawPanels: PanelModel[];
|
||||
|
||||
beforeEach(() => {
|
||||
dashboard = new DashboardModel({
|
||||
dashboard = createDashboardModelFixture({
|
||||
title: 'simple title',
|
||||
panels: [
|
||||
{
|
||||
createPanelJSONFixture({
|
||||
id: 1,
|
||||
type: 'timeseries',
|
||||
},
|
||||
{
|
||||
}),
|
||||
createPanelJSONFixture({
|
||||
id: 2,
|
||||
type: 'timeseries',
|
||||
},
|
||||
{
|
||||
}),
|
||||
createPanelJSONFixture({
|
||||
id: 3,
|
||||
type: 'table',
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
thresholds: {
|
||||
mode: 'absolute',
|
||||
mode: ThresholdsMode.Absolute,
|
||||
steps: [
|
||||
{ color: 'green', value: -Infinity }, // save model has this as null
|
||||
{ color: 'red', value: 80 },
|
||||
],
|
||||
},
|
||||
mappings: [],
|
||||
color: { mode: 'thresholds' },
|
||||
color: { mode: FieldColorModeId.Thresholds },
|
||||
},
|
||||
overrides: [],
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
rawPanels = dashboard.getSaveModelClone().panels;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { DataQuery, MutableDataFrame } from '@grafana/data';
|
||||
import { defaultDashboard } from '@grafana/schema';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import * as api from 'app/features/dashboard/state/initDashboard';
|
||||
import { ExplorePanelData } from 'app/types';
|
||||
@ -53,6 +54,7 @@ describe('addPanelToDashboard', () => {
|
||||
const existingPanel = { prop: 'this should be kept' };
|
||||
jest.spyOn(backendSrv, 'getDashboardByUid').mockResolvedValue({
|
||||
dashboard: {
|
||||
...defaultDashboard,
|
||||
templating: { list: [] },
|
||||
title: 'Previous panels should not be removed',
|
||||
uid: 'someUid',
|
||||
|
@ -5,6 +5,7 @@ import { Provider } from 'react-redux';
|
||||
|
||||
import { DataQuery } from '@grafana/data';
|
||||
import { locationService, setEchoSrv } from '@grafana/runtime';
|
||||
import { defaultDashboard } from '@grafana/schema';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { Echo } from 'app/core/services/echo/Echo';
|
||||
@ -194,7 +195,7 @@ describe('AddToDashboardButton', () => {
|
||||
const openSpy = jest.spyOn(global, 'open').mockReturnValue(true);
|
||||
|
||||
jest.spyOn(backendSrv, 'getDashboardByUid').mockResolvedValue({
|
||||
dashboard: { templating: { list: [] }, title: 'Dashboard Title', uid: 'someUid' },
|
||||
dashboard: { ...defaultDashboard, templating: { list: [] }, title: 'Dashboard Title', uid: 'someUid' },
|
||||
meta: {},
|
||||
});
|
||||
jest.spyOn(backendSrv, 'search').mockResolvedValue([
|
||||
@ -236,7 +237,7 @@ describe('AddToDashboardButton', () => {
|
||||
const pushSpy = jest.spyOn(locationService, 'push');
|
||||
|
||||
jest.spyOn(backendSrv, 'getDashboardByUid').mockResolvedValue({
|
||||
dashboard: { templating: { list: [] }, title: 'Dashboard Title', uid: 'someUid' },
|
||||
dashboard: { ...defaultDashboard, templating: { list: [] }, title: 'Dashboard Title', uid: 'someUid' },
|
||||
meta: {},
|
||||
});
|
||||
jest.spyOn(backendSrv, 'search').mockResolvedValue([
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { defaultDashboard } from '@grafana/schema';
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
|
||||
import { getBackendSrv } from '../../../core/services/backend_srv';
|
||||
@ -59,6 +60,7 @@ export async function getLibraryPanel(uid: string, isHandled = false): Promise<L
|
||||
// kinda heavy weight migration process!!!
|
||||
const { result } = response.data;
|
||||
const dash = new DashboardModel({
|
||||
...defaultDashboard,
|
||||
schemaVersion: 35, // should be saved in the library panel
|
||||
panels: [result.model],
|
||||
});
|
||||
|
@ -7,7 +7,7 @@ import * as grafanaData from '@grafana/data';
|
||||
import { setDataSourceSrv, setEchoSrv } from '@grafana/runtime';
|
||||
|
||||
import { Echo } from '../../../core/services/echo/Echo';
|
||||
import { DashboardModel } from '../../dashboard/state/index';
|
||||
import { createDashboardModelFixture } from '../../dashboard/state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import {
|
||||
createDashboardQueryRunner,
|
||||
@ -30,7 +30,7 @@ jest.mock('app/core/config', () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
const dashboardModel = new DashboardModel({
|
||||
const dashboardModel = createDashboardModelFixture({
|
||||
panels: [{ id: 1, type: 'graph' }],
|
||||
});
|
||||
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { MetaAnalyticsEventName, reportMetaAnalytics } from '@grafana/runtime';
|
||||
|
||||
import { DashboardModel } from '../../dashboard/state';
|
||||
import { createDashboardModelFixture } from '../../dashboard/state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { emitDataRequestEvent } from './queryAnalytics';
|
||||
|
||||
@ -24,7 +24,7 @@ const datasource = {
|
||||
uid: 'test',
|
||||
} as DataSourceApi;
|
||||
|
||||
const dashboardModel = new DashboardModel(
|
||||
const dashboardModel = createDashboardModelFixture(
|
||||
{ id: 1, title: 'Test Dashboard', uid: 'test' },
|
||||
{ folderTitle: 'Test Folder' }
|
||||
);
|
||||
|
@ -14,13 +14,13 @@ import { setEchoSrv } from '@grafana/runtime';
|
||||
|
||||
import { deepFreeze } from '../../../../test/core/redux/reducerTester';
|
||||
import { Echo } from '../../../core/services/echo/Echo';
|
||||
import { DashboardModel } from '../../dashboard/state/DashboardModel';
|
||||
import { createDashboardModelFixture } from '../../dashboard/state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { runRequest } from './runRequest';
|
||||
|
||||
jest.mock('app/core/services/backend_srv');
|
||||
|
||||
const dashboardModel = new DashboardModel({
|
||||
const dashboardModel = createDashboardModelFixture({
|
||||
panels: [{ id: 1, type: 'graph' }],
|
||||
});
|
||||
|
||||
|
@ -11,7 +11,7 @@ import { formatRegistry, FormatRegistryID, FormatVariable } from './formatRegist
|
||||
|
||||
export type CustomFormatterFn = (
|
||||
value: unknown,
|
||||
legacyVariableModel: VariableModel,
|
||||
legacyVariableModel: Partial<VariableModel>,
|
||||
legacyDefaultFormatter?: CustomFormatterFn
|
||||
) => string;
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { appEvents } from '../../../core/core';
|
||||
import { notifyApp } from '../../../core/reducers/appNotification';
|
||||
import { DashboardState } from '../../../types';
|
||||
import { DashboardModel } from '../../dashboard/state';
|
||||
import { createDashboardModelFixture } from '../../dashboard/state/__fixtures__/dashboardFixtures';
|
||||
import { TemplateSrv } from '../../templating/template_srv';
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { createConstantVariableAdapter } from '../constant/adapter';
|
||||
@ -226,5 +227,5 @@ describe('when onTimeRangeUpdated is dispatched', () => {
|
||||
});
|
||||
|
||||
function getDashboardModel(): DashboardModel {
|
||||
return new DashboardModel({ schemaVersion: 9999 }); // ignore any schema migrations
|
||||
return createDashboardModelFixture({ schemaVersion: 9999 }); // ignore any schema migrations
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { TypedVariableModel } from '@grafana/data';
|
||||
|
||||
import { DashboardState, StoreState } from '../../../types';
|
||||
import { DashboardModel, PanelModel } from '../../dashboard/state';
|
||||
import { PanelModel } from '../../dashboard/state';
|
||||
import { createDashboardModelFixture } from '../../dashboard/state/__fixtures__/dashboardFixtures';
|
||||
import { initialState } from '../../dashboard/state/reducers';
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { createConstantVariableAdapter } from '../constant/adapter';
|
||||
@ -13,7 +14,7 @@ import { templateVarsChangedInUrl } from './actions';
|
||||
import { getPreloadedState } from './helpers';
|
||||
import { VariablesState } from './types';
|
||||
|
||||
const dashboardModel = new DashboardModel({});
|
||||
const dashboardModel = createDashboardModelFixture({});
|
||||
|
||||
variableAdapters.setInit(() => [createCustomVariableAdapter(), createConstantVariableAdapter()]);
|
||||
|
||||
|
@ -8,6 +8,11 @@ import { mockDataSource, MockDataSourceSrv } from 'app/features/alerting/unified
|
||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||
import { DashboardModel } from 'app/features/dashboard/state';
|
||||
|
||||
import {
|
||||
createDashboardModelFixture,
|
||||
createPanelJSONFixture,
|
||||
} from '../../../features/dashboard/state/__fixtures__/dashboardFixtures';
|
||||
|
||||
import { DashboardQueryEditor } from './DashboardQueryEditor';
|
||||
import { SHARED_DASHBOARD_QUERY } from './types';
|
||||
|
||||
@ -42,21 +47,21 @@ describe('DashboardQueryEditor', () => {
|
||||
let mockDashboard: DashboardModel;
|
||||
|
||||
beforeEach(() => {
|
||||
mockDashboard = new DashboardModel({
|
||||
mockDashboard = createDashboardModelFixture({
|
||||
panels: [
|
||||
{
|
||||
createPanelJSONFixture({
|
||||
targets: [],
|
||||
type: 'timeseries',
|
||||
id: 1,
|
||||
title: 'My first panel',
|
||||
},
|
||||
{
|
||||
}),
|
||||
createPanelJSONFixture({
|
||||
targets: [],
|
||||
id: 2,
|
||||
type: 'timeseries',
|
||||
title: 'Another panel',
|
||||
},
|
||||
{
|
||||
}),
|
||||
createPanelJSONFixture({
|
||||
datasource: {
|
||||
uid: SHARED_DASHBOARD_QUERY,
|
||||
},
|
||||
@ -64,7 +69,7 @@ describe('DashboardQueryEditor', () => {
|
||||
id: 3,
|
||||
type: 'timeseries',
|
||||
title: 'A dashboard query panel',
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
jest.spyOn(getDashboardSrv(), 'getCurrent').mockImplementation(() => mockDashboard);
|
||||
|
@ -6,7 +6,7 @@ import { PanelCtrl } from 'app/angular/panel/panel_ctrl';
|
||||
import config from 'app/core/config';
|
||||
import TimeSeries from 'app/core/time_series2';
|
||||
|
||||
import { DashboardModel } from '../../../../features/dashboard/state';
|
||||
import { createDashboardModelFixture } from '../../../../features/dashboard/state/__fixtures__/dashboardFixtures';
|
||||
import { graphDirective, GraphElement } from '../graph';
|
||||
import { GraphCtrl } from '../module';
|
||||
|
||||
@ -1337,7 +1337,7 @@ describe('grafanaGraph', () => {
|
||||
});
|
||||
|
||||
function getGraphElement({ canEdit, canMakeEditable }: { canEdit?: boolean; canMakeEditable?: boolean } = {}) {
|
||||
const dashboard = new DashboardModel({});
|
||||
const dashboard = createDashboardModelFixture({});
|
||||
dashboard.events.on = jest.fn();
|
||||
dashboard.meta.canEdit = canEdit;
|
||||
dashboard.meta.canMakeEditable = canMakeEditable;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { DataQuery } from '@grafana/data';
|
||||
import { Dashboard } from '@grafana/schema';
|
||||
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
|
||||
import { VariableModel } from 'app/features/variables/types';
|
||||
|
||||
import { DashboardAcl } from './acl';
|
||||
|
||||
@ -60,12 +60,10 @@ export interface AnnotationsPermissions {
|
||||
organization: AnnotationActions;
|
||||
}
|
||||
|
||||
export interface DashboardDataDTO {
|
||||
// FIXME: This should not override Dashboard types
|
||||
export interface DashboardDataDTO extends Dashboard {
|
||||
title: string;
|
||||
uid: string;
|
||||
templating: {
|
||||
list: VariableModel[];
|
||||
};
|
||||
panels?: any[];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user