Skip to content

Commit

Permalink
Add pagination boundaries to log events.
Browse files Browse the repository at this point in the history
  • Loading branch information
junhaoliao committed Sep 3, 2024
1 parent a03d6ea commit dae8488
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 37 deletions.
57 changes: 41 additions & 16 deletions new-log-viewer/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ import {
setConfig,
} from "../utils/config";
import {openFile} from "../utils/file";
import {
getFirstItemNumInNextChunk,
getLastItemNumInPrevChunk,
} from "../utils/math";
import DropFileContainer from "./DropFileContainer";
import Editor from "./Editor";
import {goToPositionAndCenter} from "./Editor/MonacoInstance/utils";
Expand Down Expand Up @@ -183,6 +179,8 @@ const handleLogEventNumInputChange = (ev: React.ChangeEvent<HTMLInputElement>) =
const Layout = () => {
const {
fileName,
firstLogEventNumPerPage,
lastLogEventNumPerPage,
numEvents,
numFilteredEvents,
pageNum,
Expand All @@ -194,8 +192,10 @@ const Layout = () => {

const [selectedLogLevels, setSelectedLogLevels] =
useState<number[]>(LOG_LEVEL_NAMES_LIST as number[]);
const firstLogEventNumPerPageRef = useRef<number[]>(firstLogEventNumPerPage);
const lastLogEventNumPerPageRef = useRef<number[]>(lastLogEventNumPerPage);
const logEventNumRef = useRef<Nullable<number>>(logEventNum);
const numFilteredEventsRef = useRef<Nullable<number>>(numFilteredEvents);
const numEventsRef = useRef<Nullable<number>>(numEvents);

const handleCopyLinkButtonClick = () => {
copyPermalinkToClipboard({}, {logEventNum: numEvents});
Expand Down Expand Up @@ -226,28 +226,42 @@ const Layout = () => {
editor: monaco.editor.IStandaloneCodeEditor,
actionName: ACTION_NAME
) => {
const pageSize = getConfig(CONFIG_KEY.PAGE_SIZE);
const [firstFilteredLogEventNum] = firstLogEventNumPerPageRef.current;
const lastFilteredLogEventNum = firstLogEventNumPerPageRef.current.at(-1);

switch (actionName) {
case ACTION_NAME.FIRST_PAGE:
updateWindowUrlHashParams({logEventNum: 1});
updateWindowUrlHashParams({logEventNum: firstFilteredLogEventNum || 1});
break;
case ACTION_NAME.PREV_PAGE:
if (null !== logEventNumRef.current) {
const lastLogEventNumOnPrevPage = lastLogEventNumPerPageRef.current.findLast(
(value: number) => (logEventNumRef.current as number > value)
) || firstFilteredLogEventNum;

updateWindowUrlHashParams({
logEventNum: getLastItemNumInPrevChunk(logEventNumRef.current, pageSize),
logEventNum: lastLogEventNumOnPrevPage || firstFilteredLogEventNum || 1,
});
}
break;
case ACTION_NAME.NEXT_PAGE:
if (null !== logEventNumRef.current) {
if ("undefined" === typeof lastFilteredLogEventNum) {
return;
}
const firstLogEventNumOnNextPage = firstLogEventNumPerPageRef.current.find(
(value: number) => (logEventNumRef.current as number < value)
);

updateWindowUrlHashParams({
logEventNum: getFirstItemNumInNextChunk(logEventNumRef.current, pageSize),
logEventNum: firstLogEventNumOnNextPage || logEventNumRef.current < lastFilteredLogEventNum ?

Check warning on line 257 in new-log-viewer/src/components/Layout.tsx

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

new-log-viewer/src/components/Layout.tsx#L257

[@stylistic/js/max-len] This line has a length of 117. Maximum allowed is 100.
lastFilteredLogEventNum :
numEventsRef.current,
});
}
break;
case ACTION_NAME.LAST_PAGE:
updateWindowUrlHashParams({logEventNum: numFilteredEventsRef.current});
updateWindowUrlHashParams({logEventNum: lastFilteredLogEventNum || numEventsRef.current});

Check warning on line 264 in new-log-viewer/src/components/Layout.tsx

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

new-log-viewer/src/components/Layout.tsx#L264

[@stylistic/js/max-len] This line has a length of 106. Maximum allowed is 100.
break;
case ACTION_NAME.PAGE_TOP:
goToPositionAndCenter(editor, {lineNumber: 1, column: 1});
Expand All @@ -260,19 +274,30 @@ const Layout = () => {
goToPositionAndCenter(editor, {lineNumber: lineCount, column: 1});
break;
}
default: break;
default:
break;
}
}, []);

// Synchronize `firstLogEventNumPerPageRef` with `firstLogEventNumPerPage`.
useEffect(() => {
firstLogEventNumPerPageRef.current = firstLogEventNumPerPage;
}, [firstLogEventNumPerPage]);

// Synchronize `lastLogEventNumPerPageRef` with `lastLogEventNumPerPage`.
useEffect(() => {
lastLogEventNumPerPageRef.current = lastLogEventNumPerPage;
}, [lastLogEventNumPerPage]);

// Synchronize `logEventNumRef` with `logEventNum`.
useEffect(() => {
logEventNumRef.current = logEventNum;
}, [logEventNum]);

// Synchronize `numFilteredEventsRef` with `numFilteredEvents`.
// Synchronize `numEventsRef` with `numEvents`.
useEffect(() => {
numFilteredEventsRef.current = numFilteredEvents;
}, [numFilteredEvents]);
numEventsRef.current = numEvents;
}, [numEvents]);

return (
<>
Expand All @@ -287,8 +312,8 @@ const Layout = () => {
logEventNum}
onChange={handleLogEventNumInputChange}/>
{" / "}
{numFilteredEvents}
{" | "}
{numEvents}
{` (NumFilteredEvents - ${numFilteredEvents}) | `}
PageNum -
{" "}
{pageNum}
Expand Down
38 changes: 30 additions & 8 deletions new-log-viewer/src/contexts/StateContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import {
interface StateContextType {
beginLineNumToLogEventNum: BeginLineNumToLogEventNumMap,
fileName: string,
firstLogEventNumPerPage: number[],
lastLogEventNumPerPage: number[],
logData: string,
logLevelFilter: LogLevelFilter,
numEvents: number,
Expand All @@ -59,6 +61,8 @@ const StateContext = createContext<StateContextType>({} as StateContextType);
const STATE_DEFAULT: Readonly<StateContextType> = Object.freeze({
beginLineNumToLogEventNum: new Map<number, number>(),
fileName: "",
firstLogEventNumPerPage: [],
lastLogEventNumPerPage: [],
logData: "Loading...",
logLevelFilter: null,
numEvents: 0,
Expand Down Expand Up @@ -140,6 +144,8 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
const {filePath, logEventNum} = useContext(UrlContext);

const [fileName, setFileName] = useState<string>(STATE_DEFAULT.fileName);
const [firstLogEventNumPerPage, setFirstLogEventNumPerPage] = useState<number[]>([]);
const [lastLogEventNumPerPage, setLastLogEventNumPerPage] = useState<number[]>([]);
const [logData, setLogData] = useState<string>(STATE_DEFAULT.logData);
const [numEvents, setNumEvents] = useState<number>(STATE_DEFAULT.numEvents);
const [numFilteredEvents, setNumFilteredEvents] =
Expand Down Expand Up @@ -171,11 +177,19 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
setLogData(args.logs);
beginLineNumToLogEventNumRef.current = args.beginLineNumToLogEventNum;
const lastLogEventNum = getLastLogEventNum(args.beginLineNumToLogEventNum);
updateLogEventNumInUrl(lastLogEventNum, logEventNumRef.current);
updateLogEventNumInUrl(
lastLogEventNum,
Array.from(args.beginLineNumToLogEventNum.values())
.includes(logEventNumRef.current as number) ?
logEventNumRef.current :
lastLogEventNum
);
break;
}
case WORKER_RESP_CODE.VIEW_INFO:
setNumFilteredEvents(args.numFilteredEvents);
setFirstLogEventNumPerPage(args.firstLogEventNumPerPage);
setLastLogEventNumPerPage(args.lastLogEventNumPerPage);
break;
default:
console.error(`Unexpected ev.data: ${JSON.stringify(ev.data)}`);
Expand Down Expand Up @@ -234,21 +248,26 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {

// On `logEventNum` update, clamp it then switch page if necessary or simply update the URL.
useEffect(() => {
if (null === mainWorkerRef.current || URL_HASH_PARAMS_DEFAULT.logEventNum === logEventNum) {
if (null === mainWorkerRef.current || URL_HASH_PARAMS_DEFAULT.logEventNum === logEventNum ||
0 === firstLogEventNumPerPage.length) {
return;
}

const newPageNum = clamp(
getChunkNum(logEventNum, getConfig(CONFIG_KEY.PAGE_SIZE)),
1,
numPagesRef.current
);
const newPageNum = 1 +
firstLogEventNumPerPage.findLastIndex((value: number) => value <= logEventNum);

if (0 === newPageNum) {
return;
}

// Request a page switch only if it's not the initial page load.
if (STATE_DEFAULT.pageNum !== pageNumRef.current) {
if (newPageNum === pageNumRef.current) {
// Don't need to switch pages so just update `logEventNum` in the URL.
updateLogEventNumInUrl(numFilteredEvents, logEventNumRef.current);
updateLogEventNumInUrl(
numEvents,
logEventNumRef.current
);
} else {
// NOTE: We don't need to call `updateLogEventNumInUrl()` since it's called when
// handling the `WORKER_RESP_CODE.PAGE_DATA` response (the response to
Expand All @@ -265,6 +284,7 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {

pageNumRef.current = newPageNum;
}, [
firstLogEventNumPerPage,
numFilteredEvents,
logEventNum,
]);

Check warning on line 290 in new-log-viewer/src/contexts/StateContextProvider.tsx

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

new-log-viewer/src/contexts/StateContextProvider.tsx#L286-L290

[react-hooks/exhaustive-deps] React Hook useEffect has a missing dependency: 'numEvents'. Either include it or remove the dependency array.
Expand Down Expand Up @@ -298,6 +318,8 @@ const StateContextProvider = ({children}: StateContextProviderProps) => {
value={{
beginLineNumToLogEventNum: beginLineNumToLogEventNumRef.current,
fileName: fileName,
firstLogEventNumPerPage: firstLogEventNumPerPage,
lastLogEventNumPerPage: lastLogEventNumPerPage,
logData: logData,
logLevelFilter: logLevelFilterRef.current,
numEvents: numEvents,
Expand Down
30 changes: 27 additions & 3 deletions new-log-viewer/src/services/LogFileManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,14 @@ class LogFileManager {

#decoder: Decoder;

#numEvents: number = 0;
readonly #numEvents: number = 0;

#numFilteredEvents: number = 0;

#firstLogEventNumPerPage: number[] = [];

#lastLogEventNumPerPage: number[] = [];

/**
* Private constructor for LogFileManager. This is not intended to be invoked publicly.
* Instead, use LogFileManager.create() to create a new instance of the class.
Expand All @@ -82,7 +86,7 @@ class LogFileManager {
}

this.#numEvents = decoder.getEstimatedNumEvents();
this.#numFilteredEvents = decoder.getNumFilteredEvents();
this.#computerPageBoundaries();
console.log(
`Found ${this.#numEvents} log events.`,
`${this.#numFilteredEvents} matches current filter.`
Expand All @@ -101,6 +105,14 @@ class LogFileManager {
return this.#numFilteredEvents;
}

get firstLogEventNumPerPage () {
return this.#firstLogEventNumPerPage;
}

get lastLogEventNumPerPage () {
return this.#lastLogEventNumPerPage;
}

/**
* Creates a new LogFileManager.
*
Expand Down Expand Up @@ -160,7 +172,7 @@ class LogFileManager {
*/
setDecoderOptions (options: DecoderOptions) {
this.#decoder.setDecoderOptions(options);
this.#numFilteredEvents = this.#decoder.getNumFilteredEvents();
this.#computerPageBoundaries();
}

/**
Expand Down Expand Up @@ -209,6 +221,18 @@ class LogFileManager {
};
}

#computerPageBoundaries () {
this.#firstLogEventNumPerPage.length = 0;
this.#lastLogEventNumPerPage.length = 0;
const filteredLogEvents = this.#decoder.getFilteredLogEvents();
this.#numFilteredEvents = filteredLogEvents.length;
for (let i = 0; i < this.#numFilteredEvents; i += this.#pageSize) {
this.#firstLogEventNumPerPage.push(1 + (filteredLogEvents[i] as number));
this.#lastLogEventNumPerPage.push(1 +
(filteredLogEvents[i + this.#pageSize - 1] as number));
}
}

/**
* Gets the range of log event numbers for the page containing the given cursor.
*
Expand Down
4 changes: 4 additions & 0 deletions new-log-viewer/src/services/MainWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ onmessage = async (ev: MessageEvent<MainWorkerReqMessage>) => {
});
postResp(WORKER_RESP_CODE.VIEW_INFO, {
numFilteredEvents: LOG_FILE_MANAGER.numFilteredEvents,
firstLogEventNumPerPage: LOG_FILE_MANAGER.firstLogEventNumPerPage,
lastLogEventNumPerPage: LOG_FILE_MANAGER.lastLogEventNumPerPage,
});
postResp(
WORKER_RESP_CODE.PAGE_DATA,
Expand All @@ -69,6 +71,8 @@ onmessage = async (ev: MessageEvent<MainWorkerReqMessage>) => {
LOG_FILE_MANAGER.setDecoderOptions(args.decoderOptions);
postResp(WORKER_RESP_CODE.VIEW_INFO, {
numFilteredEvents: LOG_FILE_MANAGER.numFilteredEvents,
firstLogEventNumPerPage: LOG_FILE_MANAGER.firstLogEventNumPerPage,
lastLogEventNumPerPage: LOG_FILE_MANAGER.lastLogEventNumPerPage,
});
}
postResp(
Expand Down
4 changes: 2 additions & 2 deletions new-log-viewer/src/services/decoders/ClpIrDecoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ class ClpIrDecoder implements Decoder {
return this.#streamReader.getNumEventsBuffered();
}

getNumFilteredEvents (): number {
getFilteredLogEvents (): number[] {
// eslint-disable-next-line no-warning-comments
// TODO: fix this after log level filtering is implemented in clp-ffi-js
return this.#streamReader.getNumEventsBuffered();
return Array.from({length: this.#streamReader.getNumEventsBuffered()}, (_, index) => index);
}

buildIdx (beginIdx: number, endIdx: number): Nullable<LogEventCount> {
Expand Down
4 changes: 2 additions & 2 deletions new-log-viewer/src/services/decoders/JsonlDecoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ class JsonlDecoder implements Decoder {
return this.#logEvents.length;
}

getNumFilteredEvents () : number {
return this.#filteredLogIndices.length;
getFilteredLogEvents () : number[] {
return this.#filteredLogIndices;
}

buildIdx (beginIdx: number, endIdx: number): Nullable<LogEventCount> {
Expand Down
6 changes: 3 additions & 3 deletions new-log-viewer/src/typings/decoders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ interface Decoder {
getEstimatedNumEvents(): number;

/**
* Retrieves a number of filtered log events usually based on log level.
* Retrieves the filtered log events indices, which is usually based on log level.
*
* @return The number of filtered events.
* @return Indices of the filtered events.
*/
getNumFilteredEvents(): number;
getFilteredLogEvents(): number[];

/**
* When applicable, deserializes log events in the range `[beginIdx, endIdx)`.
Expand Down
6 changes: 4 additions & 2 deletions new-log-viewer/src/typings/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ type WorkerReqMap = {
fileSrc: FileSrcType,
pageSize: number,
cursor: CursorType,
decoderOptions: DecoderOptions
decoderOptions: DecoderOptions,
},
[WORKER_REQ_CODE.LOAD_PAGE]: {
cursor: CursorType,
decoderOptions?: DecoderOptions
decoderOptions?: DecoderOptions,
},
};

Expand All @@ -77,7 +77,9 @@ type WorkerRespMap = {
cursorLineNum: number,
},
[WORKER_RESP_CODE.VIEW_INFO]: {
firstLogEventNumPerPage: number[],
numFilteredEvents: number,
lastLogEventNumPerPage: number[],
}
};

Expand Down
2 changes: 1 addition & 1 deletion new-log-viewer/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
/* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
/* Specify a set of bundled library declaration files that describe the target runtime environment. */
"lib": [
"ES2022",
"DOM",
"DOM.Iterable",
"ES2023",
"WebWorker",
],
"jsx": "react-jsx",
Expand Down

0 comments on commit dae8488

Please sign in to comment.