Mirror of https://github.com/roostorg/osprey
github.com/roostorg/osprey
1import * as React from 'react';
2import { Route, RouteComponentProps } from 'react-router-dom';
3
4import useQueryStore from '../../stores/QueryStore';
5import { DefaultIntervals } from '../../types/QueryTypes';
6import { startRecordingClicks, stopRecordingClicks } from '../../utils/EventListenerUtils';
7import { getQueryDateRange, CUSTOM_RANGE_OPTION } from '../../utils/QueryUtils';
8import BulkLabelDrawer from '../bulk_label_drawer/BulkLabelDrawer';
9import EntityFeatureFilters from '../entities/EntityFeatureFilters';
10import FeatureFiltersDetailBar from '../entities/FeatureFiltersDetailBar';
11import EntityDrawer from '../entities/LabelDrawer';
12import EventStream from '../event_stream/EventStream';
13import Timeseries from '../timeseries/Timeseries';
14import TopN from '../top_n/TopN';
15import Charts from '../charts/Charts';
16import QueryDatePicker from './QueryDatePicker';
17import QueryPanel from './QueryPanel';
18
19import { Routes } from '../../Constants';
20import styles from './QueryView.module.css';
21
22const QueryView: React.FC = () => {
23 const executedQuery = useQueryStore((state) => state.executedQuery);
24 const updateExecutedQuery = useQueryStore((state) => state.updateExecutedQuery);
25 const [interval, setQueryInterval] = React.useState(executedQuery.interval);
26 const [dateRange, setDateRange] = React.useState({ start: executedQuery.start, end: executedQuery.end });
27
28 React.useEffect(() => {
29 setQueryInterval(executedQuery.interval);
30 setDateRange({ start: executedQuery.start, end: executedQuery.end });
31 }, [executedQuery]);
32
33 React.useEffect(() => {
34 document.addEventListener('keydown', startRecordingClicks);
35 document.addEventListener('keyup', stopRecordingClicks);
36
37 return () => {
38 document.removeEventListener('keydown', startRecordingClicks);
39 document.removeEventListener('keyup', stopRecordingClicks);
40 };
41 }, []);
42
43 const isDateRangeEmpty = (): boolean => {
44 return dateRange.start === '' && dateRange.end === '';
45 };
46
47 const handleIntervalChange = (interval: DefaultIntervals | 'custom' | null) => {
48 setQueryInterval(interval);
49
50 if (interval !== CUSTOM_RANGE_OPTION)
51 updateExecutedQuery({ ...executedQuery, interval, ...getQueryDateRange(interval) });
52 };
53
54 const handleDateRangeChange = (updatedDateRange: { start: string; end: string }) => {
55 setDateRange(updatedDateRange);
56 updateExecutedQuery({ ...executedQuery, interval, ...updatedDateRange });
57 };
58
59 return (
60 <>
61 <div className={styles.queryView}>
62 <div className={styles.pageContentLeft}>
63 <QueryPanel onIntervalChange={handleIntervalChange} interval={interval} dateRange={dateRange} />
64 </div>
65 <div className={styles.pageContentRight}>
66 <div className={isDateRangeEmpty() ? styles.datePickerBarHidden : styles.datePickerBarShown}>
67 <QueryDatePicker
68 onIntervalChange={handleIntervalChange}
69 onDateRangeChange={handleDateRangeChange}
70 interval={interval}
71 dateRange={dateRange}
72 />
73 <Route
74 path={Routes.ENTITY}
75 // @ts-expect-error (yarn.lock upgrade)
76 render={({ match }: RouteComponentProps<{ entityId: string; entityType: string }>) => (
77 <EntityFeatureFilters {...match.params} />
78 )}
79 />
80 </div>
81 <Route path={Routes.ENTITY}>
82 <FeatureFiltersDetailBar />
83 </Route>
84 <div className={styles.charts}>
85 <div className={styles.chartsLeft}>
86 <Timeseries />
87 <Charts />
88 <TopN />
89 </div>
90 <div className={styles.chartsRight}>
91 <EventStream />
92 </div>
93 </div>
94 <BulkLabelDrawer />
95 <EntityDrawer />
96 </div>
97 </div>
98 </>
99 );
100};
101
102export default QueryView;