Skip to content
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
5477d0a
snapshot
Henry8192 Dec 1, 2024
4a8aeb7
draft without implementing getLogEventIdxByTimestamp
Henry8192 Dec 5, 2024
7f5cc7f
patch
Henry8192 Dec 6, 2024
54ef03c
implementing JSONL getLogEventIdxByTimestamp, fix timestamp type to b…
Henry8192 Dec 9, 2024
6c2b45a
fix JSONL getEventIdxByTimestamp + timestamp hash param not cleared
Henry8192 Dec 11, 2024
255f3e3
revert timestamp type back to Number; Only keeping bigint for DecodeR…
Henry8192 Dec 12, 2024
3972319
address changes from code review
Henry8192 Dec 19, 2024
5ecdaab
Merge branch 'main' into search-timestamp
Henry8192 Feb 10, 2025
f1f93f7
rename getLogEventIdxByTimestamp to getLogEventIdxByTimestamp
Henry8192 Feb 10, 2025
683350a
update clp-ffi-js dependency
Henry8192 Feb 11, 2025
7b72d93
Merge branch 'main' into search-timestamp
Henry8192 Feb 13, 2025
0cc3649
Add docstring for findNearestLogEventByTimestamp; Change function beh…
Henry8192 Feb 13, 2025
a81d570
Fix JSONL findNearestLogEventByTimestamp not always returning the cor…
Henry8192 Feb 16, 2025
e8e58f5
fix corner case
Henry8192 Feb 20, 2025
206b01f
minor format fixes
Henry8192 Feb 24, 2025
07ef527
Merge branch 'main' into search-timestamp
junhaoliao Feb 27, 2025
6c910d4
Merge branch 'main' into search-timestamp
junhaoliao Feb 28, 2025
bc16de2
Merge remote-tracking branch 'yscope/main' into search-timestamp
Henry8192 Mar 24, 2025
e04dadb
Merge branch 'main' into search-timestamp
Henry8192 Mar 24, 2025
3c051e8
temporarily lift state context provider's max lines; eventually we wi…
Henry8192 Mar 24, 2025
32de344
Merge branch 'main' into search-timestamp
Henry8192 May 21, 2025
127d56b
Merge branch 'main' into search-timestamp
Henry8192 May 21, 2025
e5725c2
finish merging main branch
Henry8192 May 21, 2025
56c5a1f
remove StateContextProvider.tsx
Henry8192 May 26, 2025
3fa1b87
Merge branch 'main' into search-timestamp
Henry8192 May 27, 2025
2074a5d
Update error handling in AppController and reorganize CURSOR_CODE enu…
Henry8192 May 28, 2025
ca539cf
Update src/components/AppController.tsx
Henry8192 May 28, 2025
6e1c1dd
Merge branch 'main' into search-timestamp
Henry8192 May 28, 2025
2ba9e82
fix lint
Henry8192 May 28, 2025
d2c2a62
revert back to switch case
Henry8192 Jun 2, 2025
dc21b01
Merge branch 'main' into search-timestamp
Henry8192 Jun 2, 2025
012a66c
address review
Henry8192 Jun 3, 2025
67ff878
use `numEvents` in a non-reactive way
Henry8192 Jun 9, 2025
7b53dab
Merge branch 'main' into search-timestamp
Henry8192 Jun 9, 2025
251f602
finish merging main
Henry8192 Jun 10, 2025
535172f
Merge branch 'main' into search-timestamp
Henry8192 Jul 7, 2025
470db18
finish merging main; refactor update url hash parameters logic
Henry8192 Jul 8, 2025
7114402
rename action names & minor fix
Henry8192 Jul 8, 2025
61241bc
refactor getting cursor logic to getCursorFromHashParams
Henry8192 Jul 8, 2025
85d563c
Merge remote-tracking branch 'upstream/main' into HEAD
hoophalab Jul 14, 2025
4782586
revert buttons
hoophalab Jul 14, 2025
e458a4c
rename
hoophalab Jul 14, 2025
f3b9492
fix copy number
hoophalab Jul 14, 2025
b99b23a
use else if for hashParams check logic
Henry8192 Jul 15, 2025
95fbb0c
remove debugging message
hoophalab Jul 15, 2025
46124e1
Update src/components/AppController.tsx
hoophalab Jul 15, 2025
8506148
move updateUrlIfEventOnPage to url.ts
hoophalab Jul 15, 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
134 changes: 129 additions & 5 deletions src/components/AppController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,149 @@ import React, {
useRef,
} from "react";

