QueryOptions.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Libraries
  2. import React, { PureComponent } from 'react';
  3. // Utils
  4. import { isValidTimeSpan } from 'app/core/utils/rangeutil';
  5. // Components
  6. import { Switch } from '@grafana/ui';
  7. import { Input } from 'app/core/components/Form';
  8. import { EventsWithValidation } from 'app/core/components/Form/Input';
  9. import { InputStatus } from 'app/core/components/Form/Input';
  10. import DataSourceOption from './DataSourceOption';
  11. import { FormLabel } from '@grafana/ui';
  12. // Types
  13. import { PanelModel } from '../state/PanelModel';
  14. import { DataSourceSelectItem } from '@grafana/ui/src/types';
  15. import { ValidationEvents } from 'app/types';
  16. const timeRangeValidationEvents: ValidationEvents = {
  17. [EventsWithValidation.onBlur]: [
  18. {
  19. rule: value => {
  20. if (!value) {
  21. return true;
  22. }
  23. return isValidTimeSpan(value);
  24. },
  25. errorMessage: 'Not a valid timespan',
  26. },
  27. ],
  28. };
  29. const emptyToNull = (value: string) => {
  30. return value === '' ? null : value;
  31. };
  32. interface Props {
  33. panel: PanelModel;
  34. datasource: DataSourceSelectItem;
  35. }
  36. interface State {
  37. relativeTime: string;
  38. timeShift: string;
  39. }
  40. export class QueryOptions extends PureComponent<Props, State> {
  41. constructor(props) {
  42. super(props);
  43. this.state = {
  44. relativeTime: props.panel.timeFrom || '',
  45. timeShift: props.panel.timeShift || '',
  46. };
  47. }
  48. onRelativeTimeChange = event => {
  49. this.setState({
  50. relativeTime: event.target.value,
  51. });
  52. };
  53. onTimeShiftChange = event => {
  54. this.setState({
  55. timeShift: event.target.value,
  56. });
  57. };
  58. onOverrideTime = (evt, status: InputStatus) => {
  59. const { value } = evt.target;
  60. const { panel } = this.props;
  61. const emptyToNullValue = emptyToNull(value);
  62. if (status === InputStatus.Valid && panel.timeFrom !== emptyToNullValue) {
  63. panel.timeFrom = emptyToNullValue;
  64. panel.refresh();
  65. }
  66. };
  67. onTimeShift = (evt, status: InputStatus) => {
  68. const { value } = evt.target;
  69. const { panel } = this.props;
  70. const emptyToNullValue = emptyToNull(value);
  71. if (status === InputStatus.Valid && panel.timeShift !== emptyToNullValue) {
  72. panel.timeShift = emptyToNullValue;
  73. panel.refresh();
  74. }
  75. };
  76. onToggleTimeOverride = () => {
  77. const { panel } = this.props;
  78. panel.hideTimeOverride = !panel.hideTimeOverride;
  79. panel.refresh();
  80. };
  81. renderOptions() {
  82. const { datasource, panel } = this.props;
  83. const { queryOptions } = datasource.meta;
  84. if (!queryOptions) {
  85. return null;
  86. }
  87. const onChangeFn = (panelKey: string) => {
  88. return (value: string | number) => {
  89. panel[panelKey] = value;
  90. panel.refresh();
  91. };
  92. };
  93. const allOptions = {
  94. cacheTimeout: {
  95. label: 'Cache timeout',
  96. placeholder: '60',
  97. name: 'cacheTimeout',
  98. value: panel.cacheTimeout,
  99. tooltipInfo: (
  100. <>
  101. If your time series store has a query cache this option can override the default cache timeout. Specify a
  102. numeric value in seconds.
  103. </>
  104. ),
  105. },
  106. maxDataPoints: {
  107. label: 'Max data points',
  108. placeholder: 'auto',
  109. name: 'maxDataPoints',
  110. value: panel.maxDataPoints,
  111. tooltipInfo: (
  112. <>
  113. The maximum data points the query should return. For graphs this is automatically set to one data point per
  114. pixel.
  115. </>
  116. ),
  117. },
  118. minInterval: {
  119. label: 'Min time interval',
  120. placeholder: '0',
  121. name: 'minInterval',
  122. value: panel.interval,
  123. panelKey: 'interval',
  124. tooltipInfo: (
  125. <>
  126. A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example{' '}
  127. <code>1m</code> if your data is written every minute. Access auto interval via variable{' '}
  128. <code>$__interval</code> for time range string and <code>$__interval_ms</code> for numeric variable that can
  129. be used in math expressions.
  130. </>
  131. ),
  132. },
  133. };
  134. return Object.keys(queryOptions).map(key => {
  135. const options = allOptions[key];
  136. return <DataSourceOption key={key} {...options} onChange={onChangeFn(allOptions[key].panelKey || key)} />;
  137. });
  138. }
  139. render() {
  140. const hideTimeOverride = this.props.panel.hideTimeOverride;
  141. const { relativeTime, timeShift } = this.state;
  142. return (
  143. <div className="gf-form-inline">
  144. {this.renderOptions()}
  145. <div className="gf-form">
  146. <FormLabel>Relative time</FormLabel>
  147. <Input
  148. type="text"
  149. className="width-6"
  150. placeholder="1h"
  151. onChange={this.onRelativeTimeChange}
  152. onBlur={this.onOverrideTime}
  153. validationEvents={timeRangeValidationEvents}
  154. hideErrorMessage={true}
  155. value={relativeTime}
  156. />
  157. </div>
  158. <div className="gf-form">
  159. <span className="gf-form-label">Time shift</span>
  160. <Input
  161. type="text"
  162. className="width-6"
  163. placeholder="1h"
  164. onChange={this.onTimeShiftChange}
  165. onBlur={this.onTimeShift}
  166. validationEvents={timeRangeValidationEvents}
  167. hideErrorMessage={true}
  168. value={timeShift}
  169. />
  170. </div>
  171. <div className="gf-form-inline">
  172. <Switch label="Hide time info" checked={hideTimeOverride} onChange={this.onToggleTimeOverride} />
  173. </div>
  174. </div>
  175. );
  176. }
  177. }