mirror of https://github.com/grafana/grafana.git
134 lines
4.6 KiB
TypeScript
134 lines
4.6 KiB
TypeScript
import { Unsubscribable } from 'rxjs';
|
|
|
|
import { SceneDataTransformer, SceneObjectBase, SceneObjectState, SceneQueryRunner, VizPanel } from '@grafana/scenes';
|
|
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/constants';
|
|
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
|
|
|
|
import {
|
|
findOriginalVizPanelByKey,
|
|
getDashboardSceneFor,
|
|
getLibraryPanelBehavior,
|
|
getQueryRunnerFor,
|
|
getVizPanelKeyForPanelId,
|
|
} from '../utils/utils';
|
|
|
|
import { DashboardScene } from './DashboardScene';
|
|
import { LibraryPanelBehaviorState } from './LibraryPanelBehavior';
|
|
|
|
interface DashboardDatasourceBehaviourState extends SceneObjectState {}
|
|
|
|
export class DashboardDatasourceBehaviour extends SceneObjectBase<DashboardDatasourceBehaviourState> {
|
|
private prevRequestId: string | undefined;
|
|
public constructor(state: DashboardDatasourceBehaviourState) {
|
|
super(state);
|
|
|
|
this.addActivationHandler(() => this._activationHandler());
|
|
}
|
|
|
|
private _activationHandler() {
|
|
const queryRunner = this.parent;
|
|
let libraryPanelSub: Unsubscribable;
|
|
let transformerSub: Unsubscribable;
|
|
let dashboard: DashboardScene;
|
|
if (!(queryRunner instanceof SceneQueryRunner)) {
|
|
throw new Error('DashboardDatasourceBehaviour must be attached to a SceneQueryRunner');
|
|
}
|
|
|
|
if (!this.containsDashboardDSQueries(queryRunner)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
dashboard = getDashboardSceneFor(queryRunner);
|
|
} catch {
|
|
return;
|
|
}
|
|
|
|
const dashboardQuery = queryRunner.state.queries.find((query) => query.panelId !== undefined);
|
|
|
|
if (!dashboardQuery) {
|
|
return;
|
|
}
|
|
|
|
// find the source panel referenced in the the dashboard ds query
|
|
const panelId = dashboardQuery.panelId;
|
|
const vizKey = getVizPanelKeyForPanelId(panelId);
|
|
// We're trying to find the original panel, not a cloned one, since `panelId` alone cannot resolve clones
|
|
const sourcePanel = findOriginalVizPanelByKey(dashboard, vizKey);
|
|
|
|
if (!(sourcePanel instanceof VizPanel)) {
|
|
return;
|
|
}
|
|
|
|
//check if the source panel is a library panel and wait for it to load
|
|
const libraryPanelBehaviour = getLibraryPanelBehavior(sourcePanel);
|
|
if (libraryPanelBehaviour && !libraryPanelBehaviour.state.isLoaded) {
|
|
libraryPanelSub = libraryPanelBehaviour.subscribeToState((newLibPanel) => {
|
|
this.handleLibPanelStateUpdates(newLibPanel, queryRunner, sourcePanel);
|
|
});
|
|
return;
|
|
}
|
|
|
|
const sourcePanelQueryRunner = getQueryRunnerFor(sourcePanel);
|
|
|
|
if (!sourcePanelQueryRunner) {
|
|
throw new Error('Could not find SceneQueryRunner for panel');
|
|
}
|
|
|
|
const dataTransformer = sourcePanelQueryRunner.parent;
|
|
|
|
if (dataTransformer instanceof SceneDataTransformer && dataTransformer.state.transformations.length) {
|
|
// in mixed DS scenario we complete the observable and merge data, so on a variable change
|
|
// the data transformer will emit but there will be no subscription and thus not visual update
|
|
// on the panel. Similar thing happens when going to edit mode and back, where we unsubscribe and
|
|
// since we never re-run the query, only reprocess the transformations, the panel will not update.
|
|
transformerSub = dataTransformer.subscribeToState((newState, oldState) => {
|
|
if (newState.data !== oldState.data) {
|
|
queryRunner.runQueries();
|
|
}
|
|
});
|
|
}
|
|
|
|
if (this.prevRequestId && this.prevRequestId !== sourcePanelQueryRunner.state.data?.request?.requestId) {
|
|
queryRunner.runQueries();
|
|
}
|
|
|
|
return () => {
|
|
this.prevRequestId = sourcePanelQueryRunner?.state.data?.request?.requestId;
|
|
if (libraryPanelSub) {
|
|
libraryPanelSub.unsubscribe();
|
|
}
|
|
|
|
if (transformerSub) {
|
|
transformerSub.unsubscribe();
|
|
}
|
|
};
|
|
}
|
|
|
|
private containsDashboardDSQueries(queryRunner: SceneQueryRunner): boolean {
|
|
if (queryRunner.state.datasource?.uid === SHARED_DASHBOARD_QUERY) {
|
|
return true;
|
|
}
|
|
|
|
return (
|
|
queryRunner.state.datasource?.uid === MIXED_DATASOURCE_NAME &&
|
|
queryRunner.state.queries.some((query) => query.datasource?.uid === SHARED_DASHBOARD_QUERY)
|
|
);
|
|
}
|
|
|
|
private handleLibPanelStateUpdates(
|
|
newLibPanel: LibraryPanelBehaviorState,
|
|
dashboardDsQueryRunner: SceneQueryRunner,
|
|
sourcePanel: VizPanel
|
|
) {
|
|
if (newLibPanel && newLibPanel?.isLoaded) {
|
|
const libPanelQueryRunner = getQueryRunnerFor(sourcePanel);
|
|
|
|
if (!(libPanelQueryRunner instanceof SceneQueryRunner)) {
|
|
throw new Error('Could not find SceneQueryRunner for library panel');
|
|
}
|
|
dashboardDsQueryRunner.runQueries();
|
|
}
|
|
}
|
|
}
|