import useLogFileManagerProxyStore from "../stores/logFileManagerProxyStore";
import useLogFileStore from "../stores/logFileStore";
import {handleErrorWithNotification} from "../stores/notificationStore";
import useQueryStore from "../stores/queryStore";
import useViewStore from "../stores/viewStore";
import {Nullable} from "../typings/common";
import {
CURSOR_CODE,
CursorType,
} from "../typings/worker";
import {
findNearestLessThanOrEqualElement,
isWithinBounds,
} from "../utils/data";
import {clamp} from "../utils/math.ts";
import {
getWindowUrlHashParams,
getWindowUrlSearchParams,
updateWindowUrlHashParams,
URL_HASH_PARAMS_DEFAULT,
URL_SEARCH_PARAMS_DEFAULT,
} from "../utils/url";


/**
* Updates the log event number in the URL to `logEventNum` if it's within the bounds of
* `logEventNumsOnPage`.
*
* @param logEventNum
* @param logEventNumsOnPage
* @return Whether `logEventNum` is within the bounds of `logEventNumsOnPage`.
*/
const updateUrlIfEventOnPage = (
logEventNum: number,
logEventNumsOnPage: number[]
): boolean => {
if (false === isWithinBounds(logEventNumsOnPage, logEventNum)) {
return false;
}

const nearestIdx = findNearestLessThanOrEqualElement(
logEventNumsOnPage,
logEventNum
);

// Since `isWithinBounds` returned `true`, then:
// - `logEventNumsOnPage` must bound `logEventNum`.
// - `logEventNumsOnPage` cannot be empty.
// - `nearestIdx` cannot be `null`.
//
// Therefore, we can safely cast:
// - `nearestIdx` from `Nullable<number>` to `number`.
// - `logEventNumsOnPage[nearestIdx]` from `number | undefined` to `number`.
const nearestLogEventNum = logEventNumsOnPage[nearestIdx as number] as number;

updateWindowUrlHashParams({
logEventNum: nearestLogEventNum,
});

return true;
};


/**
* Determines the cursor for navigating log events based on URL hash parameters.
*
* @param params An object containing the following properties:
* @param params.isPrettified Whether the log view is in prettified mode.
* @param params.logEventNum The log event number from the URL hash.
* @param params.timestamp The timestamp from the URL hash.
* @return `CursorType` object if a navigation action is needed, or `null` if no action is required.
*/
const getCursorFromHashParams = ({isPrettified, logEventNum, timestamp}: {
isPrettified: boolean; logEventNum: number; timestamp: number;
}): Nullable<CursorType> => {
const {numEvents} = useLogFileStore.getState();
if (0 === numEvents) {
updateWindowUrlHashParams({logEventNum: URL_HASH_PARAMS_DEFAULT.logEventNum});

return null;
}

const {
isPrettified: prevIsPrettified, updateIsPrettified, updateLogEventNum,
} = useViewStore.getState();
const clampedLogEventNum = clamp(logEventNum, 1, numEvents);

if (isPrettified !== prevIsPrettified) {
updateIsPrettified(isPrettified);

return {
code: CURSOR_CODE.EVENT_NUM,
args: {eventNum: clampedLogEventNum},
};
}

if (timestamp !== URL_HASH_PARAMS_DEFAULT.timestamp) {
return {
code: CURSOR_CODE.TIMESTAMP,
args: {timestamp: timestamp},
};
} else if (logEventNum !== URL_HASH_PARAMS_DEFAULT.logEventNum) {
updateLogEventNum(logEventNum);
const {beginLineNumToLogEventNum} = useViewStore.getState();
const logEventNumsOnPage: number [] = Array.from(beginLineNumToLogEventNum.values());
if (updateUrlIfEventOnPage(clampedLogEventNum, logEventNumsOnPage)) {
// No need to request a new page since the log event is on the current page.
return null;
}

return {
code: CURSOR_CODE.EVENT_NUM,
args: {eventNum: clampedLogEventNum},
};
}

// If we reach here, we have no valid cursor.
return null;
};

