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/services/PublicDashboardDataSource.ts

167 lines
4.8 KiB

import { catchError, from, Observable, of, switchMap } from 'rxjs';
import {
AnnotationQuery,
DataQuery,
DataQueryRequest,
DataQueryResponse,
TestDataSourceResponse,
DataSourceApi,
DataSourceJsonData,
DataSourcePluginMeta,
DataSourceRef,
toDataFrame,
} from '@grafana/data';
import { BackendDataSourceResponse, getBackendSrv, toDataQueryResponse } from '@grafana/runtime';
import { GrafanaQueryType } from '../../../plugins/datasource/grafana/types';
import { MIXED_DATASOURCE_NAME } from '../../../plugins/datasource/mixed/MixedDataSource';
import { GRAFANA_DATASOURCE_NAME } from '../../alerting/unified/utils/datasource';
export const PUBLIC_DATASOURCE = '-- Public --';
export const DEFAULT_INTERVAL = '1min';
export class PublicDashboardDataSource extends DataSourceApi<DataQuery, DataSourceJsonData, {}> {
constructor(datasource: DataSourceRef | string | DataSourceApi | null) {
let meta = {} as DataSourcePluginMeta;
if (PublicDashboardDataSource.isMixedDatasource(datasource)) {
meta.mixed = true;
}
super({
name: 'public-ds',
id: 0,
type: 'public-ds',
meta,
uid: PublicDashboardDataSource.resolveUid(datasource),
jsonData: {},
access: 'proxy',
readOnly: true,
});
this.interval = PublicDashboardDataSource.resolveInterval(datasource);
this.annotations = {
prepareQuery(anno: AnnotationQuery): DataQuery | undefined {
return { ...anno, queryType: GrafanaQueryType.Annotations, refId: 'anno' };
},
};
}
/**
* Get the datasource uid based on the many types a datasource can be.
*/
private static resolveUid(datasource: DataSourceRef | string | DataSourceApi | null): string {
if (typeof datasource === 'string') {
return datasource;
}
return datasource?.uid ?? PUBLIC_DATASOURCE;
}
private static isMixedDatasource(datasource: DataSourceRef | string | DataSourceApi | null): boolean {
if (typeof datasource === 'string' || datasource == null) {
return false;
}
return datasource?.uid === MIXED_DATASOURCE_NAME;
}
private static resolveInterval(datasource: DataSourceRef | string | DataSourceApi | null): string {
if (typeof datasource === 'string' || datasource == null) {
return DEFAULT_INTERVAL;
}
const interval = 'interval' in datasource ? datasource.interval : undefined;
return interval ?? DEFAULT_INTERVAL;
}
/**
* Ideally final -- any other implementation may not work as expected
*/
query(request: DataQueryRequest<DataQuery>): Observable<DataQueryResponse> {
const {
intervalMs,
maxDataPoints,
requestId,
publicDashboardAccessToken,
panelId,
queryCachingTTL,
range: { from: fromRange, to: toRange },
} = request;
let queries: DataQuery[];
// Return early if no queries exist
if (!request.targets.length) {
return of({ data: [] });
}
// Its an annotations query
// Currently, annotations requests come in one at a time, so there will only be one target
const target = request.targets[0];
if (target.queryType === GrafanaQueryType.Annotations) {
if (target?.datasource?.uid === GRAFANA_DATASOURCE_NAME) {
return from(this.getAnnotations(request));
}
return of({ data: [] });
}
// Its a datasource query
else {
const body = {
intervalMs,
maxDataPoints,
queryCachingTTL,
timeRange: {
from: fromRange.valueOf().toString(),
to: toRange.valueOf().toString(),
timezone: this.getBrowserTimezone(),
},
};
return getBackendSrv()
.fetch<BackendDataSourceResponse>({
url: `/api/public/dashboards/${publicDashboardAccessToken}/panels/${panelId}/query`,
method: 'POST',
data: body,
requestId,
})
.pipe(
switchMap((raw) => {
return of(toDataQueryResponse(raw, queries));
}),
catchError((err) => {
return of(toDataQueryResponse(err));
})
);
}
}
async getAnnotations(request: DataQueryRequest<DataQuery>): Promise<DataQueryResponse> {
const {
publicDashboardAccessToken: accessToken,
range: { to, from },
} = request;
const params = {
from: from.valueOf(),
to: to.valueOf(),
};
const annotations = accessToken
? await getBackendSrv().get(`/api/public/dashboards/${accessToken}/annotations`, params)
: [];
return { data: [toDataFrame(annotations)] };
}
testDatasource(): Promise<TestDataSourceResponse> {
return Promise.resolve({ message: '', status: '' });
}
// Try to get the browser timezone otherwise return blank
getBrowserTimezone(): string {
return window.Intl?.DateTimeFormat().resolvedOptions()?.timeZone || '';
}
}