Adding time query to dashboard and fixing edge cases

This commit is contained in:
Mike Shi 2023-10-27 21:36:25 -07:00
parent 2e5883c684
commit cf488a7fa8
5 changed files with 185 additions and 43 deletions

View file

@ -0,0 +1,3 @@
module.exports = async () => {
process.env.TZ = 'America/New_York';
};

View file

@ -2,7 +2,7 @@ module.exports = {
preset: 'ts-jest/presets/js-with-ts',
testEnvironment: '@deploysentinel/jest-rtl-debugger/environment',
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
globalSetup: '@deploysentinel/jest-rtl-debugger/globalSetup',
globalSetup: '<rootDir>/global-setup.js',
roots: ['<rootDir>/src'],
transform: {
'^.+\\.tsx?$': 'ts-jest',

View file

@ -34,7 +34,7 @@ import TabBar from './TabBar';
import HDXHistogramChart from './HDXHistogramChart';
import api from './api';
import { LogTableWithSidePanel } from './LogTableWithSidePanel';
import { parseTimeQuery, useTimeQuery } from './timeQuery';
import { parseTimeQuery, useNewTimeQuery, useTimeQuery } from './timeQuery';
import {
EditSearchChartForm,
EditMarkdownChartForm,
@ -535,7 +535,7 @@ function DashboardFilter({
}
// TODO: This is a hack to set the default time range
const defaultTimeRange = parseTimeQuery('Past 1h', false);
const defaultTimeRange = parseTimeQuery('Past 1h', false) as [Date, Date];
export default function DashboardPage() {
const { data: dashboardsData, isLoading: isDashboardsLoading } =
api.useDashboards();
@ -622,19 +622,17 @@ export default function DashboardPage() {
const [editedChart, setEditedChart] = useState<undefined | Chart>();
const {
searchedTimeRange,
displayedTimeInputValue,
setDisplayedTimeInputValue,
onSearch,
} = useTimeQuery({
isUTC: false,
defaultValue: 'Past 1h',
defaultTimeRange: [
defaultTimeRange?.[0]?.getTime() ?? -1,
defaultTimeRange?.[1]?.getTime() ?? -1,
],
});
const { searchedTimeRange, displayedTimeInputValue, onSearch } =
useNewTimeQuery({
isUTC: false,
initialDisplayValue: 'Past 1h',
initialTimeRange: defaultTimeRange,
});
const [input, setInput] = useState<string>(displayedTimeInputValue);
useEffect(() => {
setInput(displayedTimeInputValue);
}, [displayedTimeInputValue]);
const onAddChart = () => {
setEditedChart({
@ -766,13 +764,13 @@ export default function DashboardPage() {
className="d-flex align-items-center"
onSubmit={e => {
e.preventDefault();
onSearch(displayedTimeInputValue);
onSearch(input);
}}
style={{ height: 33 }}
>
<SearchTimeRangePicker
inputValue={displayedTimeInputValue}
setInputValue={setDisplayedTimeInputValue}
inputValue={input}
setInputValue={setInput}
onSearch={range => {
onSearch(range);
}}

View file

@ -106,7 +106,18 @@ describe('useTimeQuery tests', () => {
const timeQueryRef = React.createRef<UseTimeQueryReturnType>();
testRouter.replace('/search?tq=Last+4H');
render(
const { rerender } = render(
<TestWrapper>
<TestComponent
isUTC={false}
initialTimeRange={getLiveTailTimeRange()}
ref={timeQueryRef}
/>
</TestWrapper>,
);
jest.runAllTimers();
rerender(
<TestWrapper>
<TestComponent
isUTC={false}
@ -129,6 +140,125 @@ describe('useTimeQuery tests', () => {
);
});
it('browser navigation of from/to qparmas updates the searched time range', async () => {
const timeQueryRef = React.createRef<UseTimeQueryReturnType>();
testRouter.setIsReady(false);
testRouter.replace('/search');
const result = render(
<TestWrapper>
<TestComponent
initialDisplayValue="Past 1h"
isUTC={false}
initialTimeRange={getLiveTailTimeRange()}
ref={timeQueryRef}
/>
</TestWrapper>,
);
jest.runAllTimers();
testRouter.setIsReady(true);
result.rerender(
<TestWrapper>
<TestComponent
initialDisplayValue="Past 1h"
isUTC={false}
initialTimeRange={getLiveTailTimeRange()}
ref={timeQueryRef}
/>
</TestWrapper>,
);
expect(timeQueryRef.current?.displayedTimeInputValue).toMatchInlineSnapshot(
`"Past 1h"`,
);
expect(timeQueryRef.current?.searchedTimeRange).toMatchInlineSnapshot(`
Array [
2023-10-03T15:45:00.000Z,
2023-10-03T16:00:00.000Z,
]
`);
// 10/03/23 from 04:00am EDT to 08:00am EDT
testRouter.replace('/search?from=1696320000000&to=1696334400000');
result.rerender(
<TestWrapper>
<TestComponent
initialDisplayValue="Past 1h"
isUTC={false}
initialTimeRange={getLiveTailTimeRange()}
ref={timeQueryRef}
/>
</TestWrapper>,
);
result.rerender(
<TestWrapper>
<TestComponent
initialDisplayValue="Past 1h"
isUTC={false}
initialTimeRange={getLiveTailTimeRange()}
ref={timeQueryRef}
/>
</TestWrapper>,
);
expect(timeQueryRef.current?.displayedTimeInputValue).toMatchInlineSnapshot(
`"Oct 3 04:00:00 - Oct 3 08:00:00"`,
);
expect(timeQueryRef.current?.searchedTimeRange).toMatchInlineSnapshot(`
Array [
2023-10-03T08:00:00.000Z,
2023-10-03T12:00:00.000Z,
]
`);
});
it('overrides initial value with async updated `from` and `to` params', async () => {
const timeQueryRef = React.createRef<UseTimeQueryReturnType>();
// 10/03/23 from 04:00am EDT to 08:00am EDT
testRouter.setIsReady(false);
testRouter.replace('/search');
const result = render(
<TestWrapper>
<TestComponent
initialDisplayValue="Past 1h"
isUTC={false}
initialTimeRange={getLiveTailTimeRange()}
ref={timeQueryRef}
/>
</TestWrapper>,
);
jest.runAllTimers();
testRouter.replace('/search?from=1696320000000&to=1696334400000');
testRouter.setIsReady(true);
result.rerender(
<TestWrapper>
<TestComponent
initialDisplayValue="Past 1h"
isUTC={false}
initialTimeRange={getLiveTailTimeRange()}
ref={timeQueryRef}
/>
</TestWrapper>,
);
expect(timeQueryRef.current?.displayedTimeInputValue).toMatchInlineSnapshot(
`"Oct 3 04:00:00 - Oct 3 08:00:00"`,
);
expect(timeQueryRef.current?.searchedTimeRange).toMatchInlineSnapshot(`
Array [
2023-10-03T08:00:00.000Z,
2023-10-03T12:00:00.000Z,
]
`);
});
it('accepts `from` and `to` url params', async () => {
const timeQueryRef = React.createRef<UseTimeQueryReturnType>();
// 10/03/23 from 04:00am EDT to 08:00am EDT
@ -178,7 +308,18 @@ describe('useTimeQuery tests', () => {
'/search?from=1696320000000&to=1696334400000&tq=Past+1h',
);
render(
const result = render(
<TestWrapper>
<TestComponent
isUTC={false}
initialTimeRange={getLiveTailTimeRange()}
ref={timeQueryRef}
/>
</TestWrapper>,
);
jest.runAllTimers();
result.rerender(
<TestWrapper>
<TestComponent
isUTC={false}

View file

@ -459,45 +459,45 @@ export function useNewTimeQuery({
},
);
const initialFrom = useRef(from);
const initialTo = useRef(to);
const initialInputTimeQuery = useRef(inputTimeQuery);
const initializedTimeRange = useRef(false);
const onSearch = useCallback(
(timeQuery: string) => {
const [start, end] = parseTimeQuery(timeQuery, isUTC);
// TODO: Add validation UI
if (start != null && end != null) {
setSearchedTimeRange([start, end]);
setTimeRangeQuery({ from: start.getTime(), to: end.getTime() });
const dateRangeStr = dateRangeToString([start, end], isUTC);
setDisplayedTimeInputValue(dateRangeStr);
}
},
[isUTC, setTimeRangeQuery, setDisplayedTimeInputValue],
[isUTC, setTimeRangeQuery],
);
useEffect(() => {
// On mount, we check if there is a `from` and `to` that we should use
// and if there isn't an inputTimeQuery
if (
initialFrom.current &&
initialTo.current &&
!initialInputTimeQuery.current &&
!initializedTimeRange.current
) {
initializedTimeRange.current = true;
const start = new Date(initialFrom.current);
const end = new Date(initialTo.current);
if (from != null && to != null && inputTimeQuery == null && isReady) {
const start = new Date(from);
const end = new Date(to);
if (isValid(start) && isValid(end)) {
setSearchedTimeRange([start, end]);
setTimeRangeQuery({ from: start.getTime(), to: end.getTime() });
const dateRangeStr = dateRangeToString([start, end], isUTC);
setDisplayedTimeInputValue(dateRangeStr);
}
} else if (
from == null &&
to == null &&
inputTimeQuery == null &&
isReady
) {
setSearchedTimeRange(initialTimeRange);
const dateRangeStr = dateRangeToString(initialTimeRange, isUTC);
setDisplayedTimeInputValue(initialDisplayValue ?? dateRangeStr);
}
}, [isUTC, setTimeRangeQuery]);
}, [
isReady,
inputTimeQuery,
isUTC,
from,
to,
initialDisplayValue,
initialTimeRange,
]);
useEffect(() => {
// If there is a `tq` param passed in, use it to set the time range and