github.com/thanos-io/thanos@v0.32.5/pkg/ui/react-app/src/pages/graph/GraphControls.tsx (about) 1 import React, { Component } from 'react'; 2 import { Button, ButtonGroup, Form, InputGroup, InputGroupAddon, Input } from 'reactstrap'; 3 4 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 5 import { faPlus, faMinus, faChartArea, faChartLine } from '@fortawesome/free-solid-svg-icons'; 6 7 import TimeInput from './TimeInput'; 8 import { parseDuration, formatDuration } from '../../utils'; 9 10 interface GraphControlsProps { 11 range: number; 12 endTime: number | null; 13 useLocalTime: boolean; 14 resolution: number | null; 15 stacked: boolean; 16 maxSourceResolution: string; 17 18 onChangeRange: (range: number) => void; 19 onChangeEndTime: (endTime: number | null) => void; 20 onChangeResolution: (resolution: number | null) => void; 21 onChangeStacking: (stacked: boolean) => void; 22 onChangeMaxSourceResolution: (maxSourceResolution: string) => void; 23 } 24 25 class GraphControls extends Component<GraphControlsProps> { 26 constructor(props: GraphControlsProps) { 27 super(props); 28 29 this.handleMaxSourceResChange = this.handleMaxSourceResChange.bind(this); 30 } 31 32 private rangeRef = React.createRef<HTMLInputElement>(); 33 private resolutionRef = React.createRef<HTMLInputElement>(); 34 35 rangeSteps = [ 36 1, 37 10, 38 60, 39 5 * 60, 40 15 * 60, 41 30 * 60, 42 60 * 60, 43 2 * 60 * 60, 44 6 * 60 * 60, 45 12 * 60 * 60, 46 24 * 60 * 60, 47 48 * 60 * 60, 48 7 * 24 * 60 * 60, 49 14 * 24 * 60 * 60, 50 28 * 24 * 60 * 60, 51 56 * 24 * 60 * 60, 52 365 * 24 * 60 * 60, 53 730 * 24 * 60 * 60, 54 ].map((s) => s * 1000); 55 56 onChangeRangeInput = (rangeText: string): void => { 57 const range = parseDuration(rangeText); 58 if (range === null) { 59 this.changeRangeInput(this.props.range); 60 } else { 61 this.props.onChangeRange(range); 62 } 63 }; 64 65 changeRangeInput = (range: number): void => { 66 this.rangeRef.current!.value = formatDuration(range); 67 }; 68 69 increaseRange = (): void => { 70 for (const range of this.rangeSteps) { 71 if (this.props.range < range) { 72 this.changeRangeInput(range); 73 this.props.onChangeRange(range); 74 return; 75 } 76 } 77 }; 78 79 decreaseRange = (): void => { 80 for (const range of this.rangeSteps.slice().reverse()) { 81 if (this.props.range > range) { 82 this.changeRangeInput(range); 83 this.props.onChangeRange(range); 84 return; 85 } 86 } 87 }; 88 89 componentDidUpdate(prevProps: GraphControlsProps) { 90 if (prevProps.range !== this.props.range) { 91 this.changeRangeInput(this.props.range); 92 } 93 if (prevProps.resolution !== this.props.resolution) { 94 this.resolutionRef.current!.value = this.props.resolution !== null ? this.props.resolution.toString() : ''; 95 } 96 } 97 98 handleMaxSourceResChange(event: React.ChangeEvent<HTMLInputElement>): void { 99 this.props.onChangeMaxSourceResolution(event.target.value); 100 } 101 102 render() { 103 return ( 104 <Form inline className="graph-controls" onSubmit={(e) => e.preventDefault()}> 105 <InputGroup className="range-input" size="sm"> 106 <InputGroupAddon addonType="prepend"> 107 <Button title="Decrease range" onClick={this.decreaseRange}> 108 <FontAwesomeIcon icon={faMinus} fixedWidth /> 109 </Button> 110 </InputGroupAddon> 111 112 <Input 113 defaultValue={formatDuration(this.props.range)} 114 innerRef={this.rangeRef} 115 onBlur={() => this.onChangeRangeInput(this.rangeRef.current!.value)} 116 /> 117 118 <InputGroupAddon addonType="append"> 119 <Button title="Increase range" onClick={this.increaseRange}> 120 <FontAwesomeIcon icon={faPlus} fixedWidth /> 121 </Button> 122 </InputGroupAddon> 123 </InputGroup> 124 125 <TimeInput 126 time={this.props.endTime} 127 useLocalTime={this.props.useLocalTime} 128 range={this.props.range} 129 placeholder="End time" 130 onChangeTime={this.props.onChangeEndTime} 131 /> 132 133 <Input 134 placeholder="Res. (s)" 135 className="resolution-input" 136 defaultValue={this.props.resolution !== null ? this.props.resolution.toString() : ''} 137 innerRef={this.resolutionRef} 138 onBlur={() => { 139 const res = parseInt(this.resolutionRef.current!.value); 140 this.props.onChangeResolution(res ? res : null); 141 }} 142 bsSize="sm" 143 /> 144 145 <ButtonGroup className="stacked-input" size="sm"> 146 <Button 147 title="Show unstacked line graph" 148 onClick={() => this.props.onChangeStacking(false)} 149 active={!this.props.stacked} 150 > 151 <FontAwesomeIcon icon={faChartLine} fixedWidth /> 152 </Button> 153 <Button title="Show stacked graph" onClick={() => this.props.onChangeStacking(true)} active={this.props.stacked}> 154 <FontAwesomeIcon icon={faChartArea} fixedWidth /> 155 </Button> 156 </ButtonGroup> 157 158 <Input 159 type="select" 160 value={this.props.maxSourceResolution} 161 onChange={this.handleMaxSourceResChange} 162 className="max-source-resolution-input" 163 bsSize="sm" 164 > 165 <option value="auto">Auto downsampling</option> 166 <option value="0s">Only raw data</option> 167 <option value="5m">Max 5m downsampling</option> 168 <option value="1h">Max 1h downsampling</option> 169 </Input> 170 </Form> 171 ); 172 } 173 } 174 175 export default GraphControls;