|
@@ -4,6 +4,7 @@ import { Subject, Unsubscribable, PartialObserver } from 'rxjs';
|
|
|
|
|
|
|
|
// Services & Utils
|
|
// Services & Utils
|
|
|
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
|
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
|
|
|
|
+import { getBackendSrv } from 'app/core/services/backend_srv';
|
|
|
import kbn from 'app/core/utils/kbn';
|
|
import kbn from 'app/core/utils/kbn';
|
|
|
import templateSrv from 'app/features/templating/template_srv';
|
|
import templateSrv from 'app/features/templating/template_srv';
|
|
|
|
|
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
DataQuery,
|
|
DataQuery,
|
|
|
TimeRange,
|
|
TimeRange,
|
|
|
ScopedVars,
|
|
ScopedVars,
|
|
|
- DataRequestInfo,
|
|
|
|
|
|
|
+ DataQueryRequest,
|
|
|
SeriesData,
|
|
SeriesData,
|
|
|
DataQueryError,
|
|
DataQueryError,
|
|
|
toLegacyResponseData,
|
|
toLegacyResponseData,
|
|
@@ -25,8 +26,7 @@ import {
|
|
|
} from '@grafana/ui';
|
|
} from '@grafana/ui';
|
|
|
|
|
|
|
|
export interface QueryRunnerOptions<TQuery extends DataQuery = DataQuery> {
|
|
export interface QueryRunnerOptions<TQuery extends DataQuery = DataQuery> {
|
|
|
- ds?: DataSourceApi<TQuery>; // if they already have the datasource, don't look it up
|
|
|
|
|
- datasource: string | null;
|
|
|
|
|
|
|
+ datasource: string | DataSourceApi<TQuery>;
|
|
|
queries: TQuery[];
|
|
queries: TQuery[];
|
|
|
panelId: number;
|
|
panelId: number;
|
|
|
dashboardId?: number;
|
|
dashboardId?: number;
|
|
@@ -47,6 +47,11 @@ export enum PanelQueryRunnerFormat {
|
|
|
both = 'both',
|
|
both = 'both',
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+let counter = 100;
|
|
|
|
|
+function getNextRequestId() {
|
|
|
|
|
+ return 'Q' + counter++;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
export class PanelQueryRunner {
|
|
export class PanelQueryRunner {
|
|
|
private subject?: Subject<PanelData>;
|
|
private subject?: Subject<PanelData>;
|
|
|
|
|
|
|
@@ -106,12 +111,12 @@ export class PanelQueryRunner {
|
|
|
delayStateNotification,
|
|
delayStateNotification,
|
|
|
} = options;
|
|
} = options;
|
|
|
|
|
|
|
|
- const request: DataRequestInfo = {
|
|
|
|
|
|
|
+ const request: DataQueryRequest = {
|
|
|
|
|
+ requestId: getNextRequestId(),
|
|
|
timezone,
|
|
timezone,
|
|
|
panelId,
|
|
panelId,
|
|
|
dashboardId,
|
|
dashboardId,
|
|
|
range: timeRange,
|
|
range: timeRange,
|
|
|
- rangeRaw: timeRange.raw,
|
|
|
|
|
timeInfo,
|
|
timeInfo,
|
|
|
interval: '',
|
|
interval: '',
|
|
|
intervalMs: 0,
|
|
intervalMs: 0,
|
|
@@ -121,6 +126,8 @@ export class PanelQueryRunner {
|
|
|
cacheTimeout,
|
|
cacheTimeout,
|
|
|
startTime: Date.now(),
|
|
startTime: Date.now(),
|
|
|
};
|
|
};
|
|
|
|
|
+ // Deprecated
|
|
|
|
|
+ (request as any).rangeRaw = timeRange.raw;
|
|
|
|
|
|
|
|
if (!queries) {
|
|
if (!queries) {
|
|
|
return this.publishUpdate({
|
|
return this.publishUpdate({
|
|
@@ -134,7 +141,10 @@ export class PanelQueryRunner {
|
|
|
let loadingStateTimeoutId = 0;
|
|
let loadingStateTimeoutId = 0;
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
- const ds = options.ds ? options.ds : await getDatasourceSrv().get(datasource, request.scopedVars);
|
|
|
|
|
|
|
+ const ds =
|
|
|
|
|
+ datasource && (datasource as any).query
|
|
|
|
|
+ ? (datasource as DataSourceApi)
|
|
|
|
|
+ : await getDatasourceSrv().get(datasource as string, request.scopedVars);
|
|
|
|
|
|
|
|
const lowerIntervalLimit = minInterval ? templateSrv.replace(minInterval, request.scopedVars) : ds.interval;
|
|
const lowerIntervalLimit = minInterval ? templateSrv.replace(minInterval, request.scopedVars) : ds.interval;
|
|
|
const norm = kbn.calculateInterval(timeRange, widthPixels, lowerIntervalLimit);
|
|
const norm = kbn.calculateInterval(timeRange, widthPixels, lowerIntervalLimit);
|
|
@@ -157,6 +167,11 @@ export class PanelQueryRunner {
|
|
|
const resp = await ds.query(request);
|
|
const resp = await ds.query(request);
|
|
|
request.endTime = Date.now();
|
|
request.endTime = Date.now();
|
|
|
|
|
|
|
|
|
|
+ // Make sure we send something back -- called run() w/o subscribe!
|
|
|
|
|
+ if (!(this.sendSeries || this.sendLegacy)) {
|
|
|
|
|
+ this.sendSeries = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// Make sure the response is in a supported format
|
|
// Make sure the response is in a supported format
|
|
|
const series = this.sendSeries ? getProcessedSeriesData(resp.data) : [];
|
|
const series = this.sendSeries ? getProcessedSeriesData(resp.data) : [];
|
|
|
const legacy = this.sendLegacy
|
|
const legacy = this.sendLegacy
|
|
@@ -214,6 +229,22 @@ export class PanelQueryRunner {
|
|
|
|
|
|
|
|
return this.data;
|
|
return this.data;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Called when the panel is closed
|
|
|
|
|
+ */
|
|
|
|
|
+ destroy() {
|
|
|
|
|
+ // Tell anyone listening that we are done
|
|
|
|
|
+ if (this.subject) {
|
|
|
|
|
+ this.subject.complete();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // If there are open HTTP requests, close them
|
|
|
|
|
+ const { request } = this.data;
|
|
|
|
|
+ if (request && request.requestId) {
|
|
|
|
|
+ getBackendSrv().resolveCancelerIfExists(request.requestId);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|