github.com/grafana/pyroscope@v1.18.0/public/app/components/DateRangePicker.tsx (about) 1 import React, { useState } from 'react'; 2 3 import { useAppDispatch, useAppSelector } from '@pyroscope/redux/hooks'; 4 import { 5 setDateRange, 6 selectContinuousState, 7 } from '@pyroscope/redux/reducers/continuous'; 8 import cx from 'classnames'; 9 import Button from '@pyroscope/ui/Button'; 10 import { readableRange } from '@pyroscope/util/formatDate'; 11 import { faClock } from '@fortawesome/free-solid-svg-icons/faClock'; 12 import OutsideClickHandler from 'react-outside-click-handler'; 13 import useTimeZone from '@pyroscope/hooks/timeZone.hook'; 14 import CustomDatePicker from './CustomDatePicker'; 15 import CheckIcon from './CheckIcon'; 16 17 const defaultPresets = [ 18 [ 19 { label: 'Last 5 minutes', from: 'now-5m', until: 'now' }, 20 { label: 'Last 15 minutes', from: 'now-15m', until: 'now' }, 21 { label: 'Last 30 minutes', from: 'now-30m', until: 'now' }, 22 { label: 'Last 1 hour', from: 'now-1h', until: 'now' }, 23 { label: 'Last 3 hours', from: 'now-3h', until: 'now' }, 24 { label: 'Last 6 hours', from: 'now-6h', until: 'now' }, 25 { label: 'Last 12 hours', from: 'now-12h', until: 'now' }, 26 { label: 'Last 24 hours', from: 'now-24h', until: 'now' }, 27 ], 28 [ 29 { label: 'Last 2 days', from: 'now-2d', until: 'now' }, 30 { label: 'Last 7 days', from: 'now-7d', until: 'now' }, 31 { label: 'Last 30 days', from: 'now-30d', until: 'now' }, 32 { label: 'Last 90 days', from: 'now-90d', until: 'now' }, 33 ], 34 ]; 35 36 function findPreset(from: string, until = 'now') { 37 return defaultPresets 38 .flat() 39 .filter((a) => a.until === until) 40 .find((a) => from === a.from); 41 } 42 43 function dateToLabel(from: string, until: string, offsetInMinutes: number) { 44 const preset = findPreset(from, until); 45 46 if (preset) { 47 return preset.label; 48 } 49 50 return readableRange(from, until, offsetInMinutes); 51 } 52 53 function DateRangePicker() { 54 const dispatch = useAppDispatch(); 55 const { offset } = useTimeZone(); 56 const { from, until } = useAppSelector(selectContinuousState); 57 const [opened, setOpened] = useState(false); 58 59 const toggleDropdown = () => { 60 setOpened(!opened); 61 }; 62 63 const hideDropdown = () => { 64 setOpened(false); 65 }; 66 const selectPreset = ({ from, until }: { from: string; until: string }) => { 67 dispatch(setDateRange({ from, until })); 68 setOpened(false); 69 }; 70 71 const isPresetSelected = (preset: (typeof defaultPresets)[0][0]) => { 72 return preset.label === dateToLabel(from, until, offset); 73 }; 74 75 const handleChangeDataRange = (from: string, until: string) => { 76 dispatch(setDateRange({ from, until })); 77 }; 78 79 return ( 80 <div className={opened ? 'drp-container opened' : 'drp-container'}> 81 <OutsideClickHandler onOutsideClick={hideDropdown}> 82 <Button 83 data-testid="time-dropdown-button" 84 icon={faClock} 85 onClick={toggleDropdown} 86 > 87 {dateToLabel(from, until, offset)} 88 </Button> 89 <div className="drp-dropdown"> 90 <div className="drp-quick-presets"> 91 <h4>Quick Presets</h4> 92 <div className="drp-presets"> 93 {defaultPresets.map((arr, i) => ( 94 <div key={`preset-${i + 1}`} className="drp-preset-column"> 95 {arr.map((x) => ( 96 <button 97 type="button" 98 className={cx( 99 'drp-preset', 100 isPresetSelected(x) && 'active' 101 )} 102 key={x.label} 103 onClick={() => selectPreset(x)} 104 > 105 {x.label} 106 {isPresetSelected(x) ? <CheckIcon /> : false} 107 </button> 108 ))} 109 </div> 110 ))} 111 </div> 112 </div> 113 <CustomDatePicker 114 from={from} 115 until={until} 116 onSubmit={handleChangeDataRange} 117 /> 118 </div> 119 </OutsideClickHandler> 120 </div> 121 ); 122 } 123 124 export default DateRangePicker;