diff --git a/src/module.ts b/src/module.ts index b897a3426..dcc56f0cc 100644 --- a/src/module.ts +++ b/src/module.ts @@ -2,6 +2,7 @@ import { AppPlugin } from '@grafana/data'; import { App } from 'Components/App'; import init from '@bsull/augurs'; import { linkConfigs } from 'services/extensions/links'; +import { init as initRuntimeDs } from 'services/datasource'; // eslint-disable-next-line no-console init().then(() => console.debug('Grafana ML initialized')); @@ -11,3 +12,5 @@ export const plugin = new AppPlugin<{}>().setRootPage(App); for (const linkConfig of linkConfigs) { plugin.configureExtensionLink(linkConfig); } + +initRuntimeDs(); diff --git a/src/services/datasource.ts b/src/services/datasource.ts new file mode 100644 index 000000000..206fb31e3 --- /dev/null +++ b/src/services/datasource.ts @@ -0,0 +1,57 @@ +import { DataQueryRequest, DataQueryResponse, TestDataSourceResponse } from '@grafana/data'; +import { getDataSourceSrv } from '@grafana/runtime'; +import { RuntimeDataSource, SceneObject, sceneUtils } from '@grafana/scenes'; +import { DataQuery } from '@grafana/schema'; +import { Observable, isObservable } from 'rxjs'; +import { getDataSource } from './scenes'; + +export const WRAPPED_LOKI_DS_UID = 'wrapped-loki-ds-uid'; + +type SceneDataQueryRequest = DataQueryRequest & { + scopedVars?: { __sceneObject?: { valueOf: () => SceneObject } }; +}; + +class WrappedLokiDatasource extends RuntimeDataSource { + constructor(pluginId: string, uid: string) { + super(pluginId, uid); + } + + query(request: SceneDataQueryRequest): Promise | Observable { + return new Observable((subscriber) => { + if (!request.scopedVars?.__sceneObject) { + throw new Error('Scene object not found in request'); + } + + getDataSourceSrv() + .get(getDataSource(request.scopedVars.__sceneObject.valueOf())) + .then((ds) => { + // override the target datasource to Loki + request.targets = request.targets.map((target) => { + target.datasource = ds; + return target; + }); + + // query the datasource and return either observable or promise + const dsResponse = ds.query(request); + if (isObservable(dsResponse)) { + dsResponse.subscribe(subscriber); + } else { + dsResponse.then((response) => { + subscriber.next(response); + subscriber.complete(); + }); + } + }); + }); + } + + testDatasource(): Promise { + return Promise.resolve({ status: 'success', message: 'Data source is working', title: 'Success' }); + } +} + +export function init() { + sceneUtils.registerRuntimeDataSource({ + dataSource: new WrappedLokiDatasource('wrapped-loki-ds', WRAPPED_LOKI_DS_UID), + }); +} diff --git a/src/services/panel.ts b/src/services/panel.ts index f02900da7..ef83932c4 100644 --- a/src/services/panel.ts +++ b/src/services/panel.ts @@ -2,8 +2,8 @@ import { DataFrame, FieldConfig, FieldMatcherID } from '@grafana/data'; import { FieldConfigOverridesBuilder, SceneDataTransformer, SceneQueryRunner } from '@grafana/scenes'; import { map, Observable } from 'rxjs'; import { LokiQuery } from './query'; -import { EXPLORATION_DS } from './variables'; import { HideSeriesConfig } from '@grafana/schema'; +import { WRAPPED_LOKI_DS_UID } from './datasource'; const UNKNOWN_LEVEL_LOGS = 'logs'; export function setLeverColorOverrides(overrides: FieldConfigOverridesBuilder) { @@ -86,7 +86,7 @@ export function getQueryRunner(query: LokiQuery) { if (query.legendFormat?.toLowerCase().includes('level')) { return new SceneDataTransformer({ $data: new SceneQueryRunner({ - datasource: EXPLORATION_DS, + datasource: { uid: WRAPPED_LOKI_DS_UID }, queries: [query], }), transformations: [sortLevelTransformation], @@ -94,7 +94,7 @@ export function getQueryRunner(query: LokiQuery) { } return new SceneQueryRunner({ - datasource: EXPLORATION_DS, + datasource: { uid: WRAPPED_LOKI_DS_UID }, queries: [query], }); } diff --git a/src/services/scenes.ts b/src/services/scenes.ts index 1ab905414..9e607d0aa 100644 --- a/src/services/scenes.ts +++ b/src/services/scenes.ts @@ -17,8 +17,8 @@ export function getUrlForValues(values: SceneObjectUrlValues) { return urlUtil.renderUrl(EXPLORATIONS_ROUTE, values); } -export function getDataSource(exploration: IndexScene) { - return sceneGraph.interpolate(exploration, VAR_DATASOURCE_EXPR); +export function getDataSource(sceneObject: SceneObject) { + return sceneGraph.interpolate(sceneObject, VAR_DATASOURCE_EXPR); } export function getQueryExpr(exploration: IndexScene) {