Skip to content
This repository was archived by the owner on May 13, 2025. It is now read-only.

Commit 4fa3439

Browse files
authored
Fix: URL params (#371)
1 parent 7d46c04 commit 4fa3439

File tree

10 files changed

+218
-53
lines changed

10 files changed

+218
-53
lines changed

playwright.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ export default defineConfig({
2121
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
2222
trace: 'on-first-retry',
2323
},
24+
timeout: 20000, // Timeout for each test
25+
expect: {
26+
timeout: 20000, // Timeout for `expect` assertions
27+
},
2428

2529
/* Configure projects for major browsers */
2630
projects: [

src/hooks/useQueryLogs.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export const useQueryLogs = () => {
5757
setLogsStore,
5858
] = useLogsStore((store) => store);
5959
const [appliedQuery] = useFilterStore((store) => store.appliedQuery);
60+
const [isQueryFromParams] = useFilterStore((store) => store.isQueryFromParams);
6061
const { isQuerySearchActive, custSearchQuery, activeMode } = custQuerySearchState;
6162

6263
const getColumnFilters = useCallback(
@@ -99,14 +100,17 @@ export const useQueryLogs = () => {
99100
() => {
100101
refetchSchema();
101102
if (isQuerySearchActive) {
102-
if (activeMode === 'filters') {
103+
if (activeMode === 'filters' && isQueryFromParams === false) {
103104
const { parsedQuery } = parseQuery(queryEngine, appliedQuery, currentStream || '', {
104105
startTime: timeRange.startTime,
105106
endTime: timeRange.endTime,
106107
timePartitionColumn,
107108
});
108109
const queryStrWithOffset = appendOffsetToQuery(parsedQuery, defaultQueryOpts.pageOffset);
109110
return getQueryResultWithHeaders({ ...defaultQueryOpts, access: [] }, queryStrWithOffset);
111+
} else if (activeMode === 'filters' && isQueryFromParams === true) {
112+
const queryStrWithOffset = appendOffsetToQuery(custSearchQuery, defaultQueryOpts.pageOffset);
113+
return getQueryResultWithHeaders({ ...defaultQueryOpts, access: [] }, queryStrWithOffset);
110114
} else {
111115
const queryStrWithOffset = appendOffsetToQuery(custSearchQuery, defaultQueryOpts.pageOffset);
112116
return getQueryResultWithHeaders({ ...defaultQueryOpts, access: [] }, queryStrWithOffset);

src/pages/Stream/Views/Explore/Footer.tsx

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FC, useCallback } from 'react';
1+
import { FC, useCallback, useEffect } from 'react';
22
import { useLogsStore, logsStoreReducers, LOAD_LIMIT, LOG_QUERY_LIMITS } from '../../providers/LogsProvider';
33
import { usePagination } from '@mantine/hooks';
44
import { Box, Center, Group, Loader, Menu, Pagination, Stack, Tooltip } from '@mantine/core';
@@ -90,14 +90,29 @@ const LimitControl: FC = () => {
9090

9191
const Footer = (props: { loaded: boolean; hasNoData: boolean; isFetchingCount: boolean }) => {
9292
const [tableOpts, setLogsStore] = useLogsStore((store) => store.tableOpts);
93-
const { totalPages, currentOffset, currentPage, perPage, totalCount } = tableOpts;
93+
const { totalPages, currentOffset, currentPage, perPage, totalCount, targetPage } = tableOpts;
9494

95-
const onPageChange = useCallback((page: number) => {
96-
setLogsStore((store) => setRowNumber(store, ''));
97-
setLogsStore((store) => setPageAndPageData(store, page));
98-
}, []);
95+
const onPageChange = useCallback(
96+
(page: number) => {
97+
setLogsStore((store) => setPageAndPageData(store, page));
98+
if (props.loaded && !targetPage) {
99+
setLogsStore((store) => setRowNumber(store, ''));
100+
}
101+
},
102+
[props.loaded, targetPage],
103+
);
104+
105+
useEffect(() => {
106+
if (!props.loaded) return;
107+
pagination.setPage(targetPage ? targetPage : 1);
108+
}, [props.loaded]);
109+
110+
const pagination = usePagination({
111+
total: totalPages ?? 1,
112+
initialPage: 1,
113+
onChange: onPageChange,
114+
});
99115

100-
const pagination = usePagination({ total: totalPages ?? 1, initialPage: 1, onChange: onPageChange });
101116
const onChangeOffset = useCallback(
102117
(key: 'prev' | 'next') => {
103118
if (key === 'prev') {
@@ -132,7 +147,7 @@ const Footer = (props: { loaded: boolean; hasNoData: boolean; isFetchingCount: b
132147
total={totalPages}
133148
value={currentPage}
134149
onChange={(page) => {
135-
pagination.setPage(page);
150+
pagination && pagination.setPage(page);
136151
}}
137152
size="sm">
138153
<Group gap={5} justify="center">
@@ -172,23 +187,6 @@ const Footer = (props: { loaded: boolean; hasNoData: boolean; isFetchingCount: b
172187
) : null}
173188
</Stack>
174189
<Stack w="100%" align="flex-end" style={{ flexDirection: 'row', justifyContent: 'flex-end' }}>
175-
{/* {props.loaded && (
176-
<Menu position="top">
177-
<Menu.Target>
178-
<div>
179-
<IconButton renderIcon={renderExportIcon} />
180-
</div>
181-
</Menu.Target>
182-
<Menu.Dropdown>
183-
<Menu.Item onClick={() => exportHandler('CSV')} style={{ padding: '0.5rem 2.25rem 0.5rem 0.75rem' }}>
184-
CSV
185-
</Menu.Item>
186-
<Menu.Item onClick={() => exportHandler('JSON')} style={{ padding: '0.5rem 2.25rem 0.5rem 0.75rem' }}>
187-
JSON
188-
</Menu.Item>
189-
</Menu.Dropdown>
190-
</Menu>
191-
)} */}
192190
<LimitControl />
193191
</Stack>
194192
</Stack>

src/pages/Stream/Views/Explore/LogsView.tsx

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
import { Box } from '@mantine/core';
2-
import { useLogsStore } from '../../providers/LogsProvider';
2+
import { useLogsStore, logsStoreReducers } from '../../providers/LogsProvider';
33
import JsonView from './JSONView';
44
import LogTable from './StaticLogTable';
55
import useLogsFetcher from './useLogsFetcher';
66
import LogsViewConfig from './LogsViewConfig';
7+
import { useFilterStore, filterStoreReducers } from '../../providers/FilterProvider';
8+
9+
import { useEffect } from 'react';
10+
import _ from 'lodash';
11+
12+
const { setPageAndPageData, setTargetPage, setTargetColumns, setDisabledColumns } = logsStoreReducers;
13+
const { toogleQueryParamsFlag } = filterStoreReducers;
714

815
const LogsView = (props: { schemaLoading: boolean; infoLoading: boolean }) => {
16+
const [, setFilterStore] = useFilterStore((store) => store);
917
const { schemaLoading, infoLoading } = props;
1018
const { errorMessage, hasNoData, showTable, isFetchingCount, logsLoading } = useLogsFetcher({
1119
schemaLoading,
1220
infoLoading,
1321
});
1422

15-
const [viewMode] = useLogsStore((store) => store.viewMode);
23+
const [tableOpts] = useLogsStore((store) => store.tableOpts);
24+
const { currentPage, targetPage, headers, targetColumns } = tableOpts;
25+
const [viewMode, setLogsStore] = useLogsStore((store) => store.viewMode);
1626
const viewOpts = {
1727
errorMessage,
1828
hasNoData,
@@ -21,6 +31,30 @@ const LogsView = (props: { schemaLoading: boolean; infoLoading: boolean }) => {
2131
logsLoading,
2232
};
2333

34+
useEffect(() => {
35+
if (!showTable) return;
36+
if (targetPage) {
37+
setLogsStore((store) => setPageAndPageData(store, targetPage));
38+
if (currentPage === targetPage) {
39+
setLogsStore((store) => setTargetPage(store, undefined));
40+
}
41+
}
42+
if (showTable) setFilterStore((store) => toogleQueryParamsFlag(store, false));
43+
}, [showTable, currentPage]);
44+
45+
useEffect(() => {
46+
if (!showTable) return;
47+
if (!_.isEmpty(targetColumns)) {
48+
setLogsStore((store) =>
49+
setDisabledColumns(
50+
store,
51+
headers.filter((el) => !targetColumns.includes(el)),
52+
),
53+
);
54+
setLogsStore((store) => setTargetColumns(store, []));
55+
}
56+
}, [headers]);
57+
2458
return (
2559
<Box style={{ display: 'flex', flex: 1, overflow: 'hidden' }}>
2660
{viewMode === 'table' && (

src/pages/Stream/Views/Explore/useLogsFetcher.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const useLogsFetcher = (props: { schemaLoading: boolean; infoLoading: boolean })
3131
useEffect(() => {
3232
if (infoLoading || !firstEventAt) return;
3333

34-
if (currentPage === 0 && currentOffset === 0) {
34+
if (currentPage === 0) {
3535
getQueryData();
3636
refetchCount();
3737
}

src/pages/Stream/components/Querier/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ const Querier = () => {
133133
}, []);
134134
const [schema] = useStreamStore((store) => store.schema);
135135
const [streamInfo] = useStreamStore((store) => store.info);
136-
const [{ query, isSumbitDisabled }, setFilterStore] = useFilterStore((store) => store);
136+
const [{ query, isSumbitDisabled, isQueryFromParams }, setFilterStore] = useFilterStore((store) => store);
137137
const timePartitionColumn = _.get(streamInfo, 'time_partition', 'p_timestamp');
138138

139139
useEffect(() => {
@@ -202,7 +202,7 @@ const Querier = () => {
202202

203203
// trigger query fetch if the rules were updated by the remove btn on pills
204204
// -----------------------------------
205-
if (!showQueryBuilder && (activeMode === 'filters' || savedFilterId)) {
205+
if (!showQueryBuilder && (activeMode === 'filters' || savedFilterId) && !isQueryFromParams) {
206206
if (!shouldSumbitDisabled) {
207207
onFiltersApply({ isUncontrolled: true });
208208
} else {

src/pages/Stream/hooks/useParamsController.ts

Lines changed: 74 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,32 @@ import { useLogsStore, logsStoreReducers } from '@/pages/Stream/providers/LogsPr
33
import { useSearchParams } from 'react-router-dom';
44
import _ from 'lodash';
55
import { FIXED_DURATIONS } from '@/constants/timeConstants';
6-
import { LOG_QUERY_LIMITS } from '@/pages/Stream/providers/LogsProvider';
6+
import { LOG_QUERY_LIMITS, columnsToSkip } from '@/pages/Stream/providers/LogsProvider';
77
import dayjs from 'dayjs';
88
import timeRangeUtils from '@/utils/timeRangeUtils';
99
import moment from 'moment-timezone';
1010
import { filterStoreReducers, QueryType, useFilterStore } from '../providers/FilterProvider';
1111
import { generateQueryBuilderASTFromSQL } from '../utils';
1212
import { appStoreReducers, TimeRange, useAppStore } from '@/layouts/MainLayout/providers/AppProvider';
13+
import { getOffset, joinOrSplit } from '@/utils';
1314

1415
const { getRelativeStartAndEndDate, formatDateWithTimezone, getLocalTimezone } = timeRangeUtils;
15-
const { onToggleView, setPerPage, setCustQuerySearchState, setRowNumber } = logsStoreReducers;
16+
1617
const { setTimeRange, syncTimeRange } = appStoreReducers;
17-
const { applySavedFilters } = filterStoreReducers;
18+
const {
19+
onToggleView,
20+
setPerPage,
21+
setCustQuerySearchState,
22+
setTargetPage,
23+
setCurrentOffset,
24+
setTargetColumns,
25+
setRowNumber,
26+
} = logsStoreReducers;
27+
const { toogleQueryParamsFlag, setAppliedFilterQuery, applySavedFilters, updateQuery, updateAppliedQuery } =
28+
filterStoreReducers;
29+
1830
const timeRangeFormat = 'DD-MMM-YYYY_HH-mmz';
19-
const keys = ['view', 'rows', 'interval', 'from', 'to', 'query', 'filterType', 'rowNumber'];
31+
const keys = ['view', 'rows', 'page', 'interval', 'from', 'to', 'query', 'filterType', 'fields', 'rowNumber'];
2032

2133
const dateToParamString = (date: Date) => {
2234
return formatDateWithTimezone(date, timeRangeFormat);
@@ -63,23 +75,24 @@ const deriveRowNumber = (rowNumber: string) => {
6375
const storeToParamsObj = (opts: {
6476
timeRange: TimeRange;
6577
view: string;
66-
offset: string;
6778
page: string;
6879
rows: string;
6980
query: string;
7081
filterType: string;
82+
fields: string;
7183
rowNumber: string;
7284
}): Record<string, string> => {
73-
const { timeRange, offset, page, view, rows, query, filterType, rowNumber } = opts;
85+
const { timeRange, page, view, rows, query, filterType, fields, rowNumber } = opts;
86+
7487
const params: Record<string, string> = {
7588
...deriveTimeRangeParams(timeRange),
7689
...deriveRowNumber(rowNumber),
7790
view,
78-
offset,
7991
rows,
8092
page,
8193
query,
8294
filterType: query ? filterType : '',
95+
fields,
8396
};
8497
return _.pickBy(params, (val, key) => !_.isEmpty(val) && _.includes(keys, key));
8598
};
@@ -104,8 +117,12 @@ const useParamsController = () => {
104117
const [, setLogsStore] = useLogsStore(() => null);
105118
const [, setFilterStore] = useFilterStore((store) => store);
106119

107-
const { currentOffset, currentPage, perPage, rowNumber } = tableOpts;
120+
const { currentOffset, currentPage, targetPage, perPage, headers, disabledColumns, targetColumns, rowNumber } =
121+
tableOpts;
122+
123+
const visibleHeaders = headers.filter((el) => !columnsToSkip.includes(el));
108124

125+
const activeHeaders = visibleHeaders.filter((el) => !disabledColumns.includes(el));
109126
const [searchParams, setSearchParams] = useSearchParams();
110127

111128
const syncRowNumber = useCallback((storeAsParams: Record<string, string>, presentParams: Record<string, string>) => {
@@ -115,35 +132,62 @@ const useParamsController = () => {
115132
}
116133
}
117134
}, []);
135+
const pageOffset = Math.ceil(currentOffset / perPage);
118136

119137
useEffect(() => {
120138
const storeAsParams = storeToParamsObj({
121139
timeRange,
122-
offset: `${currentOffset}`,
123-
page: `${currentPage}`,
140+
page: `${targetPage ? targetPage : Math.ceil(currentPage + pageOffset)}`,
124141
view: viewMode,
125142
rows: `${perPage}`,
126143
query: custQuerySearchState.custSearchQuery,
127144
filterType: custQuerySearchState.viewMode,
145+
fields: `${joinOrSplit(!_.isEmpty(targetColumns) ? targetColumns : activeHeaders)}`,
128146
rowNumber,
129147
});
130148
const presentParams = paramsStringToParamsObj(searchParams);
149+
if (storeAsParams.query !== presentParams.query) {
150+
if (presentParams.filterType === 'filters') {
151+
setFilterStore((store) => updateQuery(store, generateQueryBuilderASTFromSQL(presentParams.query) as QueryType));
152+
setFilterStore((store) => updateAppliedQuery(store, store.query));
153+
154+
setFilterStore((store) => setAppliedFilterQuery(store, presentParams.query));
155+
setFilterStore((store) => toogleQueryParamsFlag(store, true));
156+
}
157+
setAppStore((store) => syncTimeRange(store));
158+
setLogsStore((store) => setCustQuerySearchState(store, presentParams.query, presentParams.filterType));
159+
}
160+
161+
syncTimeRangeToStore(storeAsParams, presentParams);
162+
131163
if (['table', 'json'].includes(presentParams.view) && presentParams.view !== storeAsParams.view) {
132164
setLogsStore((store) => onToggleView(store, presentParams.view as 'table' | 'json'));
133165
}
134166
if (storeAsParams.rows !== presentParams.rows && LOG_QUERY_LIMITS.includes(_.toNumber(presentParams.rows))) {
135167
setLogsStore((store) => setPerPage(store, _.toNumber(presentParams.rows)));
136168
}
137169

138-
if (storeAsParams.query !== presentParams.query) {
139-
setAppStore((store) => syncTimeRange(store));
140-
setLogsStore((store) => setCustQuerySearchState(store, presentParams.query, presentParams.filterType));
141-
if (presentParams.filterType === 'filters')
142-
setFilterStore((store) =>
143-
applySavedFilters(store, generateQueryBuilderASTFromSQL(presentParams.query) as QueryType),
170+
if (storeAsParams.fields !== presentParams.fields) {
171+
setLogsStore((store) => setTargetColumns(store, joinOrSplit(presentParams.fields) as string[]));
172+
}
173+
174+
if (storeAsParams.page !== presentParams.page && !_.isEmpty(presentParams.page)) {
175+
setLogsStore((store) => setTargetPage(store, _.toNumber(presentParams.page)));
176+
177+
const offset = getOffset(_.toNumber(presentParams.page), _.toNumber(presentParams.rows));
178+
179+
if (offset > 0) {
180+
setLogsStore((store) => setCurrentOffset(store, offset));
181+
182+
setLogsStore((store) =>
183+
setTargetPage(
184+
store,
185+
Math.abs(_.toNumber(presentParams.page) - Math.ceil(offset / _.toNumber(presentParams.rows))),
186+
),
144187
);
188+
}
145189
}
146-
syncTimeRangeToStore(storeAsParams, presentParams);
190+
147191
syncRowNumber(storeAsParams, presentParams);
148192
setStoreSynced(true);
149193
}, []);
@@ -152,31 +196,39 @@ const useParamsController = () => {
152196
if (isStoreSynced) {
153197
const storeAsParams = storeToParamsObj({
154198
timeRange,
155-
offset: `${currentOffset}`,
156-
page: `${currentPage}`,
199+
page: `${targetPage ? targetPage : Math.ceil(currentPage + pageOffset)}`,
157200
view: viewMode,
158201
rows: `${perPage}`,
159202
query: custQuerySearchState.custSearchQuery,
160203
filterType: custQuerySearchState.viewMode,
204+
fields: `${joinOrSplit(!_.isEmpty(targetColumns) ? targetColumns : activeHeaders)}`,
161205
rowNumber,
162206
});
207+
163208
const presentParams = paramsStringToParamsObj(searchParams);
164209
if (_.isEqual(storeAsParams, presentParams)) return;
165210
setSearchParams(storeAsParams);
166211
}
167-
}, [tableOpts, viewMode, timeRange.startTime.toISOString(), timeRange.endTime.toISOString(), custQuerySearchState]);
212+
}, [
213+
tableOpts,
214+
targetPage,
215+
viewMode,
216+
timeRange.startTime.toISOString(),
217+
timeRange.endTime.toISOString(),
218+
custQuerySearchState,
219+
]);
168220

169221
useEffect(() => {
170222
if (!isStoreSynced) return;
171223

172224
const storeAsParams = storeToParamsObj({
173225
timeRange,
174-
offset: `${currentOffset}`,
175-
page: `${currentPage}`,
226+
page: `${targetPage ? targetPage : Math.ceil(currentPage + pageOffset)}`,
176227
view: viewMode,
177228
rows: `${perPage}`,
178229
query: custQuerySearchState.custSearchQuery,
179230
filterType: custQuerySearchState.viewMode,
231+
fields: `${joinOrSplit(!_.isEmpty(targetColumns) ? targetColumns : activeHeaders)}`,
180232
rowNumber,
181233
});
182234
const presentParams = paramsStringToParamsObj(searchParams);

0 commit comments

Comments
 (0)