Commit c5ff7fa5 by Peter Holmberg Committed by Torkel Ödegaard

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
parent 02d7d005
...@@ -261,7 +261,7 @@ export abstract class DataSourceApi< ...@@ -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
......
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' },
];
}
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} />
</>
);
};
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>
</>
);
}
}
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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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,
}; };
......
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,
};
<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&nbsp;
<i class="fa fa-caret-down" ng-show="ctrl.showMetrictankHelp"></i>
<i class="fa fa-caret-right" ng-hide="ctrl.showMetrictankHelp">&nbsp;</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>
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',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment