Commit 0d02ceb4 by Ryan McKinley Committed by Torkel Ödegaard

Input Datasource: convert from angular config to react ConfigEditor (#16856)

* use ConfigEditor

* use ConfigEditor

* update readme

* make the jsondata generic
parent ece4d220
...@@ -4,13 +4,16 @@ import { PluginMeta, GrafanaPlugin } from './plugin'; ...@@ -4,13 +4,16 @@ import { PluginMeta, GrafanaPlugin } from './plugin';
import { TableData, TimeSeries, SeriesData, LoadingState } from './data'; import { TableData, TimeSeries, SeriesData, LoadingState } from './data';
import { PanelData } from './panel'; import { PanelData } from './panel';
// NOTE: this seems more general than just DataSource
export interface DataSourcePluginOptionsEditorProps<TOptions> { export interface DataSourcePluginOptionsEditorProps<TOptions> {
options: TOptions; options: TOptions;
onOptionsChange: (options: TOptions) => void; onOptionsChange: (options: TOptions) => void;
} }
export class DataSourcePlugin<TOptions = {}, TQuery extends DataQuery = DataQuery> extends GrafanaPlugin<
DataSourcePluginMeta export class DataSourcePlugin<
> { TOptions extends DataSourceJsonData = DataSourceJsonData,
TQuery extends DataQuery = DataQuery
> extends GrafanaPlugin<DataSourcePluginMeta> {
DataSourceClass: DataSourceConstructor<TQuery>; DataSourceClass: DataSourceConstructor<TQuery>;
components: DataSourcePluginComponents<TOptions, TQuery>; components: DataSourcePluginComponents<TOptions, TQuery>;
...@@ -20,7 +23,7 @@ export class DataSourcePlugin<TOptions = {}, TQuery extends DataQuery = DataQuer ...@@ -20,7 +23,7 @@ export class DataSourcePlugin<TOptions = {}, TQuery extends DataQuery = DataQuer
this.components = {}; this.components = {};
} }
setConfigEditor(editor: React.ComponentType<DataSourcePluginOptionsEditorProps<TOptions>>) { setConfigEditor(editor: React.ComponentType<DataSourcePluginOptionsEditorProps<DataSourceSettings<TOptions>>>) {
this.components.ConfigEditor = editor; this.components.ConfigEditor = editor;
return this; return this;
} }
...@@ -85,14 +88,17 @@ interface PluginMetaQueryOptions { ...@@ -85,14 +88,17 @@ interface PluginMetaQueryOptions {
minInterval?: boolean; minInterval?: boolean;
} }
export interface DataSourcePluginComponents<TOptions = {}, TQuery extends DataQuery = DataQuery> { export interface DataSourcePluginComponents<
TOptions extends DataSourceJsonData = DataSourceJsonData,
TQuery extends DataQuery = DataQuery
> {
QueryCtrl?: any; QueryCtrl?: any;
AnnotationsQueryCtrl?: any; AnnotationsQueryCtrl?: any;
VariableQueryEditor?: any; VariableQueryEditor?: any;
QueryEditor?: ComponentClass<QueryEditorProps<DataSourceApi, TQuery>>; QueryEditor?: ComponentClass<QueryEditorProps<DataSourceApi, TQuery>>;
ExploreQueryField?: ComponentClass<ExploreQueryFieldProps<DataSourceApi, TQuery>>; ExploreQueryField?: ComponentClass<ExploreQueryFieldProps<DataSourceApi, TQuery>>;
ExploreStartPage?: ComponentClass<ExploreStartPageProps>; ExploreStartPage?: ComponentClass<ExploreStartPageProps>;
ConfigEditor?: React.ComponentType<DataSourcePluginOptionsEditorProps<TOptions>>; ConfigEditor?: React.ComponentType<DataSourcePluginOptionsEditorProps<DataSourceSettings<TOptions>>>;
} }
export interface DataSourceConstructor<TQuery extends DataQuery = DataQuery> { export interface DataSourceConstructor<TQuery extends DataQuery = DataQuery> {
...@@ -329,11 +335,16 @@ export interface QueryHint { ...@@ -329,11 +335,16 @@ export interface QueryHint {
fix?: QueryFix; fix?: QueryFix;
} }
export interface DataSourceJsonData {
authType?: string;
defaultRegion?: string;
}
/** /**
* Data Source instance edit model. This is returned from: * Data Source instance edit model. This is returned from:
* /api/datasources * /api/datasources
*/ */
export interface DataSourceSettings { export interface DataSourceSettings<T extends DataSourceJsonData = DataSourceJsonData, S = {}> {
id: number; id: number;
orgId: number; orgId: number;
name: string; name: string;
...@@ -348,7 +359,8 @@ export interface DataSourceSettings { ...@@ -348,7 +359,8 @@ export interface DataSourceSettings {
basicAuthPassword: string; basicAuthPassword: string;
basicAuthUser: string; basicAuthUser: string;
isDefault: boolean; isDefault: boolean;
jsonData: { authType: string; defaultRegion: string }; jsonData: T;
secureJsonData?: S;
readOnly: boolean; readOnly: boolean;
withCredentials: boolean; withCredentials: boolean;
} }
...@@ -358,13 +370,13 @@ export interface DataSourceSettings { ...@@ -358,13 +370,13 @@ export interface DataSourceSettings {
* as this data model is available to every user who has access to a data source (Viewers+). This is loaded * as this data model is available to every user who has access to a data source (Viewers+). This is loaded
* in bootData (on page load), or from: /api/frontend/settings * in bootData (on page load), or from: /api/frontend/settings
*/ */
export interface DataSourceInstanceSettings { export interface DataSourceInstanceSettings<T extends DataSourceJsonData = DataSourceJsonData> {
id: number; id: number;
type: string; type: string;
name: string; name: string;
meta: DataSourcePluginMeta; meta: DataSourcePluginMeta;
url?: string; url?: string;
jsonData: { [str: string]: any }; jsonData: T;
username?: string; username?: string;
password?: string; // when access is direct, for some legacy datasources password?: string; // when access is direct, for some legacy datasources
......
// Libraries
import React, { PureComponent } from 'react';
// Types
import { InputOptions } from './types';
import { DataSourcePluginOptionsEditorProps, DataSourceSettings, SeriesData, TableInputCSV, toCSV } from '@grafana/ui';
type InputSettings = DataSourceSettings<InputOptions>;
interface Props extends DataSourcePluginOptionsEditorProps<InputSettings> {}
interface State {
text: string;
}
export class InputConfigEditor extends PureComponent<Props, State> {
state = {
text: '',
};
componentDidMount() {
const { options } = this.props;
if (options.jsonData.data) {
const text = toCSV(options.jsonData.data);
this.setState({ text });
}
}
onSeriesParsed = (data: SeriesData[], text: string) => {
const { options, onOptionsChange } = this.props;
if (!data) {
data = [
{
fields: [],
rows: [],
},
];
}
// data is a property on 'jsonData'
const jsonData = {
...options.jsonData,
data,
};
onOptionsChange({
...options,
jsonData,
});
this.setState({ text });
};
render() {
const { text } = this.state;
return (
<div>
<div className="gf-form-group">
<h4>Shared Data:</h4>
<span>Enter CSV</span>
<TableInputCSV text={text} onSeriesParsed={this.onSeriesParsed} width={'100%'} height={200} />
</div>
<div className="grafana-info-box">
This data is stored in the datasource json and is returned to every user in the initial request for any
datasource. This is an appropriate place to enter a few values. Large datasets will perform better in other
datasources.
<br />
<br />
<b>NOTE:</b> Changes to this data will only be reflected after a browser refresh.
</div>
</div>
);
}
}
import InputDatasource from './datasource'; import InputDatasource from './InputDatasource';
import { InputQuery } from './types'; import { InputQuery, InputOptions } from './types';
import { readCSV, DataSourceInstanceSettings, PluginMeta } from '@grafana/ui'; import { readCSV, DataSourceInstanceSettings, PluginMeta } from '@grafana/ui';
import { getQueryOptions } from 'test/helpers/getQueryOptions'; import { getQueryOptions } from 'test/helpers/getQueryOptions';
describe('InputDatasource', () => { describe('InputDatasource', () => {
const data = readCSV('a,b,c\n1,2,3\n4,5,6'); const data = readCSV('a,b,c\n1,2,3\n4,5,6');
const instanceSettings: DataSourceInstanceSettings = { const instanceSettings: DataSourceInstanceSettings<InputOptions> = {
id: 1, id: 1,
type: 'x', type: 'x',
name: 'xxx', name: 'xxx',
......
...@@ -6,7 +6,7 @@ import { ...@@ -6,7 +6,7 @@ import {
DataSourceApi, DataSourceApi,
DataSourceInstanceSettings, DataSourceInstanceSettings,
} from '@grafana/ui/src/types'; } from '@grafana/ui/src/types';
import { InputQuery } from './types'; import { InputQuery, InputOptions } from './types';
export class InputDatasource implements DataSourceApi<InputQuery> { export class InputDatasource implements DataSourceApi<InputQuery> {
data: SeriesData[]; data: SeriesData[];
...@@ -17,8 +17,7 @@ export class InputDatasource implements DataSourceApi<InputQuery> { ...@@ -17,8 +17,7 @@ export class InputDatasource implements DataSourceApi<InputQuery> {
// Filled in by grafana plugin system // Filled in by grafana plugin system
id?: number; id?: number;
/** @ngInject */ constructor(instanceSettings: DataSourceInstanceSettings<InputOptions>) {
constructor(instanceSettings: DataSourceInstanceSettings) {
if (instanceSettings.jsonData) { if (instanceSettings.jsonData) {
this.data = instanceSettings.jsonData.data; this.data = instanceSettings.jsonData.data;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
// Types // Types
import { InputDatasource } from './datasource'; import { InputDatasource } from './InputDatasource';
import { InputQuery } from './types'; import { InputQuery } from './types';
import { FormLabel, Select, QueryEditorProps, SelectOptionItem, SeriesData, TableInputCSV, toCSV } from '@grafana/ui'; import { FormLabel, Select, QueryEditorProps, SelectOptionItem, SeriesData, TableInputCSV, toCSV } from '@grafana/ui';
...@@ -94,5 +94,3 @@ export class InputQueryEditor extends PureComponent<Props, State> { ...@@ -94,5 +94,3 @@ export class InputQueryEditor extends PureComponent<Props, State> {
); );
} }
} }
export default InputQueryEditor;
# Table Datasource - Native Plugin # Direct Input Datasource - Native Plugin
This datasource lets you define results directly in CSV. The values are stored either in a shared datasource, or directly in panels. This datasource lets you define results directly in CSV. The values are stored either in a shared datasource, or directly in panels.
import React, { Component } from 'react';
import coreModule from 'app/core/core_module';
import { TableInputCSV, SeriesData, toCSV } from '@grafana/ui';
interface Props {
data: SeriesData[];
onParsed: (data: SeriesData[]) => void;
}
interface State {
data: SeriesData[];
text: string;
}
/**
* Angular wrapper around TableInputCSV
*/
class Wraper extends Component<Props, State> {
constructor(props) {
super(props);
this.state = {
text: toCSV(props.data),
data: props.data,
};
}
onSeriesParsed = (data: SeriesData[], text: string) => {
this.setState({ data, text });
this.props.onParsed(data);
};
render() {
const { text } = this.state;
return <TableInputCSV text={text} onSeriesParsed={this.onSeriesParsed} width={'100%'} height={300} />;
}
}
coreModule.directive('csvInput', [
'reactDirective',
reactDirective => {
return reactDirective(Wraper, ['data', 'onParsed']);
},
]);
import { SeriesData } from '@grafana/ui';
// Loads the angular wrapping directive
import './CSVInputWrapper';
export class TableConfigCtrl {
static templateUrl = 'legacy/config.html';
current: any; // the Current Configuration (set by the plugin infra)
/** @ngInject */
constructor($scope: any, $injector: any) {
console.log('TableConfigCtrl Init', this);
}
onParsed = (data: SeriesData[]) => {
this.current.jsonData.data = data;
};
}
export default TableConfigCtrl;
<div class="gf-form-group">
<h4>Shared Data:</h4>
<span>Enter CSV</span>
<csv-input
data="ctrl.current.jsonData.data"
onParsed="ctrl.onParsed"
></csv-input>
</div>
<div class="grafana-info-box">
This data is stored in the datasource json and is returned to every user
in the initial request for any datasource. This is an appropriate place
to enter a few values. Large datasets will perform better in other datasources.
<br/><br/>
<b>NOTE:</b> Changes to this data will only be reflected after a browser refresh.
</div>
import Datasource from './datasource'; import { DataSourcePlugin } from '@grafana/ui';
import InputQueryEditor from './InputQueryEditor'; import { InputDatasource } from './InputDatasource';
import InputConfigCtrl from './legacy/InputConfigCtrl';
export { Datasource, InputQueryEditor as QueryEditor, InputConfigCtrl as ConfigCtrl }; import { InputQueryEditor } from './InputQueryEditor';
import { InputConfigEditor } from './InputConfigEditor';
import { InputOptions, InputQuery } from './types';
export const plugin = new DataSourcePlugin<InputOptions, InputQuery>(InputDatasource)
.setConfigEditor(InputConfigEditor)
.setQueryEditor(InputQueryEditor);
import { DataQuery, SeriesData } from '@grafana/ui/src/types'; import { DataQuery, SeriesData, DataSourceJsonData } from '@grafana/ui/src/types';
export interface InputQuery extends DataQuery { export interface InputQuery extends DataQuery {
// Data saved in the panel // Data saved in the panel
data?: SeriesData[]; data?: SeriesData[];
} }
export interface InputOptions extends DataSourceJsonData {
// Saved in the datasource and download with bootData
data?: SeriesData[];
}
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