Explorar o código

Made sure that DataSourceOption displays value and fires onChange/onBlur events (#15757)

* Fixed #15682 

* fix: Add hideTimeOverride to state since we need to control the Switch

* fix: Back the maxDataPoints change, we need to keep it as a string

Co-authored-by:johannes.schill@polyester.se
Hugo Häggmark %!s(int64=6) %!d(string=hai) anos
pai
achega
48570c6272

+ 9 - 8
public/app/features/dashboard/panel_editor/DataSourceOption.tsx

@@ -1,16 +1,17 @@
-import React, { FC } from 'react';
+import React, { FC, ChangeEvent } from 'react';
 import { FormLabel } from '@grafana/ui';
 
 interface Props {
   label: string;
   placeholder?: string;
-  name?: string;
-  value?: string;
-  onChange?: (evt: any) => void;
+  name: string;
+  value: string;
+  onBlur: (event: ChangeEvent<HTMLInputElement>) => void;
+  onChange: (event: ChangeEvent<HTMLInputElement>) => void;
   tooltipInfo?: any;
 }
 
-export const DataSourceOptions: FC<Props> = ({ label, placeholder, name, value, onChange, tooltipInfo }) => {
+export const DataSourceOption: FC<Props> = ({ label, placeholder, name, value, onBlur, onChange, tooltipInfo }) => {
   return (
     <div className="gf-form gf-form--flex-end">
       <FormLabel tooltip={tooltipInfo}>{label}</FormLabel>
@@ -20,10 +21,10 @@ export const DataSourceOptions: FC<Props> = ({ label, placeholder, name, value,
         placeholder={placeholder}
         name={name}
         spellCheck={false}
-        onBlur={evt => onChange(evt.target.value)}
+        onBlur={onBlur}
+        onChange={onChange}
+        value={value}
       />
     </div>
   );
 };
-
-export default DataSourceOptions;

+ 84 - 65
public/app/features/dashboard/panel_editor/QueryOptions.tsx

@@ -1,5 +1,5 @@
 // Libraries
-import React, { PureComponent } from 'react';
+import React, { PureComponent, ChangeEvent, FocusEvent } from 'react';
 
 // Utils
 import { isValidTimeSpan } from 'app/core/utils/rangeutil';
@@ -9,7 +9,7 @@ import { Switch } from '@grafana/ui';
 import { Input } from 'app/core/components/Form';
 import { EventsWithValidation } from 'app/core/components/Form/Input';
 import { InputStatus } from 'app/core/components/Form/Input';
-import DataSourceOption from './DataSourceOption';
+import { DataSourceOption } from './DataSourceOption';
 import { FormLabel } from '@grafana/ui';
 
 // Types
@@ -43,32 +43,79 @@ interface Props {
 interface State {
   relativeTime: string;
   timeShift: string;
+  cacheTimeout: string;
+  maxDataPoints: string;
+  interval: string;
+  hideTimeOverride: boolean;
 }
 
 export class QueryOptions extends PureComponent<Props, State> {
+  allOptions = {
+    cacheTimeout: {
+      label: 'Cache timeout',
+      placeholder: '60',
+      name: 'cacheTimeout',
+      tooltipInfo: (
+        <>
+          If your time series store has a query cache this option can override the default cache timeout. Specify a
+          numeric value in seconds.
+        </>
+      ),
+    },
+    maxDataPoints: {
+      label: 'Max data points',
+      placeholder: 'auto',
+      name: 'maxDataPoints',
+      tooltipInfo: (
+        <>
+          The maximum data points the query should return. For graphs this is automatically set to one data point per
+          pixel.
+        </>
+      ),
+    },
+    minInterval: {
+      label: 'Min time interval',
+      placeholder: '0',
+      name: 'minInterval',
+      panelKey: 'interval',
+      tooltipInfo: (
+        <>
+          A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example{' '}
+          <code>1m</code> if your data is written every minute. Access auto interval via variable{' '}
+          <code>$__interval</code> for time range string and <code>$__interval_ms</code> for numeric variable that can
+          be used in math expressions.
+        </>
+      ),
+    },
+  };
+
   constructor(props) {
     super(props);
 
     this.state = {
       relativeTime: props.panel.timeFrom || '',
       timeShift: props.panel.timeShift || '',
+      cacheTimeout: props.panel.cacheTimeout || '',
+      maxDataPoints: props.panel.maxDataPoints || '',
+      interval: props.panel.interval || '',
+      hideTimeOverride: props.panel.hideTimeOverride || false,
     };
   }
 
-  onRelativeTimeChange = event => {
+  onRelativeTimeChange = (event: ChangeEvent<HTMLInputElement>) => {
     this.setState({
       relativeTime: event.target.value,
     });
   };
 
-  onTimeShiftChange = event => {
+  onTimeShiftChange = (event: ChangeEvent<HTMLInputElement>) => {
     this.setState({
       timeShift: event.target.value,
     });
   };
 
-  onOverrideTime = (evt, status: InputStatus) => {
-    const { value } = evt.target;
+  onOverrideTime = (event: FocusEvent<HTMLInputElement>, status: InputStatus) => {
+    const { value } = event.target;
     const { panel } = this.props;
     const emptyToNullValue = emptyToNull(value);
     if (status === InputStatus.Valid && panel.timeFrom !== emptyToNullValue) {
@@ -77,8 +124,8 @@ export class QueryOptions extends PureComponent<Props, State> {
     }
   };
 
-  onTimeShift = (evt, status: InputStatus) => {
-    const { value } = evt.target;
+  onTimeShift = (event: FocusEvent<HTMLInputElement>, status: InputStatus) => {
+    const { value } = event.target;
     const { panel } = this.props;
     const emptyToNullValue = emptyToNull(value);
     if (status === InputStatus.Valid && panel.timeShift !== emptyToNullValue) {
@@ -89,77 +136,49 @@ export class QueryOptions extends PureComponent<Props, State> {
 
   onToggleTimeOverride = () => {
     const { panel } = this.props;
-    panel.hideTimeOverride = !panel.hideTimeOverride;
+    this.setState({ hideTimeOverride: !this.state.hideTimeOverride }, () => {
+      panel.hideTimeOverride = this.state.hideTimeOverride;
+      panel.refresh();
+    });
+  };
+
+  onDataSourceOptionBlur = (panelKey: string) => () => {
+    const { panel } = this.props;
+
+    panel[panelKey] = this.state[panelKey];
     panel.refresh();
   };
 
-  renderOptions() {
-    const { datasource, panel } = this.props;
+  onDataSourceOptionChange = (panelKey: string) => (event: ChangeEvent<HTMLInputElement>) => {
+    this.setState({ ...this.state, [panelKey]: event.target.value });
+  };
+
+  renderOptions = () => {
+    const { datasource } = this.props;
     const { queryOptions } = datasource.meta;
 
     if (!queryOptions) {
       return null;
     }
 
-    const onChangeFn = (panelKey: string) => {
-      return (value: string | number) => {
-        panel[panelKey] = value;
-        panel.refresh();
-      };
-    };
-
-    const allOptions = {
-      cacheTimeout: {
-        label: 'Cache timeout',
-        placeholder: '60',
-        name: 'cacheTimeout',
-        value: panel.cacheTimeout,
-        tooltipInfo: (
-          <>
-            If your time series store has a query cache this option can override the default cache timeout. Specify a
-            numeric value in seconds.
-          </>
-        ),
-      },
-      maxDataPoints: {
-        label: 'Max data points',
-        placeholder: 'auto',
-        name: 'maxDataPoints',
-        value: panel.maxDataPoints,
-        tooltipInfo: (
-          <>
-            The maximum data points the query should return. For graphs this is automatically set to one data point per
-            pixel.
-          </>
-        ),
-      },
-      minInterval: {
-        label: 'Min time interval',
-        placeholder: '0',
-        name: 'minInterval',
-        value: panel.interval,
-        panelKey: 'interval',
-        tooltipInfo: (
-          <>
-            A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example{' '}
-            <code>1m</code> if your data is written every minute. Access auto interval via variable{' '}
-            <code>$__interval</code> for time range string and <code>$__interval_ms</code> for numeric variable that can
-            be used in math expressions.
-          </>
-        ),
-      },
-    };
-
     return Object.keys(queryOptions).map(key => {
-      const options = allOptions[key];
-      return <DataSourceOption key={key} {...options} onChange={onChangeFn(allOptions[key].panelKey || key)} />;
+      const options = this.allOptions[key];
+      const panelKey = options.panelKey || key;
+      return (
+        <DataSourceOption
+          key={key}
+          {...options}
+          onChange={this.onDataSourceOptionChange(panelKey)}
+          onBlur={this.onDataSourceOptionBlur(panelKey)}
+          value={this.state[panelKey]}
+        />
+      );
     });
-  }
+  };
 
   render() {
-    const hideTimeOverride = this.props.panel.hideTimeOverride;
+    const { hideTimeOverride } = this.state;
     const { relativeTime, timeShift } = this.state;
-
     return (
       <div className="gf-form-inline">
         {this.renderOptions()}