QueryOptions.tsx 5.4 KB

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