import { Observable } from 'rxjs'; import { DataQuery, DataQueryRequest, DataSourceApi, DataSourceRef, getDefaultTimeRange, LoadingState, PanelData, DataTopic, } from '@grafana/data'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { PanelModel } from 'app/features/dashboard/state/PanelModel'; import { QueryRunnerOptions } from 'app/features/query/state/PanelQueryRunner'; import { SHARED_DASHBOARD_QUERY } from './constants'; import { DashboardQuery } from './types'; export function isSharedDashboardQuery(datasource: string | DataSourceRef | DataSourceApi | null) { if (!datasource) { // default datasource return false; } if (typeof datasource === 'string') { return datasource === SHARED_DASHBOARD_QUERY; } if ('meta' in datasource) { return datasource.meta.name === SHARED_DASHBOARD_QUERY || datasource.uid === SHARED_DASHBOARD_QUERY; } return datasource.uid === SHARED_DASHBOARD_QUERY; } export function runSharedRequest(options: QueryRunnerOptions, query: DashboardQuery): Observable { return new Observable((subscriber) => { const dashboard = getDashboardSrv().getCurrent(); const listenToPanelId = getPanelIdFromQuery(options.queries); if (!listenToPanelId) { subscriber.next(getQueryError('Missing panel reference ID')); return undefined; } // Source panel might be contained in a collapsed row, in which // case we need to create a PanelModel let listenToPanel = dashboard?.getPanelById(listenToPanelId, true); if (!(listenToPanel instanceof PanelModel)) { listenToPanel = new PanelModel(listenToPanel); } if (!listenToPanel) { subscriber.next(getQueryError('Unknown Panel: ' + listenToPanelId)); return undefined; } const listenToRunner = listenToPanel.getQueryRunner(); const subscription = listenToRunner .getData({ withTransforms: Boolean(query?.withTransforms), withFieldConfig: false, }) .subscribe({ next: (data: PanelData) => { // Use annotation data for series if (query?.topic === DataTopic.Annotations) { data = { ...data, series: data.annotations ?? [], annotations: undefined, // remove annotations }; } subscriber.next(data); }, }); // If we are in fullscreen the other panel will not execute any queries // So we have to trigger it from here if ( (!listenToPanel.isInView && listenToPanel.refreshWhenInView) || dashboard?.otherPanelInFullscreen(listenToPanel) ) { const { datasource, targets } = listenToPanel; const modified = { ...options, datasource, panelId: listenToPanelId, queries: targets, }; listenToPanel.refreshWhenInView = false; listenToRunner.run(modified); } return () => { subscription.unsubscribe(); }; }); } function getPanelIdFromQuery(queries: DataQuery[]): number | undefined { if (!queries || !queries.length) { return undefined; } return (queries[0] as DashboardQuery).panelId; } function getQueryError(msg: string): PanelData { return { state: LoadingState.Error, series: [], request: {} as DataQueryRequest, error: { message: msg }, timeRange: getDefaultTimeRange(), }; }