Skip to content

Commit 9d4d454

Browse files
refactor(QueriesHistory): move queries manipulations to hook
1 parent 85a3075 commit 9d4d454

File tree

8 files changed

+165
-149
lines changed

8 files changed

+165
-149
lines changed

src/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1+
import React from 'react';
2+
13
import type {Column} from '@gravity-ui/react-data-table';
24

35
import {ResizeableDataTable} from '../../../../components/ResizeableDataTable/ResizeableDataTable';
46
import {Search} from '../../../../components/Search';
57
import {TableWithControlsLayout} from '../../../../components/TableWithControlsLayout/TableWithControlsLayout';
68
import {TruncatedQuery} from '../../../../components/TruncatedQuery/TruncatedQuery';
79
import {
8-
selectQueriesHistory,
910
selectQueriesHistoryFilter,
1011
setIsDirty,
1112
setQueryHistoryFilter,
1213
} from '../../../../store/reducers/query/query';
1314
import type {QueryInHistory} from '../../../../store/reducers/query/types';
15+
import {useQueriesHistory} from '../../../../store/reducers/query/useQueriesHistory';
1416
import {TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
1517
import {setQueryTab} from '../../../../store/reducers/tenant/tenant';
1618
import {cn} from '../../../../utils/cn';
@@ -34,9 +36,13 @@ interface QueriesHistoryProps {
3436
function QueriesHistory({changeUserInput}: QueriesHistoryProps) {
3537
const dispatch = useTypedDispatch();
3638

37-
const queriesHistory = useTypedSelector(selectQueriesHistory);
39+
const {filteredHistoryQueries} = useQueriesHistory();
40+
41+
const reversedHistory = React.useMemo(() => {
42+
return [...filteredHistoryQueries].reverse();
43+
}, [filteredHistoryQueries]);
44+
3845
const filter = useTypedSelector(selectQueriesHistoryFilter);
39-
const reversedHistory = [...queriesHistory].reverse();
4046

4147
const applyQueryClick = (query: QueryInHistory) => {
4248
changeUserInput({input: query.queryText});

src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,13 @@ import {
1111
} from '../../../../store/reducers/capabilities/hooks';
1212
import {
1313
queryApi,
14-
saveQueryToHistory,
15-
selectQueriesHistory,
16-
selectQueriesHistoryCurrentIndex,
1714
selectResult,
1815
selectTenantPath,
1916
setIsDirty,
2017
setTenantPath,
2118
} from '../../../../store/reducers/query/query';
2219
import type {QueryResult} from '../../../../store/reducers/query/types';
20+
import {useQueriesHistory} from '../../../../store/reducers/query/useQueriesHistory';
2321
import {setQueryAction} from '../../../../store/reducers/queryActions/queryActions';
2422
import {selectShowPreview, setShowPreview} from '../../../../store/reducers/schema/schema';
2523
import {SETTING_KEYS} from '../../../../store/reducers/settings/constants';
@@ -77,10 +75,11 @@ export default function QueryEditor(props: QueryEditorProps) {
7775
const {theme, changeUserInput} = props;
7876
const savedPath = useTypedSelector(selectTenantPath);
7977
const result = useTypedSelector(selectResult);
80-
const historyQueries = useTypedSelector(selectQueriesHistory);
81-
const historyCurrentIndex = useTypedSelector(selectQueriesHistoryCurrentIndex);
8278
const showPreview = useTypedSelector(selectShowPreview);
8379

80+
const {historyQueries, historyCurrentIndex, saveQueryToHistory, updateQueryInHistory} =
81+
useQueriesHistory();
82+
8483
const isResultLoaded = Boolean(result);
8584

8685
const [querySettings] = useQueryExecutionSettings();
@@ -182,6 +181,12 @@ export default function QueryEditor(props: QueryEditorProps) {
182181
base64: encodeTextWithBase64,
183182
});
184183

184+
query.then(({data}) => {
185+
if (data?.queryId) {
186+
updateQueryInHistory(data.queryId, data?.queryStats);
187+
}
188+
});
189+
185190
queryManagerInstance.registerQuery(query);
186191
}
187192

@@ -190,7 +195,7 @@ export default function QueryEditor(props: QueryEditorProps) {
190195
// Don't save partial queries in history
191196
if (!partial) {
192197
if (text !== historyQueries[historyCurrentIndex]?.queryText) {
193-
dispatch(saveQueryToHistory({queryText: text, queryId}));
198+
saveQueryToHistory(text, queryId);
194199
}
195200
dispatch(setIsDirty(false));
196201
}

src/containers/Tenant/Query/QueryEditor/YqlEditor.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,8 @@ import throttle from 'lodash/throttle';
66
import type Monaco from 'monaco-editor';
77

88
import {MonacoEditor} from '../../../../components/MonacoEditor/MonacoEditor';
9-
import {
10-
goToNextQuery,
11-
goToPreviousQuery,
12-
selectQueriesHistory,
13-
selectUserInput,
14-
setIsDirty,
15-
} from '../../../../store/reducers/query/query';
9+
import {selectUserInput, setIsDirty} from '../../../../store/reducers/query/query';
10+
import {useQueriesHistory} from '../../../../store/reducers/query/useQueriesHistory';
1611
import {SETTING_KEYS} from '../../../../store/reducers/settings/constants';
1712
import type {QueryAction} from '../../../../types/store/query';
1813
import {
@@ -49,7 +44,7 @@ export function YqlEditor({
4944
const dispatch = useTypedDispatch();
5045
const [monacoGhostInstance, setMonacoGhostInstance] =
5146
React.useState<ReturnType<typeof createMonacoGhostInstance>>();
52-
const historyQueries = useTypedSelector(selectQueriesHistory);
47+
const {historyQueries, goToPreviousQuery, goToNextQuery} = useQueriesHistory();
5348
const [isCodeAssistEnabled] = useSetting(SETTING_KEYS.ENABLE_CODE_ASSISTANT);
5449

5550
const editorOptions = useEditorOptions();
@@ -160,7 +155,7 @@ export function YqlEditor({
160155
contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
161156
contextMenuOrder: 2,
162157
run: () => {
163-
dispatch(goToPreviousQuery());
158+
goToPreviousQuery();
164159
},
165160
});
166161
editor.addAction({
@@ -169,7 +164,7 @@ export function YqlEditor({
169164
contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
170165
contextMenuOrder: 3,
171166
run: () => {
172-
dispatch(goToNextQuery());
167+
goToNextQuery();
173168
},
174169
});
175170
editor.addAction({

src/containers/Tenant/Query/QueryEditor/helpers.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import type {AcceptEvent, DeclineEvent, IgnoreEvent, PromptFile} from '@ydb-plat
44
import type Monaco from 'monaco-editor';
55

66
import {codeAssistApi} from '../../../../store/reducers/codeAssist/codeAssist';
7-
import {selectQueriesHistory} from '../../../../store/reducers/query/query';
7+
import {useQueriesHistory} from '../../../../store/reducers/query/useQueriesHistory';
88
import {SETTING_KEYS} from '../../../../store/reducers/settings/constants';
99
import type {TelemetryOpenTabs} from '../../../../types/api/codeAssist';
10-
import {useSetting, useTypedSelector} from '../../../../utils/hooks';
10+
import {useSetting} from '../../../../utils/hooks';
1111
import {YQL_LANGUAGE_ID} from '../../../../utils/monaco/constats';
1212
import {useSavedQueries} from '../utils/useSavedQueries';
1313

@@ -45,7 +45,7 @@ export function useCodeAssistHelpers() {
4545
const [discardSuggestion] = codeAssistApi.useDiscardSuggestionMutation();
4646
const [ignoreSuggestion] = codeAssistApi.useIgnoreSuggestionMutation();
4747
const [sendUserQueriesData] = codeAssistApi.useSendUserQueriesDataMutation();
48-
const historyQueries = useTypedSelector(selectQueriesHistory);
48+
const {historyQueries} = useQueriesHistory();
4949
const savedQueries = useSavedQueries();
5050

5151
const getCodeAssistSuggestions = React.useCallback(

src/store/reducers/query/__test__/tabPersistence.test.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ import type {QueryState} from '../types';
44
describe('QueryResultViewer tab persistence integration', () => {
55
const initialState: QueryState = {
66
input: '',
7-
history: {
8-
queries: [],
9-
currentIndex: -1,
10-
},
117
};
128

139
test('should save and retrieve tab selection for explain queries', () => {

src/store/reducers/query/query.ts

Lines changed: 8 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {createSelector, createSlice} from '@reduxjs/toolkit';
22
import type {PayloadAction} from '@reduxjs/toolkit';
33

4-
import {settingsManager} from '../../../services/settings';
54
import {TracingLevelNumber} from '../../../types/api/query';
65
import type {QueryAction, QueryRequestParams, QuerySettings} from '../../../types/store/query';
76
import type {StreamDataChunk} from '../../../types/store/streaming';
@@ -11,25 +10,15 @@ import {isQueryErrorResponse} from '../../../utils/query';
1110
import {isNumeric} from '../../../utils/utils';
1211
import type {RootState} from '../../defaultStore';
1312
import {api} from '../api';
14-
import {SETTING_KEYS} from '../settings/constants';
1513

1614
import {prepareQueryData} from './prepareQueryData';
1715
import {
1816
addStreamingChunks as addStreamingChunksReducer,
1917
setStreamQueryResponse as setStreamQueryResponseReducer,
2018
setStreamSession as setStreamSessionReducer,
2119
} from './streamingReducers';
22-
import type {QueryResult, QueryState} from './types';
23-
import {getActionAndSyntaxFromQueryMode, getQueryInHistory, prepareQueryWithPragmas} from './utils';
24-
25-
const MAXIMUM_QUERIES_IN_HISTORY = 20;
26-
27-
const queriesHistoryInitial = settingsManager.readUserSettingsValue(
28-
SETTING_KEYS.QUERIES_HISTORY,
29-
[],
30-
) as string[];
31-
32-
const sliceLimit = queriesHistoryInitial.length - MAXIMUM_QUERIES_IN_HISTORY;
20+
import type {QueryResult, QueryState, QueryStats} from './types';
21+
import {getActionAndSyntaxFromQueryMode, prepareQueryWithPragmas} from './utils';
3322

3423
const rawQuery = loadFromSessionStorage(QUERY_EDITOR_CURRENT_QUERY_KEY);
3524
const input = typeof rawQuery === 'string' ? rawQuery : '';
@@ -39,16 +28,7 @@ const isDirty = Boolean(loadFromSessionStorage(QUERY_EDITOR_DIRTY_KEY));
3928
const initialState: QueryState = {
4029
input,
4130
isDirty,
42-
history: {
43-
queries: queriesHistoryInitial
44-
.slice(sliceLimit < 0 ? 0 : sliceLimit)
45-
.map(getQueryInHistory),
46-
currentIndex:
47-
queriesHistoryInitial.length > MAXIMUM_QUERIES_IN_HISTORY
48-
? MAXIMUM_QUERIES_IN_HISTORY - 1
49-
: queriesHistoryInitial.length - 1,
50-
filter: '',
51-
},
31+
historyFilter: '',
5232
};
5333

5434
const slice = createSlice({
@@ -66,76 +46,11 @@ const slice = createSlice({
6646
setQueryResult: (state, action: PayloadAction<QueryResult | undefined>) => {
6747
state.result = action.payload;
6848
},
69-
saveQueryToHistory: (
70-
state,
71-
action: PayloadAction<{queryText: string; queryId: string}>,
72-
) => {
73-
const {queryText, queryId} = action.payload;
74-
75-
const newQueries = [...state.history.queries, {queryText, queryId}].slice(
76-
state.history.queries.length >= MAXIMUM_QUERIES_IN_HISTORY ? 1 : 0,
77-
);
78-
settingsManager.setUserSettingsValue(SETTING_KEYS.QUERIES_HISTORY, newQueries);
79-
const currentIndex = newQueries.length - 1;
80-
81-
state.history = {
82-
queries: newQueries,
83-
currentIndex,
84-
};
85-
},
86-
updateQueryInHistory: (
87-
state,
88-
action: PayloadAction<{queryId: string; stats: QueryStats}>,
89-
) => {
90-
const {queryId, stats} = action.payload;
91-
92-
if (!stats) {
93-
return;
94-
}
95-
96-
const index = state.history.queries.findIndex((item) => item.queryId === queryId);
97-
98-
if (index === -1) {
99-
return;
100-
}
101-
102-
const newQueries = [...state.history.queries];
103-
const {durationUs, endTime} = stats;
104-
newQueries.splice(index, 1, {
105-
...state.history.queries[index],
106-
durationUs,
107-
endTime,
108-
});
109-
110-
settingsManager.setUserSettingsValue(SETTING_KEYS.QUERIES_HISTORY, newQueries);
111-
112-
state.history.queries = newQueries;
113-
},
114-
goToPreviousQuery: (state) => {
115-
const currentIndex = state.history.currentIndex;
116-
if (currentIndex <= 0) {
117-
return;
118-
}
119-
const newCurrentIndex = currentIndex - 1;
120-
const query = state.history.queries[newCurrentIndex];
121-
state.input = query.queryText;
122-
state.history.currentIndex = newCurrentIndex;
123-
},
124-
goToNextQuery: (state) => {
125-
const currentIndex = state.history.currentIndex;
126-
if (currentIndex >= state.history.queries.length - 1) {
127-
return;
128-
}
129-
const newCurrentIndex = currentIndex + 1;
130-
const query = state.history.queries[newCurrentIndex];
131-
state.input = query.queryText;
132-
state.history.currentIndex = newCurrentIndex;
133-
},
13449
setTenantPath: (state, action: PayloadAction<string>) => {
13550
state.tenantPath = action.payload;
13651
},
13752
setQueryHistoryFilter: (state, action: PayloadAction<string>) => {
138-
state.history.filter = action.payload;
53+
state.historyFilter = action.payload;
13954
},
14055
setResultTab: (
14156
state,
@@ -152,14 +67,13 @@ const slice = createSlice({
15267
setStreamQueryResponse: setStreamQueryResponseReducer,
15368
},
15469
selectors: {
155-
selectQueriesHistoryFilter: (state) => state.history.filter || '',
70+
selectQueriesHistoryFilter: (state) => state.historyFilter || '',
15671
selectTenantPath: (state) => state.tenantPath,
15772
selectResult: (state) => state.result,
15873
selectStartTime: (state) => state.result?.startTime,
15974
selectEndTime: (state) => state.result?.endTime,
16075
selectUserInput: (state) => state.input,
16176
selectIsDirty: (state) => state.isDirty,
162-
selectQueriesHistoryCurrentIndex: (state) => state.history?.currentIndex,
16377
selectResultTab: (state) => state.selectedResultTab,
16478
},
16579
});
@@ -175,27 +89,10 @@ export const selectQueryDuration = createSelector(
17589
},
17690
);
17791

178-
export const selectQueriesHistory = createSelector(
179-
[
180-
(state: RootState) => state.query.history.queries,
181-
(state: RootState) => state.query.history.filter,
182-
],
183-
(queries, filter) => {
184-
const normalizedFilter = filter?.toLowerCase();
185-
return normalizedFilter
186-
? queries.filter((item) => item.queryText.toLowerCase().includes(normalizedFilter))
187-
: queries;
188-
},
189-
);
190-
19192
export default slice.reducer;
19293
export const {
19394
changeUserInput,
19495
setQueryResult,
195-
saveQueryToHistory,
196-
updateQueryInHistory,
197-
goToPreviousQuery,
198-
goToNextQuery,
19996
setTenantPath,
20097
setQueryHistoryFilter,
20198
addStreamingChunks,
@@ -207,7 +104,6 @@ export const {
207104

208105
export const {
209106
selectQueriesHistoryFilter,
210-
selectQueriesHistoryCurrentIndex,
211107
selectTenantPath,
212108
selectResult,
213109
selectUserInput,
@@ -228,11 +124,6 @@ interface SendQueryParams extends QueryRequestParams {
228124
// Stream query receives queryId from session chunk.
229125
type StreamQueryParams = Omit<SendQueryParams, 'queryId'>;
230126

231-
interface QueryStats {
232-
durationUs?: string | number;
233-
endTime?: string | number;
234-
}
235-
236127
const DEFAULT_STREAM_CHUNK_SIZE = 1000;
237128
const DEFAULT_CONCURRENT_RESULTS = false;
238129

@@ -421,8 +312,9 @@ export const queryApi = api.injectEndpoints({
421312
const data = prepareQueryData(response);
422313
data.traceId = response?._meta?.traceId;
423314

315+
const queryStats: QueryStats = {};
316+
424317
if (actionType === 'execute') {
425-
const queryStats: QueryStats = {};
426318
if (data.stats) {
427319
const {DurationUs, Executions: [{FinishTimeMs}] = [{}]} = data.stats;
428320
queryStats.durationUs = DurationUs;
@@ -432,8 +324,6 @@ export const queryApi = api.injectEndpoints({
432324
queryStats.durationUs = (now - timeStart) * 1000;
433325
queryStats.endTime = now;
434326
}
435-
436-
dispatch(updateQueryInHistory({stats: queryStats, queryId}));
437327
}
438328

439329
dispatch(
@@ -446,7 +336,7 @@ export const queryApi = api.injectEndpoints({
446336
endTime: Date.now(),
447337
}),
448338
);
449-
return {data: null};
339+
return {data: {queryStats, queryId}};
450340
} catch (error) {
451341
const state = getState() as RootState;
452342
if (state.query.result?.startTime !== startTime) {

0 commit comments

Comments
 (0)