mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* DashboardScene: Panel menu updates, adding explore action * DashboardScene: Panel menu updates, adding explore action * Initial test * Update * share modal * Update * rename * Update tests * Fix test * update * Fix tooltip wording * Update translation file * fix e2e * Extract ShareLinkTab component * rename to overlay --------- Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
177 lines
4.5 KiB
TypeScript
177 lines
4.5 KiB
TypeScript
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');
|
|
}
|