mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Convert internal grafana datasource from angular to react (#27870)
This commit is contained in:
20
public/app/plugins/datasource/grafana/annotation_ctrl.ts
Normal file
20
public/app/plugins/datasource/grafana/annotation_ctrl.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { GrafanaAnnotationType } from './types';
|
||||
|
||||
export const annotationTypes: Array<SelectableValue<GrafanaAnnotationType>> = [
|
||||
{ text: 'Dashboard', value: GrafanaAnnotationType.Dashboard },
|
||||
{ text: 'Tags', value: GrafanaAnnotationType.Tags },
|
||||
];
|
||||
|
||||
export class GrafanaAnnotationsQueryCtrl {
|
||||
annotation: any;
|
||||
|
||||
types = annotationTypes;
|
||||
|
||||
constructor() {
|
||||
this.annotation.type = this.annotation.type || GrafanaAnnotationType.Tags;
|
||||
this.annotation.limit = this.annotation.limit || 100;
|
||||
}
|
||||
|
||||
static templateUrl = 'partials/annotations.editor.html';
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import defaults from 'lodash/defaults';
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { InlineField, Select } from '@grafana/ui';
|
||||
import { QueryEditorProps, SelectableValue } from '@grafana/data';
|
||||
import { GrafanaDatasource } from '../datasource';
|
||||
import { defaultQuery, GrafanaQuery, GrafanaQueryType } from '../types';
|
||||
|
||||
type Props = QueryEditorProps<GrafanaDatasource, GrafanaQuery>;
|
||||
|
||||
export class QueryEditor extends PureComponent<Props> {
|
||||
queryTypes: Array<SelectableValue<GrafanaQueryType>> = [
|
||||
{
|
||||
label: 'Random Walk',
|
||||
value: GrafanaQueryType.RandomWalk,
|
||||
description: 'Random signal within the selected time rage',
|
||||
},
|
||||
];
|
||||
|
||||
onQueryTypeChange = (sel: SelectableValue<GrafanaQueryType>) => {
|
||||
const { onChange, query, onRunQuery } = this.props;
|
||||
onChange({ ...query, queryType: sel.value! });
|
||||
onRunQuery();
|
||||
};
|
||||
|
||||
render() {
|
||||
const query = defaults(this.props.query, defaultQuery);
|
||||
return (
|
||||
<div className="gf-form">
|
||||
<InlineField label="Query type" grow={true}>
|
||||
<Select
|
||||
options={this.queryTypes}
|
||||
value={this.queryTypes.find(v => v.value === query.queryType) || this.queryTypes[0]}
|
||||
onChange={this.onQueryTypeChange}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
import { DataSourceInstanceSettings, dateTime } from '@grafana/data';
|
||||
import { DataSourceInstanceSettings, dateTime, AnnotationQueryRequest } from '@grafana/data';
|
||||
|
||||
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
||||
import { GrafanaDatasource } from '../datasource';
|
||||
import { GrafanaDatasource } from './datasource';
|
||||
import { GrafanaQuery, GrafanaAnnotationQuery, GrafanaAnnotationType } from './types';
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...((jest.requireActual('@grafana/runtime') as unknown) as object),
|
||||
getBackendSrv: () => backendSrv,
|
||||
}));
|
||||
|
||||
jest.mock('app/features/templating/template_srv', () => ({
|
||||
replace: (val: string) => {
|
||||
return val.replace('$var2', 'replaced__delimiter__replaced2').replace('$var', 'replaced');
|
||||
},
|
||||
getTemplateSrv: () => ({
|
||||
replace: (val: string) => {
|
||||
return val.replace('$var2', 'replaced__delimiter__replaced2').replace('$var', 'replaced');
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('grafana data source', () => {
|
||||
@@ -61,7 +61,7 @@ describe('grafana data source', () => {
|
||||
describe('with type dashboard', () => {
|
||||
const options = setupAnnotationQueryOptions(
|
||||
{
|
||||
type: 'dashboard',
|
||||
type: GrafanaAnnotationType.Dashboard,
|
||||
tags: ['tag1'],
|
||||
},
|
||||
{ id: 1 }
|
||||
@@ -78,8 +78,8 @@ describe('grafana data source', () => {
|
||||
});
|
||||
});
|
||||
|
||||
function setupAnnotationQueryOptions(annotation: { tags: string[]; type?: string }, dashboard?: { id: number }) {
|
||||
return {
|
||||
function setupAnnotationQueryOptions(annotation: Partial<GrafanaAnnotationQuery>, dashboard?: { id: number }) {
|
||||
return ({
|
||||
annotation,
|
||||
dashboard,
|
||||
range: {
|
||||
@@ -87,5 +87,5 @@ function setupAnnotationQueryOptions(annotation: { tags: string[]; type?: string
|
||||
to: dateTime(1432288401),
|
||||
},
|
||||
rangeRaw: { from: 'now-24h', to: 'now' },
|
||||
};
|
||||
} as unknown) as AnnotationQueryRequest<GrafanaQuery>;
|
||||
}
|
||||
@@ -1,55 +1,66 @@
|
||||
import _ from 'lodash';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { DataSourceApi, DataSourceInstanceSettings } from '@grafana/data';
|
||||
import {
|
||||
AnnotationEvent,
|
||||
AnnotationQueryRequest,
|
||||
DataQueryRequest,
|
||||
DataQueryResponse,
|
||||
DataSourceApi,
|
||||
DataSourceInstanceSettings,
|
||||
} from '@grafana/data';
|
||||
|
||||
import templateSrv from 'app/features/templating/template_srv';
|
||||
import { GrafanaQuery, GrafanaAnnotationQuery, GrafanaAnnotationType } from './types';
|
||||
import { getBackendSrv, getTemplateSrv, toDataQueryResponse } from '@grafana/runtime';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
|
||||
class GrafanaDatasource extends DataSourceApi<any> {
|
||||
/** @ngInject */
|
||||
export class GrafanaDatasource extends DataSourceApi<GrafanaQuery> {
|
||||
constructor(instanceSettings: DataSourceInstanceSettings) {
|
||||
super(instanceSettings);
|
||||
}
|
||||
|
||||
query(options: any) {
|
||||
query(request: DataQueryRequest<GrafanaQuery>): Observable<DataQueryResponse> {
|
||||
const { intervalMs, maxDataPoints, range, requestId } = request;
|
||||
|
||||
// Yes, this implementaiton ignores multiple targets! But that matches exisitng behavior
|
||||
const params: Record<string, any> = {
|
||||
intervalMs,
|
||||
maxDataPoints,
|
||||
from: range.from.valueOf(),
|
||||
to: range.to.valueOf(),
|
||||
};
|
||||
|
||||
return getBackendSrv()
|
||||
.get('/api/tsdb/testdata/random-walk', {
|
||||
from: options.range.from.valueOf(),
|
||||
to: options.range.to.valueOf(),
|
||||
intervalMs: options.intervalMs,
|
||||
maxDataPoints: options.maxDataPoints,
|
||||
.fetch({
|
||||
url: '/api/tsdb/testdata/random-walk',
|
||||
method: 'GET',
|
||||
params,
|
||||
requestId,
|
||||
})
|
||||
.then((res: any) => {
|
||||
const data: any[] = [];
|
||||
|
||||
if (res.results) {
|
||||
_.forEach(res.results, queryRes => {
|
||||
for (const series of queryRes.series) {
|
||||
data.push({
|
||||
target: series.name,
|
||||
datapoints: series.points,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return { data: data };
|
||||
});
|
||||
.pipe(
|
||||
map((rsp: any) => {
|
||||
return toDataQueryResponse(rsp);
|
||||
}),
|
||||
catchError(err => {
|
||||
return of(toDataQueryResponse(err));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
metricFindQuery(options: any) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
annotationQuery(options: any) {
|
||||
annotationQuery(options: AnnotationQueryRequest<GrafanaQuery>): Promise<AnnotationEvent[]> {
|
||||
const templateSrv = getTemplateSrv();
|
||||
const annotation = (options.annotation as unknown) as GrafanaAnnotationQuery;
|
||||
const params: any = {
|
||||
from: options.range.from.valueOf(),
|
||||
to: options.range.to.valueOf(),
|
||||
limit: options.annotation.limit,
|
||||
tags: options.annotation.tags,
|
||||
matchAny: options.annotation.matchAny,
|
||||
limit: annotation.limit,
|
||||
tags: annotation.tags,
|
||||
matchAny: annotation.matchAny,
|
||||
};
|
||||
|
||||
if (options.annotation.type === 'dashboard') {
|
||||
if (annotation.type === GrafanaAnnotationType.Dashboard) {
|
||||
// if no dashboard id yet return
|
||||
if (!options.dashboard.id) {
|
||||
return Promise.resolve([]);
|
||||
@@ -60,7 +71,7 @@ class GrafanaDatasource extends DataSourceApi<any> {
|
||||
delete params.tags;
|
||||
} else {
|
||||
// require at least one tag
|
||||
if (!_.isArray(options.annotation.tags) || options.annotation.tags.length === 0) {
|
||||
if (!Array.isArray(annotation.tags) || annotation.tags.length === 0) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
const delimiter = '__delimiter__';
|
||||
@@ -83,7 +94,7 @@ class GrafanaDatasource extends DataSourceApi<any> {
|
||||
return getBackendSrv().get(
|
||||
'/api/annotations',
|
||||
params,
|
||||
`grafana-data-source-annotations-${options.annotation.name}-${options.dashboard?.id}`
|
||||
`grafana-data-source-annotations-${annotation.name}-${options.dashboard?.id}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -91,5 +102,3 @@ class GrafanaDatasource extends DataSourceApi<any> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
export { GrafanaDatasource };
|
||||
|
||||
@@ -1,29 +1,9 @@
|
||||
import { DataSourcePlugin } from '@grafana/data';
|
||||
import { GrafanaDatasource } from './datasource';
|
||||
import { QueryCtrl } from 'app/plugins/sdk';
|
||||
import { QueryEditor } from './components/QueryEditor';
|
||||
import { GrafanaQuery } from './types';
|
||||
import { GrafanaAnnotationsQueryCtrl } from './annotation_ctrl';
|
||||
|
||||
class GrafanaQueryCtrl extends QueryCtrl {
|
||||
static templateUrl = 'partials/query.editor.html';
|
||||
}
|
||||
|
||||
class GrafanaAnnotationsQueryCtrl {
|
||||
annotation: any;
|
||||
|
||||
types = [
|
||||
{ text: 'Dashboard', value: 'dashboard' },
|
||||
{ text: 'Tags', value: 'tags' },
|
||||
];
|
||||
|
||||
constructor() {
|
||||
this.annotation.type = this.annotation.type || 'tags';
|
||||
this.annotation.limit = this.annotation.limit || 100;
|
||||
}
|
||||
|
||||
static templateUrl = 'partials/annotations.editor.html';
|
||||
}
|
||||
|
||||
export {
|
||||
GrafanaDatasource,
|
||||
GrafanaDatasource as Datasource,
|
||||
GrafanaQueryCtrl as QueryCtrl,
|
||||
GrafanaAnnotationsQueryCtrl as AnnotationsQueryCtrl,
|
||||
};
|
||||
export const plugin = new DataSourcePlugin<GrafanaDatasource, GrafanaQuery>(GrafanaDatasource)
|
||||
.setQueryEditor(QueryEditor)
|
||||
.setAnnotationQueryCtrl(GrafanaAnnotationsQueryCtrl);
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<query-editor-row query-ctrl="ctrl" can-collapse="false">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label">Test data: random walk</label>
|
||||
</div>
|
||||
|
||||
<div class="gf-form gf-form--grow">
|
||||
<div class="gf-form-label gf-form-label--grow"></div>
|
||||
</div>
|
||||
</div>
|
||||
</query-editor-row>
|
||||
36
public/app/plugins/datasource/grafana/types.ts
Normal file
36
public/app/plugins/datasource/grafana/types.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { AnnotationQuery, DataQuery } from '@grafana/data';
|
||||
|
||||
//----------------------------------------------
|
||||
// Query
|
||||
//----------------------------------------------
|
||||
|
||||
export enum GrafanaQueryType {
|
||||
RandomWalk = 'randomWalk',
|
||||
RandomStream = 'randomStream',
|
||||
HostMetrics = 'hostmetrics',
|
||||
}
|
||||
|
||||
export interface GrafanaQuery extends DataQuery {
|
||||
queryType: GrafanaQueryType; // RandomWalk by default
|
||||
}
|
||||
|
||||
export const defaultQuery: GrafanaQuery = {
|
||||
refId: 'A',
|
||||
queryType: GrafanaQueryType.RandomWalk,
|
||||
};
|
||||
|
||||
//----------------------------------------------
|
||||
// Annotations
|
||||
//----------------------------------------------
|
||||
|
||||
export enum GrafanaAnnotationType {
|
||||
Dashboard = 'dashboard',
|
||||
Tags = 'tags',
|
||||
}
|
||||
|
||||
export interface GrafanaAnnotationQuery extends AnnotationQuery<GrafanaQuery> {
|
||||
type: GrafanaAnnotationType; // tags
|
||||
limit: number; // 100
|
||||
tags?: string[];
|
||||
matchAny?: boolean; // By default Grafana only shows annotations that match all tags in the query. Enabling this returns annotations that match any of the tags in the query.
|
||||
}
|
||||
Reference in New Issue
Block a user