/**
* Updates view-related states from URL hash parameters.
* NOTE: this may modify the URL parameters.
*/
const updateViewHashParams = () => {
const {isPrettified, logEventNum} = getWindowUrlHashParams();
const {updateIsPrettified, updateLogEventNum} = useViewStore.getState();
const {isPrettified, logEventNum, timestamp} = getWindowUrlHashParams();
updateWindowUrlHashParams({
isPrettified: URL_HASH_PARAMS_DEFAULT.isPrettified,
timestamp: URL_HASH_PARAMS_DEFAULT.timestamp,
});

updateIsPrettified(isPrettified);
updateLogEventNum(logEventNum);
const cursor = getCursorFromHashParams({isPrettified, logEventNum, timestamp});
if (null === cursor) {
// If no cursor was set, we can return early.
return;
}

(async () => {
const {logFileManagerProxy} = useLogFileManagerProxyStore.getState();
const {updatePageData} = useViewStore.getState();
const pageData = await logFileManagerProxy.loadPage(cursor, isPrettified);
updatePageData(pageData);
})().catch(handleErrorWithNotification);
};

/**
Expand All @@ -39,6 +156,8 @@ const updateViewHashParams = () => {
*/
const updateQueryHashParams = () => {
const {queryIsCaseSensitive, queryIsRegex, queryString} = getWindowUrlHashParams();
updateWindowUrlHashParams({queryIsCaseSensitive, queryIsRegex, queryString});
Copy link
Contributor

@hoophalab hoophalab Jul 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm probably missing context again, but is there any reason adding this line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is meant to clear the query parameters, but unfortunately I forgot to set them to the default value (so that it is cleared)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i prefer making this change in a separate PR as a follow-up to

TODO: Remove empty or falsy parameters.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai Can you create an issue on this?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

I'll create an issue to track this follow-up work.

@hoophalab I've created a GitHub issue to track the follow-up work for fixing the query parameter clearing functionality. The issue covers both the incomplete implementation in the current PR and the broader TODO about removing empty/falsy parameters.


🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for the query parameter clearing follow-up
gh issue create \
  --title "Fix query parameter clearing in updateQueryHashParams" \
  --body "## Description

The \`updateQueryHashParams\` function in \`src/components/AppController.tsx\` currently has an incomplete implementation for clearing query parameters. A line was added to call \`updateWindowUrlHashParams({queryIsCaseSensitive, queryIsRegex, queryString})\` but this doesn't actually clear the parameters because it doesn't set them to their default values.

## Context

This issue was discovered during PR #152 where the line was added with the intent to clear query parameters, but the implementation was incomplete.

## Tasks

- [ ] Fix the \`updateQueryHashParams\` function to properly clear query parameters by setting them to default values
- [ ] Address the existing TODO comment: \`TODO: Remove empty or falsy parameters.\`
- [ ] Ensure proper parameter cleanup in URL handling

## References

- PR: https://github.com/y-scope/yscope-log-viewer/pull/152
- Comment: https://github.com/y-scope/yscope-log-viewer/pull/152#discussion_r2200335762
- Requested by: @hoophalab" \
  --assignee hoophalab

Length of output: 1158


@hoophalab Perfect! I've successfully created issue #345 to track the query parameter clearing follow-up work. The issue is available at: #345

The issue includes:

  • A detailed description of the incomplete implementation
  • Context from the current PR discussion
  • Task checklist for the required fixes
  • References to this PR and comment thread
  • Assignment to you for follow-up

This will help track the work needed to properly clear query parameters by setting them to default values, as well as addressing the broader TODO about removing empty/falsy parameters.


🧬 Code Graph Analysis Results

Relevant snippets for understanding src/components/AppController.tsx and addressing the user comment:


From src/typings/common.ts at line 6:

Nullable

Type alias or utility type representing a value that can be null, used in AppController.tsx for nullable types.


From src/typings/worker.ts at lines 103 and 110:

CURSOR_CODE

Enum or constant object defining cursor codes such as EVENT_NUM, TIMESTAMP, LAST_EVENT, used to identify navigation types in logs.

CursorType

Type describing the cursor object with a code property (one of CURSOR_CODE) and args for cursor parameters, used extensively in navigation and loading pages.


From src/stores/notificationStore.ts at line 76:

handleErrorWithNotification

Function to handle errors by showing notifications, used in AppController.tsx to catch and notify errors during async page data loading.


From src/utils/url.ts at lines 378-379, 383-384, 386-387:

getWindowUrlHashParams

Function to parse and return URL hash parameters as an object, used to read navigation and query parameters.

getWindowUrlSearchParams

Function to parse and return URL search parameters as an object, used to read file path and other parameters.

updateUrlIfEventOnPage

Function that updates the URL if a given log event number is currently visible on the page, returns boolean indicating if URL was updated.

updateWindowUrlHashParams

Function to update the URL hash parameters, used to synchronize URL state with application state.

URL_HASH_PARAMS_DEFAULT

Default values for URL hash parameters, used for resetting or comparing current URL hash state.

URL_SEARCH_PARAMS_DEFAULT

Default values for URL search parameters, used for resetting or comparing current URL search state.


From src/services/LogFileManagerProxy.ts at lines 17-43 and 66-69:

async loadFile (
    {decoderOptions, fileSrc, pageSize}: {
        decoderOptions: DecoderOptions;
        fileSrc: FileSrcType;
        pageSize: number;
    },
    onExportChunk: (logs: string) => void,
    onQueryResults: (queryProgress: number, queryResults: QueryResults) => void,
): Promise<LogFileInfo> {
    // Creates and returns a LogFileManager instance and its info.
}

Asynchronous method to load a log file with given options, returning metadata and file info.

startQuery (queryString: string, isRegex: boolean, isCaseSensitive: boolean): void {
    // Starts a query on the log file with given parameters.
}

Method to start a query on the log file, used indirectly via query store.


From src/services/LogFileManager/index.ts at lines 129-131 and 303-333 and 439-473:

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

Getter for the number of log events in the loaded file.

startQuery ({queryString, isRegex, isCaseSensitive}: QueryArgs): void {
    // Starts a query with regex and case sensitivity options.
    // Handles empty queries and invalid regex with error handling.
}

Starts a query on the log file, managing query state and error handling.

#getCursorData (cursor: CursorType, numActiveEvents: number): CursorData {
    // Converts a CursorType into internal CursorData for navigation.
    // Supports cursor codes PAGE_NUM, LAST_EVENT, EVENT_NUM, TIMESTAMP.
    // Throws error on unsupported cursor codes.
}

Internal method to translate cursor info into data used for loading pages or navigating logs.


These snippets provide context on:

  • URL parameter handling and synchronization with app state.
  • Cursor types and navigation logic.
  • Log file loading and querying mechanisms.
  • Error handling with notifications.
  • Types and constants used throughout AppController.tsx.

This information is essential for understanding the behavior of AppController.tsx and for creating an issue related to its functionality.


🧠 Learnings used
Learnt from: zzxthehappiest
PR: y-scope/yscope-log-viewer#286
File: src/components/CentralContainer/Sidebar/SidebarTabs/SearchTabPanel/QueryInputBox.tsx:37-40
Timestamp: 2025-06-01T13:41:12.938Z
Learning: The `updateWindowUrlHashParams` function in `src/utils/url.ts` doesn't throw errors, so error handling is not needed when calling this function.

Learnt from: davemarco
PR: y-scope/yscope-log-viewer#76
File: new-log-viewer/src/utils/actions.ts:105-133
Timestamp: 2024-10-08T15:52:50.753Z
Learning: In the `actions.ts` file, the `PAGE_TOP` and `PAGE_BOTTOM` actions are not intended to be handled in the `getPageNumCursorArgs` function.

Learnt from: davemarco
PR: y-scope/yscope-log-viewer#76
File: new-log-viewer/src/utils/actions.ts:105-133
Timestamp: 2024-09-25T21:12:28.732Z
Learning: In the `actions.ts` file, the `PAGE_TOP` and `PAGE_BOTTOM` actions are not intended to be handled in the `getPageNumCursorArgs` function.

Learnt from: davemarco
PR: y-scope/yscope-log-viewer#76
File: new-log-viewer/src/utils/actions.ts:84-139
Timestamp: 2024-10-08T15:52:50.753Z
Learning: In the `getPageNumCursorArgs` function, variables `newPageNum` and `anchor` are always initialized when handling valid actions, so there is no risk of them being uninitialized.

Learnt from: davemarco
PR: y-scope/yscope-log-viewer#76
File: new-log-viewer/src/utils/actions.ts:84-139
Timestamp: 2024-09-25T21:13:37.250Z
Learning: In the `getPageNumCursorArgs` function, variables `newPageNum` and `anchor` are always initialized when handling valid actions, so there is no risk of them being uninitialized.

Learnt from: junhaoliao
PR: y-scope/yscope-log-viewer#94
File: new-log-viewer/src/components/CentralContainer/Sidebar/index.tsx:99-118
Timestamp: 2024-10-19T03:33:29.578Z
Learning: In `new-log-viewer/src/components/CentralContainer/Sidebar/index.tsx`, when using `useEffect` to register window resize event handlers, it's acceptable to have an empty dependency array because the variables and functions used within the effect (`getPanelWidth`, `PANEL_CLIP_THRESHOLD_IN_PIXELS`, and `tabListRef`) are constants or refs declared outside the functional component and do not change.

Learnt from: Henry8192
PR: y-scope/yscope-log-viewer#80
File: new-log-viewer/src/services/LogFileManager.ts:297-313
Timestamp: 2024-10-09T02:08:56.053Z
Learning: In the `#searchChunk` method of `LogFileManager.ts`, checking `typeof match.index === "number"` correctly handles matches at index 0, ensuring matches at the beginning of the string are not skipped.

Learnt from: zzxthehappiest
PR: y-scope/yscope-log-viewer#286
File: src/components/AppController.tsx:40-43
Timestamp: 2025-06-01T13:44:05.278Z
Learning: In the y-scope/yscope-log-viewer codebase, when functions return invalid or default log event numbers, they should use 0 as this aligns with URL_HASH_PARAMS_DEFAULT.LOG_EVENT_NUM which is set to 0. This maintains consistency with the established default hash parameter pattern.

Learnt from: Henry8192
PR: y-scope/yscope-log-viewer#224
File: src/contexts/states/logFileStore.ts:72-79
Timestamp: 2025-05-09T22:39:04.485Z
Learning: In the log viewer application, silently ignoring calls to `handleExportChunk` when `logExportManager` is null is intentional, as the page is reloaded in this scenario anyway.

Learnt from: zzxthehappiest
PR: y-scope/yscope-log-viewer#286
File: src/components/Editor/index.tsx:138-139
Timestamp: 2025-06-01T13:40:12.222Z
Learning: In the yscope-log-viewer codebase, when using Zustand stores in React components, the preferred pattern is to use `getState()` for static setters that never change (like `setLogEventNum`) to avoid unnecessary subscriptions, while using hooks for actions that do more than just setting values. All store state variables should be declared at the beginning of the component for consistency and clear dependency overview.


const {
queryIsCaseSensitive: currentQueryIsCaseSensitive,
queryIsRegex: currentQueryIsRegex,
Expand Down Expand Up @@ -110,7 +229,12 @@ const AppController = ({children}: AppControllerProps) => {
if (URL_SEARCH_PARAMS_DEFAULT.filePath !== searchParams.filePath) {
let cursor: CursorType = {code: CURSOR_CODE.LAST_EVENT, args: null};

if (URL_HASH_PARAMS_DEFAULT.logEventNum !== hashParams.logEventNum) {
if (URL_HASH_PARAMS_DEFAULT.timestamp !== hashParams.timestamp) {
cursor = {
code: CURSOR_CODE.TIMESTAMP,
args: {timestamp: hashParams.timestamp},
};
} else if (URL_HASH_PARAMS_DEFAULT.logEventNum !== hashParams.logEventNum) {
cursor = {
code: CURSOR_CODE.EVENT_NUM,
args: {eventNum: hashParams.logEventNum},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import {
TAB_DISPLAY_NAMES,
TAB_NAME,
} from "../../../../../typings/tab";
import {copyPermalinkToClipboard} from "../../../../../utils/url";
import {
copyPermalinkToClipboard,
URL_HASH_PARAMS_DEFAULT,
} from "../../../../../utils/url";
import CustomTabPanel from "../CustomTabPanel";
import PanelTitleButton from "../PanelTitleButton";
import QueryInputBox from "./QueryInputBox";
Expand Down Expand Up @@ -55,7 +58,7 @@ const SearchTabPanel = () => {
setQueryString(queryString);

copyPermalinkToClipboard({}, {
logEventNum: null,
logEventNum: URL_HASH_PARAMS_DEFAULT.logEventNum,
queryString: queryString,
queryIsCaseSensitive: queryIsCaseSensitive,
queryIsRegex: queryIsRegex,
Expand Down
26 changes: 19 additions & 7 deletions src/services/LogFileManager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,8 @@ class LogFileManager {
*/
#getCursorData (cursor: CursorType, numActiveEvents: number): CursorData {
const {code, args} = cursor;

let eventNum = 0;
switch (code) {
case CURSOR_CODE.PAGE_NUM:
return getPageNumCursorData(
Expand All @@ -449,15 +451,25 @@ class LogFileManager {
case CURSOR_CODE.LAST_EVENT:
return getLastEventCursorData(numActiveEvents, this.#pageSize);
case CURSOR_CODE.EVENT_NUM:
return getEventNumCursorData(
args.eventNum,
numActiveEvents,
this.#pageSize,
this.#decoder.getFilteredLogEventMap(),
);
({eventNum} = args);
break;
case CURSOR_CODE.TIMESTAMP: {
const eventIdx = this.#decoder.findNearestLogEventByTimestamp(args.timestamp);
if (null !== eventIdx) {
eventNum = eventIdx + 1;
}
break;
}
default:
throw new Error(`Unsupported cursor type: ${code}`);
throw new Error(`Unsupported cursor code: ${code as string}`);
}

return getEventNumCursorData(
eventNum,
numActiveEvents,
this.#pageSize,
this.#decoder.getFilteredLogEventMap(),
);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/services/decoders/ClpIrDecoder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ class ClpIrDecoder implements Decoder {
return this.#streamReader.getMetadata();
}

findNearestLogEventByTimestamp (timestamp: number): Nullable<number> {
return this.#streamReader.findNearestLogEventByTimestamp(BigInt(timestamp));
}

setLogLevelFilter (logLevelFilter: LogLevelFilter): boolean {
this.#streamReader.filterLogEvents(logLevelFilter);

Expand Down
28 changes: 28 additions & 0 deletions src/services/decoders/JsonlDecoder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,34 @@ class JsonlDecoder implements Decoder {
return results;
}

findNearestLogEventByTimestamp (timestamp: number): Nullable<number> {
let low = 0;
let high = this.#logEvents.length - 1;
if (high < low) {
return null;
}

while (low <= high) {
const mid = Math.floor((low + high) / 2);

// `mid` is guaranteed to be within bounds since `low <= high`.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const midTimestamp = this.#logEvents[mid]!.timestamp.valueOf();
if (midTimestamp <= timestamp) {
low = mid + 1;
} else {
high = mid - 1;
}
}

// corner case: all log events have timestamps >= timestamp
if (0 > high) {
return 0;
}

return high;
}

/**
* Parses each line from the data array and buffers it internally.
*
Expand Down
3 changes: 2 additions & 1 deletion src/stores/viewStore/createViewPageSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,11 @@ const createViewPageSlice: StateCreator<
});
},
updatePageData: (pageData: PageData) => {
const {setPageData, updateLogEventNum} = get();
const {setPageData} = get();
setPageData(pageData);
const newLogEventNum = pageData.logEventNum;
updateWindowUrlHashParams({logEventNum: newLogEventNum});
const {updateLogEventNum} = get();
updateLogEventNum(newLogEventNum);
const {setUiState} = useUiStore.getState();
setUiState(UI_STATE.READY);
Expand Down
19 changes: 19 additions & 0 deletions src/typings/decoders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,25 @@ interface Decoder {
endIdx: number,
useFilter: boolean
): Nullable<DecodeResult[]>;

/**
* Finds the log event, L, where if we assume:
*
* - the collection of log events is sorted in chronological order;
* - and we insert a marker log event, M, with timestamp `timestamp` into the collection (if log
* events with timestamp `timestamp` already exist in the collection, M should be inserted
* after them).
*
* L is the event just before M, if M is not the first event in the collection; otherwise L is
* the event just after M.
*
* NOTE: If the collection of log events isn't in chronological order, this method has undefined
* behaviour.
*
* @param timestamp
* @return The index of the log event L.
*/
findNearestLogEventByTimestamp(timestamp: number): Nullable<number>;
}

export type {
Expand Down
4 changes: 3 additions & 1 deletion src/typings/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ enum SEARCH_PARAM_NAMES {
}

enum HASH_PARAM_NAMES {
LOG_EVENT_NUM = "logEventNum",
IS_PRETTIFIED = "isPrettified",
LOG_EVENT_NUM = "logEventNum",
QUERY_IS_CASE_SENSITIVE = "queryIsCaseSensitive",
QUERY_IS_REGEX = "queryIsRegex",
QUERY_STRING = "queryString",
TIMESTAMP = "timestamp",
}

interface UrlSearchParams {
Expand All @@ -23,6 +24,7 @@ interface UrlHashParams {
[HASH_PARAM_NAMES.QUERY_IS_CASE_SENSITIVE]: boolean;
[HASH_PARAM_NAMES.QUERY_IS_REGEX]: boolean;
[HASH_PARAM_NAMES.QUERY_STRING]: string;
[HASH_PARAM_NAMES.TIMESTAMP]: number;
}

type UrlSearchParamUpdatesType = {
Expand Down
12 changes: 6 additions & 6 deletions src/typings/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,24 @@ enum EVENT_POSITION_ON_PAGE {
* - PAGE_NUM: the first or last event on the given page
*/
enum CURSOR_CODE {
LAST_EVENT = "lastEvent",
EVENT_NUM = "eventNum",
TIMESTAMP = "timestamp",
LAST_EVENT = "lastEvent",
PAGE_NUM = "pageNum",
TIMESTAMP = "timestamp",
}

type CursorArgMap = {
[CURSOR_CODE.LAST_EVENT]: null;
[CURSOR_CODE.EVENT_NUM]: {
eventNum: number;
};
[CURSOR_CODE.TIMESTAMP]: {
timestamp: number;
};
[CURSOR_CODE.LAST_EVENT]: null;
[CURSOR_CODE.PAGE_NUM]: {
pageNum: number;
eventPositionOnPage: EVENT_POSITION_ON_PAGE;
};
[CURSOR_CODE.TIMESTAMP]: {
timestamp: number;
};
};

type CursorType = {
Expand Down
Loading
Loading