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