Skip to content

Commit b15d9e0

Browse files
authored
fix(query): Restart log queries when case-sensitivity or regex button is toggled. (#130)
1 parent 2f69e27 commit b15d9e0

File tree

7 files changed

+102
-58
lines changed

7 files changed

+102
-58
lines changed

src/components/CentralContainer/Sidebar/SidebarTabs/SearchTabPanel/ResultsGroup.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717

1818
import DescriptionOutlinedIcon from "@mui/icons-material/DescriptionOutlined";
1919

20-
import {QueryResultsType} from "../../../../../typings/worker";
20+
import {QueryResultsType} from "../../../../../typings/query";
2121
import Result from "./Result";
2222

2323
import "./ResultsGroup.css";

src/components/CentralContainer/Sidebar/SidebarTabs/SearchTabPanel/index.tsx

+40-5
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@ import UnfoldLessIcon from "@mui/icons-material/UnfoldLess";
1616
import UnfoldMoreIcon from "@mui/icons-material/UnfoldMore";
1717

1818
import {StateContext} from "../../../../../contexts/StateContextProvider";
19+
import {
20+
QUERY_PROGRESS_VALUE_MAX,
21+
QueryArgs,
22+
} from "../../../../../typings/query";
1923
import {UI_ELEMENT} from "../../../../../typings/states";
2024
import {
2125
TAB_DISPLAY_NAMES,
2226
TAB_NAME,
2327
} from "../../../../../typings/tab";
24-
import {QUERY_PROGRESS_DONE} from "../../../../../typings/worker";
2528
import {isDisabled} from "../../../../../utils/states";
2629
import CustomTabPanel from "../CustomTabPanel";
2730
import PanelTitleButton from "../PanelTitleButton";
@@ -35,6 +38,24 @@ enum QUERY_OPTION {
3538
IS_REGEX = "isRegex"
3639
}
3740

41+
/**
42+
* Determines if the query is case-sensitive based on the provided query options.
43+
*
44+
* @param queryOptions
45+
* @return True if the query is case-sensitive.
46+
*/
47+
const getIsCaseSensitive =
48+
(queryOptions: QUERY_OPTION[]) => queryOptions.includes(QUERY_OPTION.IS_CASE_SENSITIVE);
49+
50+
/**
51+
* Determines if the query is a regular expression based on the provided query options.
52+
*
53+
* @param queryOptions
54+
* @return True if the query is a regular expression.
55+
*/
56+
const getIsRegex =
57+
(queryOptions: QUERY_OPTION[]) => queryOptions.includes(QUERY_OPTION.IS_REGEX);
58+
3859
/**
3960
* Displays a panel for submitting queries and viewing query results.
4061
*
@@ -44,17 +65,31 @@ const SearchTabPanel = () => {
4465
const {queryProgress, queryResults, startQuery, uiState} = useContext(StateContext);
4566
const [isAllExpanded, setIsAllExpanded] = useState<boolean>(true);
4667
const [queryOptions, setQueryOptions] = useState<QUERY_OPTION[]>([]);
68+
const [queryString, setQueryString] = useState<string>("");
69+
70+
const handleQuerySubmit = (newArgs: Partial<QueryArgs>) => {
71+
startQuery({
72+
isCaseSensitive: getIsCaseSensitive(queryOptions),
73+
isRegex: getIsRegex(queryOptions),
74+
queryString: queryString,
75+
...newArgs,
76+
});
77+
};
4778

4879
const handleQueryInputChange = (ev: React.ChangeEvent<HTMLTextAreaElement>) => {
49-
const isCaseSensitive = queryOptions.includes(QUERY_OPTION.IS_CASE_SENSITIVE);
50-
const isRegex = queryOptions.includes(QUERY_OPTION.IS_REGEX);
51-
startQuery(ev.target.value, isRegex, isCaseSensitive);
80+
setQueryString(ev.target.value);
81+
handleQuerySubmit({queryString: ev.target.value});
5282
};
83+
5384
const handleQueryOptionsChange = (
5485
_: React.MouseEvent<HTMLElement>,
5586
newOptions: QUERY_OPTION[]
5687
) => {
5788
setQueryOptions(newOptions);
89+
handleQuerySubmit({
90+
isCaseSensitive: getIsCaseSensitive(newOptions),
91+
isRegex: getIsRegex(newOptions),
92+
});
5893
};
5994

6095
return (
@@ -109,7 +144,7 @@ const SearchTabPanel = () => {
109144
determinate={true}
110145
thickness={4}
111146
value={queryProgress * 100}
112-
color={QUERY_PROGRESS_DONE === queryProgress ?
147+
color={QUERY_PROGRESS_VALUE_MAX === queryProgress ?
113148
"success" :
114149
"primary"}/>
115150
</div>

src/contexts/StateContextProvider.tsx

+10-15
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ import {
2424
DEFAULT_AUTO_DISMISS_TIMEOUT_MILLIS,
2525
LONG_AUTO_DISMISS_TIMEOUT_MILLIS,
2626
} from "../typings/notifications";
27+
import {
28+
QUERY_PROGRESS_VALUE_MIN,
29+
QueryArgs,
30+
QueryResults,
31+
} from "../typings/query";
2732
import {UI_STATE} from "../typings/states";
2833
import {SEARCH_PARAM_NAMES} from "../typings/url";
2934
import {
@@ -33,8 +38,6 @@ import {
3338
EVENT_POSITION_ON_PAGE,
3439
FileSrcType,
3540
MainWorkerRespMessage,
36-
QUERY_PROGRESS_INIT,
37-
QueryResults,
3841
WORKER_REQ_CODE,
3942
WORKER_RESP_CODE,
4043
WorkerReq,
@@ -81,7 +84,7 @@ interface StateContextType {
8184
loadFile: (fileSrc: FileSrcType, cursor: CursorType) => void,
8285
loadPageByAction: (navAction: NavigationAction) => void,
8386
setIsSettingsModalOpen: (isOpen: boolean) => void,
84-
startQuery: (queryString: string, isRegex: boolean, isCaseSensitive: boolean) => void,
87+
startQuery: (queryArgs: QueryArgs) => void,
8588
}
8689
const StateContext = createContext<StateContextType>({} as StateContextType);
8790

@@ -98,7 +101,7 @@ const STATE_DEFAULT: Readonly<StateContextType> = Object.freeze({
98101
numPages: 0,
99102
onDiskFileSizeInBytes: 0,
100103
pageNum: 0,
101-
queryProgress: QUERY_PROGRESS_INIT,
104+
queryProgress: QUERY_PROGRESS_VALUE_MIN,
102105
queryResults: new Map(),
103106
uiState: UI_STATE.UNOPENED,
104107

@@ -339,7 +342,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
339342
}
340343
case WORKER_RESP_CODE.QUERY_RESULT:
341344
setQueryProgress(args.progress);
342-
if (QUERY_PROGRESS_INIT === args.progress) {
345+
if (QUERY_PROGRESS_VALUE_MIN === args.progress) {
343346
setQueryResults(STATE_DEFAULT.queryResults);
344347
} else {
345348
setQueryResults((v) => {
@@ -361,22 +364,14 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
361364
}
362365
}, [postPopUp]);
363366

364-
const startQuery = useCallback((
365-
queryString: string,
366-
isRegex: boolean,
367-
isCaseSensitive: boolean
368-
) => {
367+
const startQuery = useCallback((queryArgs: QueryArgs) => {
369368
setQueryResults(STATE_DEFAULT.queryResults);
370369
if (null === mainWorkerRef.current) {
371370
console.error("Unexpected null mainWorkerRef.current");
372371

373372
return;
374373
}
375-
workerPostReq(mainWorkerRef.current, WORKER_REQ_CODE.START_QUERY, {
376-
queryString: queryString,
377-
isRegex: isRegex,
378-
isCaseSensitive: isCaseSensitive,
379-
});
374+
workerPostReq(mainWorkerRef.current, WORKER_REQ_CODE.START_QUERY, queryArgs);
380375
}, []);
381376

382377
const exportLogs = useCallback(() => {

src/services/LogFileManager/index.ts

+19-7
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@ import {
66
} from "../../typings/decoders";
77
import {MAX_V8_STRING_LENGTH} from "../../typings/js";
88
import {LogLevelFilter} from "../../typings/logs";
9+
import {
10+
QueryArgs,
11+
QueryResults,
12+
} from "../../typings/query";
913
import {
1014
BeginLineNumToLogEventNumMap,
1115
CURSOR_CODE,
1216
CursorData,
1317
CursorType,
1418
EMPTY_PAGE_RESP,
1519
FileSrcType,
16-
QueryResults,
1720
WORKER_RESP_CODE,
1821
WorkerResp,
1922
} from "../../typings/worker";
@@ -286,11 +289,13 @@ class LogFileManager {
286289
* Creates a RegExp object based on the given query string and options, and starts querying the
287290
* first log chunk.
288291
*
289-
* @param queryString
290-
* @param isRegex
291-
* @param isCaseSensitive
292+
* @param queryArgs
293+
* @param queryArgs.queryString
294+
* @param queryArgs.isRegex
295+
* @param queryArgs.isCaseSensitive
296+
* @throws {SyntaxError} if the query regex string is invalid.
292297
*/
293-
startQuery (queryString: string, isRegex: boolean, isCaseSensitive: boolean): void {
298+
startQuery ({queryString, isRegex, isCaseSensitive}: QueryArgs): void {
294299
this.#queryId++;
295300
this.#queryCount = 0;
296301

@@ -310,9 +315,16 @@ class LogFileManager {
310315
const regexFlags = isCaseSensitive ?
311316
"" :
312317
"i";
313-
const queryRegex = new RegExp(regexPattern, regexFlags);
314318

315-
this.#queryChunkAndScheduleNext(this.#queryId, 0, queryRegex);
319+
try {
320+
const queryRegex = new RegExp(regexPattern, regexFlags);
321+
this.#queryChunkAndScheduleNext(this.#queryId, 0, queryRegex);
322+
} catch (e) {
323+
if (e instanceof SyntaxError) {
324+
console.error("Invalid regular expression:", e);
325+
}
326+
throw e;
327+
}
316328
}
317329

318330
/**

src/services/MainWorker.ts

+2-13
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import dayjsTimezone from "dayjs/plugin/timezone";
44
import dayjsUtc from "dayjs/plugin/utc";
55

66
import {LOG_LEVEL} from "../typings/logs";
7+
import {QueryResults} from "../typings/query";
78
import {
89
MainWorkerReqMessage,
9-
QueryResults,
1010
WORKER_REQ_CODE,
1111
WORKER_RESP_CODE,
1212
WorkerResp,
@@ -124,18 +124,7 @@ onmessage = async (ev: MessageEvent<MainWorkerReqMessage>) => {
124124
if (null === LOG_FILE_MANAGER) {
125125
throw new Error("Log file manager hasn't been initialized");
126126
}
127-
if (
128-
"string" !== typeof args.queryString ||
129-
"boolean" !== typeof args.isRegex ||
130-
"boolean" !== typeof args.isCaseSensitive
131-
) {
132-
throw new Error("Invalid arguments for QUERY_LOG");
133-
}
134-
LOG_FILE_MANAGER.startQuery(
135-
args.queryString,
136-
args.isRegex,
137-
args.isCaseSensitive
138-
);
127+
LOG_FILE_MANAGER.startQuery(args);
139128
break;
140129
default:
141130
console.error(`Unexpected ev.data: ${JSON.stringify(ev.data)}`);

src/typings/query.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
interface QueryArgs {
2+
queryString: string;
3+
isCaseSensitive: boolean;
4+
isRegex: boolean;
5+
}
6+
7+
type TextRange = [number, number];
8+
9+
interface QueryResultsType {
10+
logEventNum: number;
11+
message: string;
12+
matchRange: TextRange;
13+
}
14+
15+
type QueryResults = Map<number, QueryResultsType[]>;
16+
17+
const QUERY_PROGRESS_VALUE_MIN = 0;
18+
const QUERY_PROGRESS_VALUE_MAX = 1;
19+
20+
21+
export type {
22+
QueryArgs,
23+
QueryResults,
24+
QueryResultsType,
25+
};
26+
export {
27+
QUERY_PROGRESS_VALUE_MAX,
28+
QUERY_PROGRESS_VALUE_MIN,
29+
};

src/typings/worker.ts

+1-17
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
LOG_LEVEL,
88
LogLevelFilter,
99
} from "./logs";
10+
import {QueryResults} from "./query";
1011

1112

1213
/**
@@ -106,19 +107,6 @@ type WorkerReqMap = {
106107
},
107108
};
108109

109-
type TextRange = [number, number];
110-
111-
interface QueryResultsType {
112-
logEventNum: number;
113-
message: string;
114-
matchRange: TextRange;
115-
}
116-
117-
type QueryResults = Map<number, QueryResultsType[]>;
118-
119-
const QUERY_PROGRESS_INIT = 0;
120-
const QUERY_PROGRESS_DONE = 1;
121-
122110
type WorkerRespMap = {
123111
[WORKER_RESP_CODE.CHUNK_DATA]: {
124112
logs: string
@@ -180,8 +168,6 @@ export {
180168
CURSOR_CODE,
181169
EMPTY_PAGE_RESP,
182170
EVENT_POSITION_ON_PAGE,
183-
QUERY_PROGRESS_DONE,
184-
QUERY_PROGRESS_INIT,
185171
WORKER_REQ_CODE,
186172
WORKER_RESP_CODE,
187173
};
@@ -192,8 +178,6 @@ export type {
192178
FileSrcType,
193179
MainWorkerReqMessage,
194180
MainWorkerRespMessage,
195-
QueryResults,
196-
QueryResultsType,
197181
WorkerReq,
198182
WorkerResp,
199183
};

0 commit comments

Comments
 (0)