Browse Source

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

* use ConfigEditor

* use ConfigEditor

* update readme

* make the jsondata generic
Ryan McKinley 6 years ago
parent
commit
0d02ceb452

+ 22 - 10
packages/grafana-ui/src/types/datasource.ts

@@ -4,13 +4,16 @@ import { PluginMeta, GrafanaPlugin } from './plugin';
 import { TableData, TimeSeries, SeriesData, LoadingState } from './data';
 import { PanelData } from './panel';
 
+// NOTE: this seems more general than just DataSource
 export interface DataSourcePluginOptionsEditorProps<TOptions> {
   options: TOptions;
   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>;
   components: DataSourcePluginComponents<TOptions, TQuery>;
 
@@ -20,7 +23,7 @@ export class DataSourcePlugin<TOptions = {}, TQuery extends DataQuery = DataQuer
     this.components = {};
   }
 
-  setConfigEditor(editor: React.ComponentType<DataSourcePluginOptionsEditorProps<TOptions>>) {
+  setConfigEditor(editor: React.ComponentType<DataSourcePluginOptionsEditorProps<DataSourceSettings<TOptions>>>) {
     this.components.ConfigEditor = editor;
     return this;
   }
@@ -85,14 +88,17 @@ interface PluginMetaQueryOptions {
   minInterval?: boolean;
 }
 
-export interface DataSourcePluginComponents<TOptions = {}, TQuery extends DataQuery = DataQuery> {
+export interface DataSourcePluginComponents<
+  TOptions extends DataSourceJsonData = DataSourceJsonData,
+  TQuery extends DataQuery = DataQuery
+> {
   QueryCtrl?: any;
   AnnotationsQueryCtrl?: any;
   VariableQueryEditor?: any;
   QueryEditor?: ComponentClass<QueryEditorProps<DataSourceApi, TQuery>>;
   ExploreQueryField?: ComponentClass<ExploreQueryFieldProps<DataSourceApi, TQuery>>;
   ExploreStartPage?: ComponentClass<ExploreStartPageProps>;
-  ConfigEditor?: React.ComponentType<DataSourcePluginOptionsEditorProps<TOptions>>;
+  ConfigEditor?: React.ComponentType<DataSourcePluginOptionsEditorProps<DataSourceSettings<TOptions>>>;
 }
 
 export interface DataSourceConstructor<TQuery extends DataQuery = DataQuery> {
@@ -329,11 +335,16 @@ export interface QueryHint {
   fix?: QueryFix;
 }
 
+export interface DataSourceJsonData {
+  authType?: string;
+  defaultRegion?: string;
+}
+
 /**
  * Data Source instance edit model.  This is returned from:
  *  /api/datasources
  */
-export interface DataSourceSettings {
+export interface DataSourceSettings<T extends DataSourceJsonData = DataSourceJsonData, S = {}> {
   id: number;
   orgId: number;
   name: string;
@@ -348,7 +359,8 @@ export interface DataSourceSettings {
   basicAuthPassword: string;
   basicAuthUser: string;
   isDefault: boolean;
-  jsonData: { authType: string; defaultRegion: string };
+  jsonData: T;
+  secureJsonData?: S;
   readOnly: boolean;
   withCredentials: boolean;
 }
@@ -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
  * in bootData (on page load), or from: /api/frontend/settings
  */
-export interface DataSourceInstanceSettings {
+export interface DataSourceInstanceSettings<T extends DataSourceJsonData = DataSourceJsonData> {
   id: number;
   type: string;
   name: string;
   meta: DataSourcePluginMeta;
   url?: string;
-  jsonData: { [str: string]: any };
+  jsonData: T;
   username?: string;
   password?: string; // when access is direct, for some legacy datasources
 

+ 74 - 0
public/app/plugins/datasource/input/InputConfigEditor.tsx

@@ -0,0 +1,74 @@
+// 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>
+    );
+  }
+}

+ 3 - 3
public/app/plugins/datasource/input/datasource.test.ts → public/app/plugins/datasource/input/InputDatasource.test.ts

@@ -1,11 +1,11 @@
-import InputDatasource from './datasource';
-import { InputQuery } from './types';
+import InputDatasource from './InputDatasource';
+import { InputQuery, InputOptions } from './types';
 import { readCSV, DataSourceInstanceSettings, PluginMeta } from '@grafana/ui';
 import { getQueryOptions } from 'test/helpers/getQueryOptions';
 
 describe('InputDatasource', () => {
   const data = readCSV('a,b,c\n1,2,3\n4,5,6');
-  const instanceSettings: DataSourceInstanceSettings = {
+  const instanceSettings: DataSourceInstanceSettings<InputOptions> = {
     id: 1,
     type: 'x',
     name: 'xxx',

+ 2 - 3
public/app/plugins/datasource/input/datasource.ts → public/app/plugins/datasource/input/InputDatasource.ts

@@ -6,7 +6,7 @@ import {
   DataSourceApi,
   DataSourceInstanceSettings,
 } from '@grafana/ui/src/types';
-import { InputQuery } from './types';
+import { InputQuery, InputOptions } from './types';
 
 export class InputDatasource implements DataSourceApi<InputQuery> {
   data: SeriesData[];
@@ -17,8 +17,7 @@ export class InputDatasource implements DataSourceApi<InputQuery> {
   // Filled in by grafana plugin system
   id?: number;
 
-  /** @ngInject */
-  constructor(instanceSettings: DataSourceInstanceSettings) {
+  constructor(instanceSettings: DataSourceInstanceSettings<InputOptions>) {
     if (instanceSettings.jsonData) {
       this.data = instanceSettings.jsonData.data;
     }

+ 1 - 3
public/app/plugins/datasource/input/InputQueryEditor.tsx

@@ -2,7 +2,7 @@
 import React, { PureComponent } from 'react';
 
 // Types
-import { InputDatasource } from './datasource';
+import { InputDatasource } from './InputDatasource';
 import { InputQuery } from './types';
 
 import { FormLabel, Select, QueryEditorProps, SelectOptionItem, SeriesData, TableInputCSV, toCSV } from '@grafana/ui';
@@ -94,5 +94,3 @@ export class InputQueryEditor extends PureComponent<Props, State> {
     );
   }
 }
-
-export default InputQueryEditor;

+ 1 - 1
public/app/plugins/datasource/input/README.md

@@ -1,3 +1,3 @@
-# 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.

+ 0 - 45
public/app/plugins/datasource/input/legacy/CSVInputWrapper.tsx

@@ -1,45 +0,0 @@
-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']);
-  },
-]);

+ 0 - 21
public/app/plugins/datasource/input/legacy/InputConfigCtrl.ts

@@ -1,21 +0,0 @@
-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;

+ 0 - 16
public/app/plugins/datasource/input/legacy/config.html

@@ -1,16 +0,0 @@
-<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>

+ 9 - 4
public/app/plugins/datasource/input/module.ts

@@ -1,6 +1,11 @@
-import Datasource from './datasource';
+import { DataSourcePlugin } from '@grafana/ui';
 
-import InputQueryEditor from './InputQueryEditor';
-import InputConfigCtrl from './legacy/InputConfigCtrl';
+import { InputDatasource } from './InputDatasource';
 
-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);

+ 6 - 1
public/app/plugins/datasource/input/types.ts

@@ -1,6 +1,11 @@
-import { DataQuery, SeriesData } from '@grafana/ui/src/types';
+import { DataQuery, SeriesData, DataSourceJsonData } from '@grafana/ui/src/types';
 
 export interface InputQuery extends DataQuery {
   // Data saved in the panel
   data?: SeriesData[];
 }
+
+export interface InputOptions extends DataSourceJsonData {
+  // Saved in the datasource and download with bootData
+  data?: SeriesData[];
+}