QueryOptions.tsx 5.4 KB

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