The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/dashboard-scene/utils/utils.ts

176 lines
4.5 KiB

import { UrlQueryMap, urlUtil } from '@grafana/data';
import { config, locationSearchToObject } from '@grafana/runtime';
import {
MultiValueVariable,
SceneDataTransformer,
sceneGraph,
SceneObject,
SceneQueryRunner,
VizPanel,
} from '@grafana/scenes';
import { DashboardScene } from '../scene/DashboardScene';
export function getVizPanelKeyForPanelId(panelId: number) {
return `panel-${panelId}`;
}
export function getPanelIdForVizPanel(panel: SceneObject): number {
return parseInt(panel.state.key!.replace('panel-', ''), 10);
}
/**
* This will also try lookup based on panelId
*/
export function findVizPanelByKey(scene: SceneObject, key: string | undefined): VizPanel | null {
if (!key) {
return null;
}
const panel = findVizPanelInternal(scene, key);
if (panel) {
return panel;
}
// Also try to find by panel id
const id = parseInt(key, 10);
if (isNaN(id)) {
return null;
}
return findVizPanelInternal(scene, getVizPanelKeyForPanelId(id));
}
function findVizPanelInternal(scene: SceneObject, key: string | undefined): VizPanel | null {
if (!key) {
return null;
}
const panel = sceneGraph.findObject(scene, (obj) => obj.state.key === key);
if (panel) {
if (panel instanceof VizPanel) {
return panel;
} else {
throw new Error(`Found panel with key ${key} but it was not a VizPanel`);
}
}
return null;
}
/**
* Force re-render children. This is useful in some edge case scenarios when
* children deep down the scene graph needs to be re-rendered when some parent state change.
*
* Example could be isEditing bool flag or a layout IsDraggable state flag.
*
* @param model The model whose children should be re-rendered. It does not force render this model, only the children.
* @param recursive if it should keep force rendering down to leaf nodess
*/
export function forceRenderChildren(model: SceneObject, recursive?: boolean) {
model.forEachChild((child) => {
if (!child.isActive) {
return;
}
child.forceRender();
forceRenderChildren(child, recursive);
});
}
export interface DashboardUrlOptions {
uid?: string;
subPath?: string;
updateQuery?: UrlQueryMap;
/** Set to location.search to preserve current params */
currentQueryParams: string;
/** * Returns solo panel route instead */
soloRoute?: boolean;
/** return render url */
render?: boolean;
/** Return an absolute URL */
absolute?: boolean;
// Add tz to query params
timeZone?: string;
}
export function getDashboardUrl(options: DashboardUrlOptions) {
let path = `/scenes/dashboard/${options.uid}${options.subPath ?? ''}`;
if (options.soloRoute) {
path = `/d-solo/${options.uid}${options.subPath ?? ''}`;
}
if (options.render) {
path = '/render' + path;
options.updateQuery = {
...options.updateQuery,
width: 1000,
height: 500,
tz: options.timeZone,
};
}
const params = options.currentQueryParams ? locationSearchToObject(options.currentQueryParams) : {};
if (options.updateQuery) {
for (const key of Object.keys(options.updateQuery)) {
// removing params with null | undefined
if (options.updateQuery[key] === null || options.updateQuery[key] === undefined) {
delete params[key];
} else {
params[key] = options.updateQuery[key];
}
}
}
const relativeUrl = urlUtil.renderUrl(path, params);
if (options.absolute) {
return config.appUrl + relativeUrl.slice(1);
}
return relativeUrl;
}
export function getMultiVariableValues(variable: MultiValueVariable) {
const { value, text, options } = variable.state;
if (variable.hasAllValue()) {
return {
values: options.map((o) => o.value),
texts: options.map((o) => o.label),
};
}
return {
values: Array.isArray(value) ? value : [value],
texts: Array.isArray(text) ? text : [text],
};
}
export function getQueryRunnerFor(sceneObject: SceneObject | undefined): SceneQueryRunner | undefined {
if (!sceneObject) {
return undefined;
}
if (sceneObject.state.$data instanceof SceneQueryRunner) {
return sceneObject.state.$data;
}
if (sceneObject.state.$data instanceof SceneDataTransformer) {
return getQueryRunnerFor(sceneObject.state.$data);
}
return undefined;
}
export function getDashboardSceneFor(sceneObject: SceneObject): DashboardScene {
const root = sceneObject.getRoot();
if (root instanceof DashboardScene) {
return root;
}
throw new Error('SceneObject root is not a DashboardScene');
}