mirror of
https://github.com/grafana/grafana.git
synced 2025-09-27 04:23:51 +08:00
ReactMigration: Migrate Graphite config page to React (#20444)
* adding configeditor * fix method signature and add state for metrictankhelper * fix onChangeHandler * prettier fix * remove config and fix autoversion * adding optional parameter to make this build * set default version if none specified * Graphite: removed version detection
This commit is contained in:

committed by
Torkel Ödegaard

parent
02d7d00560
commit
c5ff7fa580
@ -261,7 +261,7 @@ export abstract class DataSourceApi<
|
|||||||
*/
|
*/
|
||||||
languageProvider?: any;
|
languageProvider?: any;
|
||||||
|
|
||||||
getVersion?(): Promise<string>;
|
getVersion?(optionalOptions?: any): Promise<string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can be optionally implemented to allow datasource to be a source of annotations for dashboard. To be visible
|
* Can be optionally implemented to allow datasource to be a source of annotations for dashboard. To be visible
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
import DatasourceSrv from 'app/features/plugins/datasource_srv';
|
|
||||||
import { GraphiteType } from './types';
|
|
||||||
|
|
||||||
export class GraphiteConfigCtrl {
|
|
||||||
static templateUrl = 'public/app/plugins/datasource/graphite/partials/config.html';
|
|
||||||
datasourceSrv: any;
|
|
||||||
current: any;
|
|
||||||
graphiteTypes: any;
|
|
||||||
|
|
||||||
/** @ngInject */
|
|
||||||
constructor($scope: any, datasourceSrv: DatasourceSrv) {
|
|
||||||
this.datasourceSrv = datasourceSrv;
|
|
||||||
this.current.jsonData = this.current.jsonData || {};
|
|
||||||
this.current.jsonData.graphiteVersion = this.current.jsonData.graphiteVersion || '0.9';
|
|
||||||
this.current.jsonData.graphiteType = this.current.jsonData.graphiteType || GraphiteType.Default;
|
|
||||||
this.autoDetectGraphiteVersion();
|
|
||||||
this.graphiteTypes = Object.keys(GraphiteType).map((key: string) => ({
|
|
||||||
name: key,
|
|
||||||
value: (GraphiteType as any)[key],
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
autoDetectGraphiteVersion() {
|
|
||||||
if (!this.current.id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.datasourceSrv
|
|
||||||
.loadDatasource(this.current.name)
|
|
||||||
.then((ds: any) => {
|
|
||||||
return ds.getVersion();
|
|
||||||
})
|
|
||||||
.then((version: any) => {
|
|
||||||
if (!version) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.graphiteVersions.push({ name: version, value: version });
|
|
||||||
this.current.jsonData.graphiteVersion = version;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
graphiteVersions = [
|
|
||||||
{ name: '0.9.x', value: '0.9' },
|
|
||||||
{ name: '1.0.x', value: '1.0' },
|
|
||||||
{ name: '1.1.x', value: '1.1' },
|
|
||||||
];
|
|
||||||
}
|
|
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { DataSourceHttpSettings } from '@grafana/ui';
|
||||||
|
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
|
||||||
|
import { GraphiteDetails } from './GraphiteDetails';
|
||||||
|
import { GraphiteOptions } from '../types';
|
||||||
|
|
||||||
|
export const ConfigEditor = (props: DataSourcePluginOptionsEditorProps<GraphiteOptions>) => {
|
||||||
|
const { options, onOptionsChange } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DataSourceHttpSettings
|
||||||
|
defaultUrl="http://localhost:8080"
|
||||||
|
dataSourceConfig={options}
|
||||||
|
onChange={onOptionsChange}
|
||||||
|
/>
|
||||||
|
<GraphiteDetails value={options} onChange={onOptionsChange} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,107 @@
|
|||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import { DataSourceSettings, SelectableValue } from '@grafana/data';
|
||||||
|
import { Button, FormLabel, Select } from '@grafana/ui';
|
||||||
|
import { GraphiteOptions, GraphiteType } from '../types';
|
||||||
|
|
||||||
|
const graphiteVersions = [
|
||||||
|
{ label: '0.9.x', value: '0.9' },
|
||||||
|
{ label: '1.0.x', value: '1.0' },
|
||||||
|
{ label: '1.1.x', value: '1.1' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const graphiteTypes = Object.keys(GraphiteType).map((key: string) => ({
|
||||||
|
label: key,
|
||||||
|
value: (GraphiteType as any)[key],
|
||||||
|
}));
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
value: DataSourceSettings<GraphiteOptions>;
|
||||||
|
onChange: (value: DataSourceSettings<GraphiteOptions>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
showMetricTankHelp: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GraphiteDetails extends PureComponent<Props, State> {
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
showMetricTankHelp: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeHandler = (key: keyof GraphiteOptions) => (newValue: SelectableValue) => {
|
||||||
|
const { value, onChange } = this.props;
|
||||||
|
onChange({
|
||||||
|
...value,
|
||||||
|
jsonData: {
|
||||||
|
...value.jsonData,
|
||||||
|
[key]: newValue.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { value } = this.props;
|
||||||
|
const { showMetricTankHelp } = this.state;
|
||||||
|
|
||||||
|
const currentVersion =
|
||||||
|
graphiteVersions.find(item => item.value === value.jsonData.graphiteVersion) ?? graphiteVersions[2];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h3 className="page-heading">Graphite details</h3>
|
||||||
|
<div className="gf-form-group">
|
||||||
|
<div className="gf-form">
|
||||||
|
<FormLabel tooltip="This option controls what functions are available in the Graphite query editor.">
|
||||||
|
Version
|
||||||
|
</FormLabel>
|
||||||
|
<Select
|
||||||
|
value={currentVersion}
|
||||||
|
options={graphiteVersions}
|
||||||
|
width={8}
|
||||||
|
onChange={this.onChangeHandler('graphiteVersion')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="gf-form-inline">
|
||||||
|
<FormLabel>Type</FormLabel>
|
||||||
|
<Select
|
||||||
|
options={graphiteTypes}
|
||||||
|
value={graphiteTypes.find(type => type.value === value.jsonData.graphiteType)}
|
||||||
|
width={8}
|
||||||
|
onChange={this.onChangeHandler('graphiteType')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
style={{ marginLeft: '8px', marginTop: '5px' }}
|
||||||
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
|
onClick={() =>
|
||||||
|
this.setState((prevState: State) => ({ showMetricTankHelp: !prevState.showMetricTankHelp }))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Help <i className={showMetricTankHelp ? 'fa fa-caret-down' : 'fa fa-caret-right'} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{showMetricTankHelp && (
|
||||||
|
<div className="grafana-info-box m-t-2">
|
||||||
|
<div className="alert-body">
|
||||||
|
<p>
|
||||||
|
There are different types of Graphite compatible backends. Here you can specify the type you are
|
||||||
|
using. If you are using{' '}
|
||||||
|
<a href="https://github.com/grafana/metrictank" className="pointer" target="_blank">
|
||||||
|
Metrictank
|
||||||
|
</a>{' '}
|
||||||
|
then select that here. This will enable Metrictank specific features like query processing meta data.
|
||||||
|
Metrictank is a multi-tenant timeseries engine for Graphite and friends.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,23 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { DataFrame, dateMath, ScopedVars, DataQueryResponse, DataQueryRequest, toDataFrame } from '@grafana/data';
|
import {
|
||||||
|
DataFrame,
|
||||||
|
dateMath,
|
||||||
|
ScopedVars,
|
||||||
|
DataQueryResponse,
|
||||||
|
DataQueryRequest,
|
||||||
|
toDataFrame,
|
||||||
|
DataSourceApi,
|
||||||
|
} from '@grafana/data';
|
||||||
import { isVersionGtOrEq, SemVersion } from 'app/core/utils/version';
|
import { isVersionGtOrEq, SemVersion } from 'app/core/utils/version';
|
||||||
import gfunc from './gfunc';
|
import gfunc from './gfunc';
|
||||||
import { IQService } from 'angular';
|
import { IQService } from 'angular';
|
||||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
//Types
|
//Types
|
||||||
import { GraphiteQuery, GraphiteType } from './types';
|
import { GraphiteOptions, GraphiteQuery, GraphiteType } from './types';
|
||||||
import { getSearchFilterScopedVar } from '../../../features/templating/variable';
|
import { getSearchFilterScopedVar } from '../../../features/templating/variable';
|
||||||
|
|
||||||
export class GraphiteDatasource {
|
export class GraphiteDatasource extends DataSourceApi<GraphiteQuery, GraphiteOptions> {
|
||||||
basicAuth: string;
|
basicAuth: string;
|
||||||
url: string;
|
url: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -29,6 +37,7 @@ export class GraphiteDatasource {
|
|||||||
private backendSrv: BackendSrv,
|
private backendSrv: BackendSrv,
|
||||||
private templateSrv: TemplateSrv
|
private templateSrv: TemplateSrv
|
||||||
) {
|
) {
|
||||||
|
super(instanceSettings);
|
||||||
this.basicAuth = instanceSettings.basicAuth;
|
this.basicAuth = instanceSettings.basicAuth;
|
||||||
this.url = instanceSettings.url;
|
this.url = instanceSettings.url;
|
||||||
this.name = instanceSettings.name;
|
this.name = instanceSettings.name;
|
||||||
@ -157,7 +166,7 @@ export class GraphiteDatasource {
|
|||||||
return expandedQueries;
|
return expandedQueries;
|
||||||
}
|
}
|
||||||
|
|
||||||
annotationQuery(options: { annotation: { target: string; tags: string }; rangeRaw: any }) {
|
annotationQuery(options: any) {
|
||||||
// Graphite metric as annotation
|
// Graphite metric as annotation
|
||||||
if (options.annotation.target) {
|
if (options.annotation.target) {
|
||||||
const target = this.templateSrv.replace(options.annotation.target, {}, 'glob');
|
const target = this.templateSrv.replace(options.annotation.target, {}, 'glob');
|
||||||
@ -237,7 +246,7 @@ export class GraphiteDatasource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
targetContainsTemplate(target: { target: any }) {
|
targetContainsTemplate(target: GraphiteQuery) {
|
||||||
return this.templateSrv.variableExists(target.target);
|
return this.templateSrv.variableExists(target.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,12 +375,10 @@ export class GraphiteDatasource {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getTagValues(tag: string, optionalOptions: any) {
|
getTagValues(options: any = {}) {
|
||||||
const options = optionalOptions || {};
|
|
||||||
|
|
||||||
const httpOptions: any = {
|
const httpOptions: any = {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/tags/' + this.templateSrv.replace(tag),
|
url: '/tags/' + this.templateSrv.replace(options.key),
|
||||||
// for cancellations
|
// for cancellations
|
||||||
requestId: options.requestId,
|
requestId: options.requestId,
|
||||||
};
|
};
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { GraphiteDatasource } from './datasource';
|
import { GraphiteDatasource } from './datasource';
|
||||||
import { GraphiteQueryCtrl } from './query_ctrl';
|
import { GraphiteQueryCtrl } from './query_ctrl';
|
||||||
import { GraphiteConfigCtrl } from './config_ctrl';
|
import { DataSourcePlugin } from '@grafana/data';
|
||||||
|
import { ConfigEditor } from './configuration/ConfigEditor';
|
||||||
|
|
||||||
class AnnotationsQueryCtrl {
|
class AnnotationsQueryCtrl {
|
||||||
static templateUrl = 'partials/annotations.editor.html';
|
static templateUrl = 'partials/annotations.editor.html';
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export const plugin = new DataSourcePlugin(GraphiteDatasource)
|
||||||
GraphiteDatasource as Datasource,
|
.setQueryCtrl(GraphiteQueryCtrl)
|
||||||
GraphiteQueryCtrl as QueryCtrl,
|
.setConfigEditor(ConfigEditor)
|
||||||
GraphiteConfigCtrl as ConfigCtrl,
|
.setAnnotationQueryCtrl(AnnotationsQueryCtrl);
|
||||||
AnnotationsQueryCtrl,
|
|
||||||
};
|
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
<datasource-http-settings
|
|
||||||
current="ctrl.current"
|
|
||||||
suggest-url="http://localhost:8080">
|
|
||||||
</datasource-http-settings>
|
|
||||||
|
|
||||||
<h3 class="page-heading">Graphite details</h3>
|
|
||||||
|
|
||||||
<div class="gf-form-group">
|
|
||||||
<div class="gf-form">
|
|
||||||
<span class="gf-form-label width-8">
|
|
||||||
Version
|
|
||||||
<info-popover mode="right-normal" position="top center">
|
|
||||||
This option controls what functions are available in the Graphite query editor.
|
|
||||||
</info-popover>
|
|
||||||
</span>
|
|
||||||
<span class="gf-form-select-wrapper">
|
|
||||||
<select class="gf-form-input gf-size-auto" ng-model="ctrl.current.jsonData.graphiteVersion" ng-options="f.value as f.name for f in ctrl.graphiteVersions"></select>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="gf-form-inline">
|
|
||||||
<span class="gf-form-label width-8">Type</span>
|
|
||||||
<span class="gf-form-select-wrapper">
|
|
||||||
<select class="gf-form-input gf-size-auto" ng-model="ctrl.current.jsonData.graphiteType" ng-options="f.value as f.name
|
|
||||||
for f in ctrl.graphiteTypes"></select>
|
|
||||||
</span>
|
|
||||||
<div class="gf-form">
|
|
||||||
<label class="gf-form-label query-keyword pointer" ng-click="ctrl.showMetrictankHelp = !ctrl.showMetrictankHelp">
|
|
||||||
Help
|
|
||||||
<i class="fa fa-caret-down" ng-show="ctrl.showMetrictankHelp"></i>
|
|
||||||
<i class="fa fa-caret-right" ng-hide="ctrl.showMetrictankHelp"> </i>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div ng-if="ctrl.showMetrictankHelp" class="grafana-info-box m-t-2">
|
|
||||||
<div class="alert-body">
|
|
||||||
<p>
|
|
||||||
There are different types of Graphite compatible backends. Here you can specify the type you are using.
|
|
||||||
If you are using <a href="https://github.com/grafana/metrictank" class="pointer" target="_blank">Metrictank</a>
|
|
||||||
then select that here. This will enable Metrictank specific features like query processing meta data.
|
|
||||||
|
|
||||||
Metrictank is a multi-tenant timeseries engine for Graphite and friends.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,9 +1,14 @@
|
|||||||
import { DataQuery } from '@grafana/data';
|
import { DataQuery, DataSourceJsonData } from '@grafana/data';
|
||||||
|
|
||||||
export interface GraphiteQuery extends DataQuery {
|
export interface GraphiteQuery extends DataQuery {
|
||||||
target?: string;
|
target?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GraphiteOptions extends DataSourceJsonData {
|
||||||
|
graphiteVersion: string;
|
||||||
|
graphiteType: GraphiteType;
|
||||||
|
}
|
||||||
|
|
||||||
export enum GraphiteType {
|
export enum GraphiteType {
|
||||||
Default = 'default',
|
Default = 'default',
|
||||||
Metrictank = 'metrictank',
|
Metrictank = 'metrictank',
|
||||||
|
Reference in New Issue
Block a user