Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
be6e9e0
Migrate isPrettified
zzxthehappiest May 21, 2025
1f0aeda
Remove UrlContextProvider
zzxthehappiest May 22, 2025
81585cb
Remove hashchange event when updateHashUrlParams
zzxthehappiest May 24, 2025
0ae420c
Add logEventNum to viewStore and remove from Url
zzxthehappiest May 22, 2025
cd36fb8
Add fileSrc to logFileStore and remove from UrlContext
zzxthehappiest May 22, 2025
0dfe7b8
Fix lint
zzxthehappiest May 25, 2025
5852960
Merge branch 'main' into zzx/feat-269
zzxthehappiest May 25, 2025
c808cf2
Fix coderabit comments
zzxthehappiest May 25, 2025
00cadb9
Fix coderabbit review
zzxthehappiest May 25, 2025
6a873d4
Add junhaoliao@b972113
zzxthehappiest May 25, 2025
6620583
Fix lint
zzxthehappiest May 26, 2025
66abf15
Fix coderabbit comments
zzxthehappiest May 26, 2025
cf10ebe
Fix comments
zzxthehappiest May 27, 2025
0910692
Fix comments
zzxthehappiest May 27, 2025
6ebcf09
Merge branch 'main' into zzx/feat-269
zzxthehappiest May 28, 2025
f4cc127
refactor: Rename uiStoreState type to UiStoreState to follow PascalCa…
Henry8192 May 26, 2025
9879d0a
docs: Add deployment instructions (resolves #217). (#236)
junhaoliao May 27, 2025
7159bf2
Fix comments
zzxthehappiest May 28, 2025
e9b2cbb
Merge branch 'zzx/feat-269' of github.com:zzxthehappiest/yscope-log-v…
zzxthehappiest May 28, 2025
4139d0e
Merge branch 'main' into zzx/feat-269
zzxthehappiest May 29, 2025
23aa8b3
Merge queryStore to zustandard (not test yet)
zzxthehappiest May 29, 2025
d204c9b
Fix lint
zzxthehappiest May 29, 2025
a464dc9
Finish the rest
zzxthehappiest May 30, 2025
0dabdfc
Fix #306
zzxthehappiest Jun 1, 2025
de74c4f
Merge branch 'main' into zzx/feat-269
zzxthehappiest Jun 1, 2025
3add41d
Fix coderabbit comments
zzxthehappiest Jun 1, 2025
7166d2b
Fix comments except: Remove null in URL params
zzxthehappiest Jun 4, 2025
def27ea
Final fix
zzxthehappiest Jun 5, 2025
3369449
Minor fix
zzxthehappiest Jun 5, 2025
3c9bd0d
Merge branch 'main' into zzx/feat-269
zzxthehappiest Jun 5, 2025
9669cd5
Fix latest comments
zzxthehappiest Jun 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import AppController from "./components/AppController";
import Layout from "./components/Layout";
import UrlContextProvider from "./contexts/UrlContextProvider";


/**
Expand All @@ -10,11 +9,9 @@ import UrlContextProvider from "./contexts/UrlContextProvider";
*/
const App = () => {
return (
<UrlContextProvider>
<AppController>
<Layout/>
</AppController>
</UrlContextProvider>
<AppController>
<Layout/>
</AppController>
);
};

Expand Down
174 changes: 84 additions & 90 deletions src/components/AppController.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
import React, {
useContext,
useEffect,
useRef,
} from "react";
/* eslint max-statements: ["error", 30] */
import React, {useEffect} from "react";

import {
updateWindowUrlHashParams,
URL_HASH_PARAMS_DEFAULT,
URL_SEARCH_PARAMS_DEFAULT,
UrlContext,
} from "../contexts/UrlContextProvider";
import useContextStore from "../stores/contextStore";
import useLogFileManagerStore from "../stores/logFileManagerProxyStore";
import useLogFileStore from "../stores/logFileStore";
import {handleErrorWithNotification} from "../stores/notificationStore";
Expand All @@ -27,6 +17,13 @@ import {
isWithinBounds,
} from "../utils/data";
import {clamp} from "../utils/math";
import {
getWindowUrlHashParams,
getWindowUrlSearchParams,
updateWindowUrlHashParams,
URL_HASH_PARAMS_DEFAULT,
URL_SEARCH_PARAMS_DEFAULT,
} from "../utils/url.ts";


/**
Expand All @@ -40,9 +37,9 @@ import {clamp} from "../utils/math";
const updateUrlIfEventOnPage = (
logEventNum: number,
logEventNumsOnPage: number[]
): boolean => {
): {isUpdated: boolean; nearestLogEventNum: number} => {
if (false === isWithinBounds(logEventNumsOnPage, logEventNum)) {
return false;
return {isUpdated: false, nearestLogEventNum: URL_HASH_PARAMS_DEFAULT.logEventNum};
}

const nearestIdx = findNearestLessThanOrEqualElement(
Expand All @@ -64,7 +61,40 @@ const updateUrlIfEventOnPage = (
logEventNum: nearestLogEventNum,
});

return true;
return {isUpdated: true, nearestLogEventNum: nearestLogEventNum};
};

/**
* Handle the hash parameters change.
*/
const handleHashChange = () => {
const {setLogEventNum} = useViewStore.getState();
const {setQueryIsCaseSensitive} = useQueryStore.getState();
const {setQueryIsRegex} = useQueryStore.getState();
const {setQueryString} = useQueryStore.getState();
const {updateIsPrettified} = useViewStore.getState();

const hashParams = getWindowUrlHashParams();

if (null !== hashParams.logEventNum) {
setLogEventNum(hashParams.logEventNum);
}

if (null !== hashParams.isPrettified) {
updateIsPrettified(hashParams.isPrettified);
}

if (null !== hashParams.queryIsCaseSensitive) {
setQueryIsCaseSensitive(hashParams.queryIsCaseSensitive);
}

if (null !== hashParams.queryIsRegex) {
setQueryIsRegex(hashParams.queryIsRegex);
}

if (null !== hashParams.queryString) {
setQueryString(hashParams.queryString);
}
};

interface AppControllerProps {
Expand All @@ -79,47 +109,46 @@ interface AppControllerProps {
* @return
*/
const AppController = ({children}: AppControllerProps) => {
const {
filePath, isPrettified, logEventNum, queryString, queryIsRegex, queryIsCaseSensitive,
} = useContext(UrlContext);

// States
const setLogEventNum = useContextStore((state) => state.setLogEventNum);
const logFileManagerProxy = useLogFileManagerStore((state) => state.logFileManagerProxy);
const loadFile = useLogFileStore((state) => state.loadFile);
const numEvents = useLogFileStore((state) => state.numEvents);
const beginLineNumToLogEventNum = useViewStore((state) => state.beginLineNumToLogEventNum);
const setIsPrettified = useViewStore((state) => state.updateIsPrettified);
const numEvents = useLogFileStore((state) => state.numEvents);
const queryString = useQueryStore((state) => state.queryString);
const updatePageData = useViewStore((state) => state.updatePageData);
const uiState = useUiStore((state) => state.uiState);
const setUiState = useUiStore((state) => state.setUiState);

// Refs
const isPrettifiedRef = useRef<boolean>(isPrettified ?? false);
const logEventNumRef = useRef(logEventNum);

// Synchronize `logEventNumRef` with `logEventNum`.
useEffect(() => {
if (null !== logEventNum) {
logEventNumRef.current = logEventNum;
setLogEventNum(logEventNum);
const {loadFile} = useLogFileStore.getState();
const {logEventNum} = useViewStore.getState();

handleHashChange();
window.addEventListener("hashchange", handleHashChange);

// Handle initial page load and maintain full URL state
const searchParams = getWindowUrlSearchParams();
if (URL_SEARCH_PARAMS_DEFAULT.filePath !== searchParams.filePath) {
let cursor: CursorType = {code: CURSOR_CODE.LAST_EVENT, args: null};
if (URL_HASH_PARAMS_DEFAULT.logEventNum !== logEventNum) {
cursor = {
code: CURSOR_CODE.EVENT_NUM,
args: {eventNum: logEventNum},
};
}
loadFile(searchParams.filePath, cursor);
}
}, [
logEventNum,
setLogEventNum,
]);

// Synchronize `isPrettifiedRef` with `isPrettified`.
useEffect(() => {
isPrettifiedRef.current = isPrettified ?? false;
setIsPrettified(isPrettifiedRef.current);
}, [
isPrettified,
setIsPrettified,
]);
return () => {
window.removeEventListener("hashchange", handleHashChange);
};
}, []);

// On `logEventNum` update, clamp it then switch page if necessary or simply update the URL.
useEffect(() => {
const {isPrettified} = useViewStore.getState();
const {logEventNum} = useViewStore.getState();
const {logFileManagerProxy} = useLogFileManagerStore.getState();
const {setLogEventNum} = useViewStore.getState();
const {setUiState} = useUiStore.getState();

if (0 === numEvents || URL_HASH_PARAMS_DEFAULT.logEventNum === logEventNum) {
return;
}
Expand All @@ -128,8 +157,15 @@ const AppController = ({children}: AppControllerProps) => {
const logEventNumsOnPage: number [] =
Array.from(beginLineNumToLogEventNum.values());

if (updateUrlIfEventOnPage(clampedLogEventNum, logEventNumsOnPage)) {
const {
isUpdated,
nearestLogEventNum,
} = updateUrlIfEventOnPage(clampedLogEventNum, logEventNumsOnPage);

if (isUpdated) {
// No need to request a new page since the log event is on the current page.
setLogEventNum(nearestLogEventNum);

return;
}

Expand All @@ -140,65 +176,23 @@ const AppController = ({children}: AppControllerProps) => {
code: CURSOR_CODE.EVENT_NUM,
args: {eventNum: clampedLogEventNum},
};
const pageData = await logFileManagerProxy.loadPage(cursor, isPrettifiedRef.current);
const pageData = await logFileManagerProxy.loadPage(cursor, isPrettified);
updatePageData(pageData);
})().catch(handleErrorWithNotification);
}, [
beginLineNumToLogEventNum,
logEventNum,
logFileManagerProxy,
numEvents,
setUiState,
updatePageData,
]);

// On `filePath` update, load file.
useEffect(() => {
if (URL_SEARCH_PARAMS_DEFAULT.filePath === filePath) {
return;
}

let cursor: CursorType = {code: CURSOR_CODE.LAST_EVENT, args: null};
if (URL_HASH_PARAMS_DEFAULT.logEventNum !== logEventNumRef.current) {
cursor = {
code: CURSOR_CODE.EVENT_NUM,
args: {eventNum: logEventNumRef.current},
};
}
loadFile(filePath, cursor);
}, [
filePath,
loadFile,
]);

// Synchronize `queryIsCaseSensitive` with the Zustand QueryStore.
useEffect(() => {
if (null !== queryIsCaseSensitive) {
const {setQueryIsCaseSensitive} = useQueryStore.getState();
setQueryIsCaseSensitive(queryIsCaseSensitive);
}
}, [queryIsCaseSensitive]);

// Synchronize `queryIsRegex` with the Zustand QueryStore.
useEffect(() => {
if (null !== queryIsRegex) {
const {setQueryIsRegex} = useQueryStore.getState();
setQueryIsRegex(queryIsRegex);
}
}, [queryIsRegex]);

useEffect(() => {
if (null !== queryString) {
const {setQueryString} = useQueryStore.getState();
setQueryString(queryString);
}
if (UI_STATE.READY === uiState) {
const {startQuery} = useQueryStore.getState();
startQuery();
}
}, [
uiState,
queryString,
uiState,
]);

return children;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import useUiStore from "../../../../../stores/uiStore";
import {QUERY_PROGRESS_VALUE_MAX} from "../../../../../typings/query";
import {UI_ELEMENT} from "../../../../../typings/states";
import {isDisabled} from "../../../../../utils/states";
import {updateWindowUrlHashParams} from "../../../../../utils/url";
import ToggleIconButton from "./ToggleIconButton";

import "./QueryInputBox.css";
Expand All @@ -33,17 +34,23 @@ const QueryInputBox = () => {
const uiState = useUiStore((state) => state.uiState);

const handleQueryInputChange = (ev: React.ChangeEvent<HTMLTextAreaElement>) => {
setQueryString(ev.target.value);
const newQueryString = ev.target.value;
updateWindowUrlHashParams({queryString: newQueryString});
setQueryString(newQueryString);
startQuery();
};

const handleCaseSensitivityButtonClick = () => {
setQueryIsCaseSensitive(!isCaseSensitive);
const newQueryIsSensitive = !isCaseSensitive;
updateWindowUrlHashParams({queryIsCaseSensitive: newQueryIsSensitive});
setQueryIsCaseSensitive(newQueryIsSensitive);
startQuery();
};

const handleRegexButtonClick = () => {
setQueryIsRegex(!isRegex);
const newQueryIsRegex = !isRegex;
updateWindowUrlHashParams({queryIsRegex: newQueryIsRegex});
setQueryIsRegex(newQueryIsRegex);
startQuery();
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import {useCallback} from "react";

import {
ListItemButton,
Typography,
} from "@mui/joy";

import {updateWindowUrlHashParams} from "../../../../../contexts/UrlContextProvider";
import useViewStore from "../../../../../stores/viewStore.ts";
import {updateWindowUrlHashParams} from "../../../../../utils/url.ts";

import "./Result.css";

Expand Down Expand Up @@ -36,9 +39,14 @@ const Result = ({logEventNum, message, matchRange}: ResultProps) => {
message.slice(...matchRange),
message.slice(matchRange[1]),
];
const handleResultButtonClick = () => {
const {setLogEventNum} = useViewStore.getState();
const handleResultButtonClick = useCallback(() => {
updateWindowUrlHashParams({logEventNum});
};
setLogEventNum(logEventNum);
}, [
logEventNum,
setLogEventNum,
]);

return (
<ListItemButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import ShareIcon from "@mui/icons-material/Share";
import UnfoldLessIcon from "@mui/icons-material/UnfoldLess";
import UnfoldMoreIcon from "@mui/icons-material/UnfoldMore";

import {copyPermalinkToClipboard} from "../../../../../contexts/UrlContextProvider";
import useQueryStore from "../../../../../stores/queryStore";
import {
TAB_DISPLAY_NAMES,
TAB_NAME,
} from "../../../../../typings/tab";
import {copyPermalinkToClipboard} from "../../../../../utils/url.ts";
import CustomTabPanel from "../CustomTabPanel";
import PanelTitleButton from "../PanelTitleButton";
import QueryInputBox from "./QueryInputBox";
Expand All @@ -44,6 +44,14 @@ const SearchTabPanel = () => {
}, []);

const handleShareButtonClick = useCallback(() => {
const {setQueryIsCaseSensitive} = useQueryStore.getState();
const {setQueryIsRegex} = useQueryStore.getState();
const {setQueryString} = useQueryStore.getState();

setQueryIsCaseSensitive(queryIsCaseSensitive);
setQueryIsRegex(queryIsRegex);
setQueryString(queryString);

copyPermalinkToClipboard({}, {
logEventNum: null,
queryString: "" === queryString ?
Expand Down
Loading