Skip to content

Conversation

Henry8192
Copy link
Contributor

@Henry8192 Henry8192 commented Jun 13, 2025

Description

Instead of subscribing logEventNum changes in AppController useEffect, setLogEventNum is changed to updateLogEventNum, which handles logEventNum change and triggers a page load if needed.

viewStore is also refactored using zustand slices.

Checklist

  • The PR satisfies the contribution guidelines.
  • This is a breaking change and that has been indicated in the PR title, OR this isn't a
    breaking change.
  • Necessary docs have been updated, OR no docs need to be updated.

Validation performed

Summary by CodeRabbit

  • New Features

    • Introduced a unified view state management system consolidating event handling, pagination, filtering, and formatting into a single store.
    • Added advanced log filtering by log level and improved log formatting (prettified view) options.
  • Improvements

    • Simplified URL synchronization by removing automatic updates tied to event number changes.
    • Updated log event number handling methods for consistency across components.
    • Enhanced log loading processes with clearer UI state transitions and error notifications.
  • Refactor

    • Modularized state slices for event, page, filter, and formatting management to improve maintainability and performance.
    • Removed redundant URL and page-loading logic to streamline component behaviour.

Copy link

coderabbitai bot commented Jun 13, 2025

## Walkthrough

This change refactors view state management by introducing a modular Zustand store architecture with distinct slices for events, pagination, filtering, and formatting. It removes URL and page synchronization logic from `AppController`, delegating log event navigation and related side effects to the new store. Associated components are updated to use the new store API.

## Changes

| File(s)                                                                                  | Change Summary                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
|------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| src/components/AppController.tsx                                                         | Removed all logic syncing `logEventNum` state with URL and page loading; simplified URL param update functions; removed `logEventNum` state subscription; now only initializes state from URL/hash on load and hash changes.                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| src/components/CentralContainer/Sidebar/SidebarTabs/SearchTabPanel/Result.tsx<br>src/components/Editor/index.tsx | Updated to use `updateLogEventNum` (from Zustand store) instead of `setLogEventNum` for log event navigation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| src/stores/viewStore/index.ts                                                            | Introduced and exported a new Zustand store `useViewStore`, combining four view state slices: event, page, filter, and formatting.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| src/stores/viewStore/types.ts                                                            | Added TypeScript interfaces/types for view state slices: pagination, event, formatting, filtering, and the combined `ViewState`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| src/stores/viewStore/createViewEventSlice.ts                                             | New Zustand slice: manages `logEventNum` state, updates URL, loads new pages if needed, and handles errors. Exports `createViewEventSlice` and default state.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| src/stores/viewStore/createViewPageSlice.ts                                              | New Zustand slice: manages pagination state, provides actions for page navigation/loading, updates URL and global state, and handles errors.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| src/stores/viewStore/createViewFilterSlice.ts                                            | New Zustand slice: provides `filterLogs` method for log level filtering, updates UI state, fetches filtered data, and handles errors.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| src/stores/viewStore/createViewFormattingSlice.ts                                        | New Zustand slice: manages prettification state, updates UI and page data on change, and handles errors.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| src/stores/logFileStore.ts                                                               | Removed explicit setting of log data to `"Loading..."` during file load; replaced with resetting structured page data. No other logic changed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant UI_Component as UI Component (e.g., Editor, Search Result)
    participant ViewStore as useViewStore (Zustand)
    participant LogFileManager as logFileManagerProxy
    participant URL as URL Hash

    UI_Component->>ViewStore: updateLogEventNum(newLogEventNum)
    alt event is on current page
        ViewStore->>URL: Update hash param with new logEventNum
    else event not on current page
        ViewStore->>UI_Component: Set UI to FAST_LOADING
        ViewStore->>LogFileManager: loadPage({eventNum: newLogEventNum})
        LogFileManager-->>ViewStore: Return page data
        ViewStore->>ViewStore: updatePageData(pageData)
        ViewStore->>URL: Update hash param with new logEventNum
    end

Possibly related PRs

  • #286: Refactors AppController.tsx to move URL parameter handling from React context to Zustand stores and adds hashchange event listeners—directly related as both PRs modify URL/event sync in AppController.
  • #224: Replaces React context provider with Zustand stores for global state, including view-related stores—closely related as this PR continues and expands upon that state management refactor.

Suggested reviewers

  • junhaoliao

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> npm error Exit handler never called!
> npm error This is an error with npm itself. Please report this error at:
> npm error   <https://github.com/npm/cli/issues>
> npm error A complete log of this run can be found in: /.npm/_logs/2025-06-23T19_31_35_353Z-debug-0.log
> 
> 
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 745e75dd9c788632cf0625b28add947bdc2ba860 and b4cf71a253ab4172caf3de7b7741e8f7ca255f01.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `src/stores/logFileStore.ts` (4 hunks)
* `src/stores/viewStore/createViewPageSlice.ts` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>📓 Path-based instructions (1)</summary>

<details>
<summary>`**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}`: - Prefer `false == <expression>` rather than `!<expression>`.</summary>

> `**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}`: - Prefer `false == <expression>` rather than `!<expression>`.

- `src/stores/logFileStore.ts`
- `src/stores/viewStore/createViewPageSlice.ts`

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (7)</summary><blockquote>

<details>
<summary>src/stores/logFileStore.ts (2)</summary>

`31-32`: **LGTM: Clean imports for view store defaults**

The imports for `VIEW_EVENT_DEFAULT` and `VIEW_PAGE_DEFAULT` are properly added to support the refactored initialization logic.

---

`146-146`: **LGTM: Simplified destructuring after state initialization**

The change to only destructure `isPrettified` is appropriate since `updatePageData` is now called directly on the retrieved page data, eliminating the need to destructure it here.

</details>
<details>
<summary>src/stores/viewStore/createViewPageSlice.ts (5)</summary>

`37-75`: **LGTM: Well-structured navigation cursor logic**

The `getPageNumCursor` function correctly handles all navigation actions with appropriate page clamping and position setting. The logic properly:
- Clamps page numbers within valid bounds
- Sets appropriate cursor positions (TOP/BOTTOM)
- Returns null for unsupported actions

---

`77-82`: **LGTM: Appropriate default values for page slice**

The default values are sensible:
- Empty map for line-to-event mapping
- Clear "No file is open" message
- Zero values for page counts

---

`113-119`: **Good error handling for invalid reload state**

The validation logic correctly checks for invalid states during reload and provides meaningful error messages with contextual information.

---

`129-133`: **Appropriate UI state validation with informative logging**

The check for `UI_STATE.READY` prevents navigation during loading states, and the console warning provides useful debugging information.

---

`144-151`: **Robust async page loading with error handling**

The async page loading logic is well-structured:
- Proper error handling with notification
- Correct use of the file manager proxy
- Appropriate state updates after successful load

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEYDEZyAAUASpETZWaCrKNxU3bABsvkCiQBHbGlcABpIcVwvOkgAIn8AMzQxfAouAFl8KUgvfCIAUSkMXAA5R0hsblpqEkhYTFoveAwiSASKFkgAQW5uAGF8Yo6fSgj8SAl4EgB3AGUCfwBuSFnuJtwJqbmF2uaCeyaGaVDYyGm0ZAcBZnUaejkKxFGACTIXAA4ARgBOACZ0ZC2SAYRwCUYAZk+ADYUFhcLBarIwIgmNwSAB6WQo/BosC5IhgSYzUb+bj4RDqVKyDQwBGQZjaLAMeotXYYCT4LxSZCJZILZqtWD4aYVKo1ZD7eG1AAG+MK7DKzGl9lwNXQ/jqDWitBpAEkMIgaGh6PgEvZsAIURR4GoWmNILK8vLiorlczMKRkNN1AgsGgHdgnvkEglRLhlUL8ABrWEUpQROnSnr9Qa4YbRChulhk8jFcJStrYDBieCDB1PXAAGSdRVKjgjF0gYLIfjIaDY9AajBZpHo+2llWqNGrBVrrpp7mQ5BFCSLJbLDIwaE9DrlY/r3Y90kgtHg/jEXnkXbT8CIpAoyH93GXtVyxpQZvIR0QiGc1KMXVou/EgzQPlk+aJkS2ypCQDYyCQLa8ik/h9uMga1AAXoGqoYPQiCHMc9KKN4zjwIhAoJrUhpqouN5sMUsL7IgDIjBQ4TMKB9KYDeKjRDwzi4IgE50p4PitkEISwgwXjYEol7dqIUZNIa9pkA4GpMMwazwJgRxnD6ChDDaeCllgRDYPAShNOQiD5uMzS7gwarTAiUp8AW7qsigMj+GgUaEakwL4GE6BofaTAYAke7MA+O74AwjjsNQemikO27OLU/hBHudA0iU4yIGiDDwMFDATH+RkxWWXk0IahFKKq8BeF6lC1LwWRGTEzRETu0gMNa3A/hgPG1Fkyj8UQ+B/vwZoFkCqD7PAykdNkjmKCQAgXLUDxHEMhUEXaBaDmq+LwPlCReY6o4Khu3rwi1BYkTQKpMVQ9kJpgmpoSZrTqLCrVKTm7BaWmnIZuEx7jGQLLqVdabYGI2AaqarXSsB8ygcq8IdNgRCwAc+0Cho5iWAMrDsJcjgMi4bh0kpFFcfwcIIMgfG+MlwSyc0IlibU/q7iigYUmWzTqKpdxNvIBZoHgQr0ZArwYB8Py/L18iJKM+xXv4kz4IGPD4Hs6ACOrGz+IxkxbYmFYjgAItQaDKrOxbdeEbmIIMhHwtQ9gszK+IW6qbpPWC9gkBsDwDmKNBWDeXtW4BMqm3kEfW3O3X0qesCB0ldBFtUxQ0lLMt/N5ZWPRs0ox0QccuYw0P+MUh6PM1NMe8NtAAGLVWBha27FU0YPzG0N6XlvSuEAh4OaZ4hMg73TOrXj3CtAc0A5Fnd+Ivf8A9/heDU6GqgXjbTCQPjhI7hcBiHJBh6QZfWVgfsIfQJAAB6sxSUg14dfDXWyPdNIhxV+v5O0yo4wME3f6wpna03CDnWQXw84XCjF6OyCIHJ0lfGwHIeR9r2CFN4TsvQa79grC3aIJR2xgXCNNNYsgIGu2LgHYhJBSFsGVDcdGGw/zHz9gbfqJo+Ckk3kcdC01qrOAIZlNMJB2wmWIjvWoZFSCU2AfqVsWVBhPHCIFE8w8FiQCEEWeonJVLjBEnhYK24XZFyIa3JhbcwS5BaBKcYBZgrsUNKBcItl9oY1QHrOMtQrqoj6mNcmlcfrAVuhqaC/I7S2GzsKEgUgJZ6IwAYpoaBxjLn8OY+o7C3Y3E3nwkgSQYKESYLgps7N8FTDgq1FxMimItX9E8a8916reAZoEJmmgjAZTXsghQBNijIC8pzSKL49KXg1LwaQP1Lq8Vmk1egQ40DAP0MYcAUAyAmjNKLAgxAyDKEFhTdgXBeD8GEGGSQ25VoLSoKodQWgdBrJMFASc5cnq7MIKQcgrT6DHOKFwKgIoHBOBcELBQSg7lqE0NoXQYBDDrNMAYRAFAGDoi+oMQm6JkwDCGP9SgGguIPw4AYWIZKDAWG6LqfZPyt7mlBfIWGTlPRk1qLuEMrZDYJX4ntfKG86XUVkMWWAHRu6bVaAWY6zo6xKhVDZTSBYACqNhKx+XoHeXcdppwcRXEtJ4JosDqGQMy6QNJViiFyvtP8h4KEbGMgHbJMpAEkEVRQLwuoEjSoAPIYAvm3BEXg0R8BtvOf+fZEwIWDKGMQEZ8DRhPiY5SMQpXriVBohEDAozNTNJPRsZZHKhMoteUg4RnXhtqMq1VyQmAUE1UQG1/AHLWjHrBDBxpCL+m1cW2okx/THQYekFi54rAdAfrIaUNIBgUH8KotChFKGpCpvywWkoERPH4EGv+ZlhKiTrREhKADxDrHkCG7qyB36ME3spDt/ldYZ2NRmjyLRAYag4eMbhUgdSsvbqG5Awd4oADUtjPAuLAMOVBmCIGVF2f9NQACKwQXAgcQGB5w7YoPqmIpQpoZj7gKxIIbCBJA9wcQgw6i8arYxGiWalA88hrI+EItKUguAADqllhSuq8Mh1DEHEAAAoACUyo9iUCXP+e0/gTwJIrSqzUKHSNkIXtxSAU6Z05jrQ2hjNV7RSnXaeiZ3kMGsj4NeF8im2DKeAXAGULJGgkB430HsbcDO82QGWgK1rWotKU5QaI5nEk8wNKNU+gHgOgfA+h6D/lYM0AQ5QWQPHIuQYnZAXU7CarvoI/1CUdIpPQywLDSt8mMY+cs5QbiRhlGSpxamdMlAszKUxXmVquQGNypulcK08Auqd3GCm06srUAfrSrSL+K8f5/0gEU6N+sCOMm3RWcQdpKitXqApk1OQkA0B+ZRjVRHYTfzaK3Jsy0DWQGK2V8j27tFGfseeVsfJHGrhrINt0znnvOtasVryGqdWmqMF6xJ1qo6blZDybLc06RsCckgUKFj7BCuZKK/Cya1xvY67UE1XpNLFedZefy3a211qPth3K1DjZY+zM1jY+xBg1z5hN1HmO2gdFCpdtD5WKNlj+12Ms62MbY+AbjboXgF5bt03SJQJj7qGdho/MkFBBZeU8AIQ403ij82kEYKAvTsdyQfor5XpmLTq/YOoeQ0uCkS/3hqBkSheoOlq3iuijXvqUQpEQJcuBoZpwZM0dzwqtxfrJbEHXSKUVooxbmLi6I+jsCoF4XFVUfnolmE1JaFA08Z+cNAFQiA0+SNRbAPPAgw7kC8OiGw0hvCaCJSS0PFLLBdGpd8w5MQQUk0ZWabH36mDxn1wWSzQo/nWpiPmuk4S3Eak/qzzodCqyvZdBufszqRzStdBpC69cHR2eiNXhwYuABCeACAYD6IcKMPsfBLUzTSI/PkMbD8UJMtO0nP1z/h6gsh+7MdDxHttGfD+onEuOguthUlBCQGsMkHQBQnOtZMtq0P6JtnMrUF0FYLqI2vSAHCPsCO2IRBeoAgdviNNrWMCKCASmNiohsLDAWLynAazHukQZThdnJgLhZtdpRo5NarfjGEoGiGhGQDlFhAbAthUEHqyF+kYE3qLuLmepLmyqINbvIfLobouuPibmrlgubuINrgYBlOQDjI3gYBAGAEYJHuitTjHgXvkN+KkOiJZI/ISogMSqSuSpSi3jSu3uhMTG+CFr3gYNVomHviQH0NDI7BQPkIbocOoFYOSE5luNfl4LwVvr6HDLYZSJmAMu7r5ODGqF9s/vQO0J0JKghEBjMIjP4MqNPrUOAc2EyM5jqNYKrKWIGA2kPjgYoOWAHOvqmsqOcBDu/jEF2NpjEOdBjAWNqiQTJpRCCMwGCBQDxKgHUZBFgPwjAXhq2O/jeqPoxnaLFiQL0RjgHtRuEGZhSCwWgjKNOEccvrKs4AZIopAL0o/qMLylgZosMG0LkCKPrrbnIsaGyAmKgE8KGsLjIV0GLocoZquooTLhLqoUbhoTwKbtoZrroYgDrs8cYh9goW1PCSoR/KeN7r7sMmaAruobwiiVoflDoVMLVHboCUYeSiYRHqiuiDUQXgjDsA4YIQ/M4Q3u4c3q3gcr8vSl3v4R9h+MCDMJAAAFooRdg1F4EdgBhPDlEgRVHlwdSSKCxdgUlK7DG5aKFJC16f6tSMS0DeAkBLGXA7ADK2jbiHTQyYzPghaz5di8pcDSg6k1AanSqzCYSDwOi+k0AanEILyBn7TkIhluRhlbCgIUAMi4CIFRlHDBkwahkkAal+pplgQ0j5DJAYwYTRnlyM6qQ/wxAPBZRuR7pGpbEFbj4XJiBUROKoI7AADkdpNQjuNRXZLOuAsgaI5cSgwU5AmxkqGp8wNQImxQlAxSNptIIJAcq2a0aYvcyAwEYAy6HesizES4CiP0DwbAFARAhEMxGwe+Ao4QLiC815bQqQyZiBgMhOy4zQU2rm4mWuE8xQGSbsLQri9pJxakNpIukJchMJbZcJyhcu5JahhpVJquZu6J9JWJJQspo5osYu028FnAap2ZWwlRbc/G/oCpJE/kypkYUYgmH0xc7JnJ6I3JoEvJSg/JXE0obhYerJZhyK9FOwXJhFPJg5aI3EXEgpYeHhIptKgsnefhTKUpBgXQMpIo0AQ5JAswHUPWtOalbUY5/MZYdSZZeKVpgiJ8o5zQ24omFAC5BOfYal56Xk8iB2s+sM/oU+9pO5NSJBwE2MaWGwWU6wxpLOew4wzAtePWrimEiA3pOZN4eZLCQ624xa75icnpeQO4lsqRPAHQQaGJD5fADIvQhE0i5B8xFW9o0xZBcxCx26dB6Vmi7AGihaGwRO1VlAL5cEqovg3a26f4gwrQ4x6Av6FVjc/2MgZ21MeBkwRAU2fIhmXYX2ROyyNI0o/ptY8VdQnItAQVkU06P0lVP0bVfAXYDUkw4kfkQ1ic+wX2DyDo4Zj51AqZQZEQVAmaiCOBSsdI3lWw5c0yKZlqwx/kLMu6B6l1fWYwZ47EF03ZNAK14Z1UkZz1p1TUEkhR9ot5bxeQMg8gJB0Qr8vU66JZbpiUDpFl9AIV6A2R/gCIBoVyd1glM5EQOlpIM65uLB5uGo7lTEn8NIkJvgVlNlXB9lmGOFSJRRXkj8C84mtc4JHhUJsuaieJVuaGKhcFYtWBSFaJkQqFJhzxspAtMBotlJMVWwfqAGf4TMyo/GyV3usUaVrQyy2VOIlAGJgmut6FIoBt6kBpdwJtMwfqXQv6Vtc1it+wf2PVlGi1N4GVqobtuuspwltQPtdAft0wuZz1/GSkjpf6sVpA5tok0g0W9Aq1ptN4gdZ60ocdetntc51lhtydtAqd0q+dltkAmdzVGCrQF5pVCxVdHtVE859duFKd9NMw0q5dEywdoa9oX2B1sxFBFAfdCdOlDdTd61GdWdFlOdWwzdFthdlGJdY9tYE9aild7t+ttdC5RtCFqdiZT5AoLd+91tUm4geUH5m8RAS9NdC8V9q9o90wd9j1AoJ9BoU9V18EQBf1r9VqicCQH9X9TNw5f9h9ADD1/1LQG1mdLA2d/9gD6DRAj9GGMG91SZQDLQIDUGCDXtSdw9jduDCNlAmDaN+wGNfA+I2NndOQMmXgCDid19vt/905NAVtm9pk/96d0ZwZKDAZQZ4QKDeDT1kjHV9D8t8Vbtxhph5hfFoEBe+IDCRFApnFEJUl3h4pclPeClNmL2xoDCLCnR5NO+A4TwI4+jOw1RQFyAlpANNS6xYM8yCSrRxqXmhCPRscls/GsQ1Y7aLQGgsTsQwm5pTjBFFRbjWVyBwT/WzqfqZcCO5ZG59I4Vaw9UN425B8dKs+ZiM8z2UoJGmFZpEge926wNYkTGYIZ5GAlYFlio0A+AtxMqUju1ERnT5Arocj6OdxUj7DVtFY9okTjc2McTgmcjcxfqUGyj0o3a44S5EO0BbpS2Ha/59at48zdoho1odog1rN+DlNZzkMPuraS1mVggIgYgvNX4+l4mDaAeTUrUFwSOIqgw6s56CcekoO4kEMUM5zrQsMSTU5OwGgLGQjJAQmImD6wekmkOTqZ82TA85pBY4LFAdz0MHa4yXulMywJxkitAcjWT4cuLqAoxNG+4UQR4CQC85yKeTG3acc6U4wrxfAg+xidWnI3xwo4QlAHQfAV5z6WBs++OIt9uoFEJ8tEusJ+JMFitiJlJGtqJtJKFehuuOJW41TUuShKtcuRJXu1ApJIWDdOrNJGu2tllWAdFaKDFejrcBj7FzJXFmjvFbr/FjFglzFWZa17AeZhjjeklXhYpslYK8lxrZMqA2qhl5lYjpFipFFe5RNtQF6TlLB7laonlI1XdtYP5lNiquoeoGwPtEkdT2Fn5sZupyT0wMjkjCacZCUrpQSrU9aggI0s+g1eTvgDTBdtlF1zqwaILBlpUISe1lEc9GwR1vZmEzEewYhfa4z/TwVy8FZqONSiElA+A1m5MTEn5hUg55cpRZ8fTm+hRHiCAzIl67Y3AQVjMIQMQ3dR1qRqBBUTQ9AVAzkqh2255Zb1bREDRUkE8wSSdVVC9v1rNlEE+WOzVNcGqMQRONyykeEdoy4C2uShVtrcHZVFGYdFlPdFWeoMHpBsywyO+u1VcLVN4tqcU4o32bBoGHB7L+wiQ0QLZBYX78HXYaAHIRkwLSu/S+2MTVW1H3dybPkk1Ba87THJaKAtOza54EklbLOm2ysbQFwGwUnrQlp7M/kfzwqoqQLNc77hoQVaAvQOV1oaojzqo5p/oJBhl8iowDUY6jwBzgzXkzzYY9g2U5OB2gnJHNIiqOY5oDAz4iAs4vgRnLH8rBYLn/ov7PNkA+Q06qQyAVpULwJl4iA/zlnGsztCtfoikosbClGIR9Ag1naPklqCBekwCSlAaQawBsUBxXGHq3qvqN4yoQh9nh+bHdVZ5+U+wiS5OYUT0EXCx5c4xv7d6aEZJn0Hd3a/ZC35VC1Z8QVxW7B1aqQmm1IVBObKATWSum5eEQLFQR6Fu3XitfOD0nJAUcataKVMiaoSpPzM2YYlWBgQOA0XgoOF3yN51nx+K9AzB0L1HwEMQi7FHEsxWJXFnTsv8dslGgU34ekI0RnIWXaN471O+NngscnU4CnDH7AaHjcaUYFKr8harytlX63drKuurjr35WJn4SgfyaiqERcAGuo+QrGAA+vkABvkCUNAGL2bPkE3F0IqpWNAMqLQTpdI7WIQ/0ZpPW/5XuaO0zDjFALz5+7Q09y66GzvevdGVwEi30HGakMAHCzUOEAANoAC67vXvkAYbxQeZeg/Rj7gunb47+WFAwWBY4S3dF3mijIAoJKkAugKwe5DUuV8gA2dxXAR1HFSfUA6Q9joWNQt7jg/GNxS+Mq2fC9gmXAontAyMED8UG3ynnDO3fAg1ia3A95eOZ8yjOPHzI0RORnPr4ePFFhDFTF/g6Knb8NqjmEkbQpVKMb5Tvh8bFjibilyl8pmb28aoF3oByaVvMwEZjDz1qAewHQJlMQ+wXnmwMwpTm8gsrDBB07X5l7y3O+9nKkrXZYWXbyF3FJJ4BJAuJHMAQpXQFhrDRrShWGI4DDJ4ifbVooCVMPtCOErDcMT+WRK7AvBpCsYaasIDkFmmpZqd/YVMJVJgVnx6ckgskAniZyjh+g0eyOCARhHkBWUnsaTThp50SqmZR0wsDJPgmFh0hWGp2fVIpznaMcaO89EjpRigYtcpsWXLoGyxJCiBiMRsVoKwww7R1lkKXfbq1ELY3Rjun3ACkeH8gngW0EkQSGChnSqglcvNDAPIAlZ5cdwxLY2KgHM6MCMAd3BqPFxFrWQ0YKcOrlqBiC9pKaHg6Bj/ywAw4WQcOFdqWVExEBWkOOeEH0lGBvcHACA5AJW3CAecTsXnCWF2AsHyA3u+wJgCdy+4s55Wv3eMP9zECA8GeEFUOlBXVbmtNWatbVhzwdZ0kDW3QL8Gb3Vp68LeTbP0gmQYYUANq6vYctKHt6O8KAzvBmjQG94LDfewwuftGUD60Vx+gbSfhiCP4AMRhEbdimcGD5O0zqjqbAvCEUCJ9k+0AkYbAP4ysMuAqA9ASMJr4TAtY9fSAIABQCMAejw8FtET0Iw5AOw3BS41uGpaHQdp0/g3kA4zIJ0iMJiBaDWOBcdLsoysGcRkAFg+kiP24paMA2OjINikxDYz8EyaDRRkcAX4SVhSy/GSqv27xg4WUm/bVGRVQi79Osq7A/sXR2EKMBQG1c/sZUhjX9QqiVVrOlXfj31Tme5D/pTWAjgdh2qORIRjA5hFIsKGwUUWQ1aCDtkEMoJACOnnjeNUW+nGqIuSsYAC1CQAymlAOdS6hEAOo/6rhmRg5JERpwmQW/UTguUMADOajtqkN5spcooYCjMUS/wocW+mKKLjFxNQscKwB3cgXuUoEGdichEWgY6KCpWVpakIyjJVEoA3B02FcC8F5AvQE8SCjtPVOPno4d02+4HKUPQPAG/DmBAkLpBJCJywxCxmVAMZTWyHsRchTtMdGcQuAgDm+ERLgnSC7Qv1ZBsDD+jSB9R+M2UmVVAOhyIHvRUuvETQTOJ3zyC7B02XLhRgK4HY3BALGsRumhJlgSavg2rl2Hq6bB/QTXMIVNkiGYBoh0hZVvUMj6NCWeCJVoQhXtbIUnWmJc+iKDtb9DPy3pTkSSO5HPVxhMoKYbqSd4u95hkAT3osJIZiiiAAfWcuWG0Yzp8RmpbYUSOP4gSMG8/A4ZAAMB59supo7cIUW9KWjrRI43DGXxmBWibR0DEerrE5CSIMALwuvhxQ0ZslcRGErYdP2ba511KBE6KkY2jZt5Y2NIyUhvzeQpsTsabLtkyKVLZtV2oZI6DsIkbpl8q+5N8naBtp0o9BPbdsdONc6Sj/QlbcDv7mKBiFZ83on8owQOzU8i00dI6uZC6pjUsh6VR2mc3vLCdmI3Ac0iVSOrPYkewUmId7TIkSgp4a7P0L+konYs6W3sA+hqj9RH5ZAIDCdEYAOI4skpi44iKu0HaaQiepAGOv6H4zsMexJUspC1ickqcSAyjaRGAD2Td1CqXfFoEsyTHsdVU7BLAaMEGpKdxBoUhemCPihBU+2S0JLulTb5/5KMkY77NGLVD7AbA+QLoGbAACawCR0MaFSnpTQ0DYF6NuCXDTVZqw1MOqNSaShc8o/2LAhvFGoDSfodSKjr82nqoBlplYL1KtJY63TjQQVQyq7HukLsppxHBYoBA6DehcOWABwXwFyi1ITsjsaGOpAlrAzRgvI0dkZBpCJlkhfAI6aeBOlnoWOMIt6mFDIHlxlpq0taUfADhRiBy4wRXrMFl7vTVpuoEoAAHENE2YPAF22KlBiBxxY87JMRE64zUq09fjDaSIAaAbye4WSN2nCDkAH4dUo+JdKwTdoOpwnBgXuKs441G4QVdLheLbEiichXArsWd2i6/9IY8XRLsTm0GjTvMy41zllxy6St8uzg1oAT2PE1d/BZ4wIQ1yKnNcXREydrnUAPhddG2zGAOH6kVBhFcxWRdcgaEf6HTBZM1YWfIQprIFwigXZsv5UukU4JUdIawSxmunft9SZBMkBSETjId/sGiK9G1NaCtUF68olqGjPuDqw1ulGcPt3C1TtJtJRYBwL0G1Yh0DQwCM2EqLNLDs/2TMbSVdAKl7kSaEPWAjuhaYQzpsykS9s2Nc5sAXw0dLsIew6BjVgEwPRPKDyK7dsNc1kV9rhALgTcsEF6fSYLEMk6TDyLWHGUnNBbfD3Bng6Oslw3GStnojQXyf5AhF7kShhgv+LLWbyM9IKrUV8arX4bIlNaerb8Tzx6H3xzegUcikLxF7i8rAXQFmfkDl4K8leKvLgEJO15ZV+hY82yY03WHoTpAmEoigJKGH+04qIkjiib2QWwKlkI8htq/0GHxkmFpAPMnb1kQO8oJMwmCfVLgk+94JSw/hcJNWGoTXWHJTYcGyn4aTmF0ZZwkHy8SMBQ+bclchHyCrhIicF3D0mZ1/RYi1kBgF5Brm2Q4A9kEkulP8jwpAozGYKG5JChUDQpHkcKQwNYopjqAxeYnMXi0WJC0AxeJEJXD4sRRQAAA7N8E+CfBrICQX4AAFYBA4IFJTEoYACB3gAgKEAwHeDvAYlGSvJQwE+AxK0A3wFJQABYEg7wKEDEqhAcpnkGySACkoAAM7wapQIF+CfBfgDAcEEUihDtKEg4IAQO0u+AxLPgtAGJaMveC/B3gySlJe8FoDtL2l2SqEAsqiXWLPgAgBIHsrBBoBPgNS94CQESXfA9l4INAGgC+ApKEgZSlZWsqODrLqlnwG5TCBaUQBIAfwPZX0oYDfBql7wK5VcqmUJBoQvwcEAwFoDghZlKS5ZSQHBAJBql7S34J0uRXVLtlrS9pbQG+BNKfg0IQFQkChBKjaADAGpQIH+UJAYlAgGJSkvKXghVlDAdpdUv+XtKYlmKr5Qkp6V3LfgtAXJb8HGUjLXl7wFJVcuqDEq0AoqmJe0vBDvAJlKS65YMo+XworFrSmJdUpSUkBaVX4b4AwBiWFKoQ4IfpQkHaWbK0lCy40DiuqXUrSVAq95e0o5VQABALKqlW8tSVXLnV5S/pWgFGVKBqVMS9VZ8BICLKslaAVJXcvaWfAolqqr5f4twCBLtqwSgJqErF5bIfFQAA= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=y-scope/yscope-log-viewer&utm_content=316):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

Copy link
Member

@junhaoliao junhaoliao left a comment

Choose a reason for hiding this comment

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

for the PR title, how about:

refactor: Move logEventNum update handling from AppController to viewStore.

@Henry8192 Henry8192 changed the title feat(url): refactor updateLogEventNum refactor: Move logEventNum update handling from AppController to viewStore. Jun 14, 2025
@Henry8192 Henry8192 requested a review from junhaoliao June 18, 2025 15:54
@Henry8192 Henry8192 marked this pull request as ready for review June 18, 2025 15:58
@Henry8192 Henry8192 requested a review from a team as a code owner June 18, 2025 15:58
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🔭 Outside diff range comments (1)
src/stores/viewStore/createViewUtilitySlice.ts (1)

113-129: Avoid hard-crashing on “reload” pre-conditions

Throwing an Error here will bubble up past the store call-site and blank the React tree. Prefer returning early with a warning, or surface the issue via the notification store for a controlled UX.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 159ca16 and 7911caf.

📒 Files selected for processing (7)
  • src/components/AppController.tsx (2 hunks)
  • src/components/CentralContainer/Sidebar/SidebarTabs/SearchTabPanel/Result.tsx (1 hunks)
  • src/components/Editor/index.tsx (1 hunks)
  • src/stores/viewStore/createViewUpdateSlice.ts (1 hunks)
  • src/stores/viewStore/createViewUtilitySlice.ts (4 hunks)
  • src/stores/viewStore/index.ts (1 hunks)
  • src/stores/viewStore/types.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}`: - Prefer `false == ` rather than `!`.

**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}: - Prefer false == <expression> rather than !<expression>.

  • src/components/CentralContainer/Sidebar/SidebarTabs/SearchTabPanel/Result.tsx
  • src/stores/viewStore/index.ts
  • src/components/Editor/index.tsx
  • src/stores/viewStore/types.ts
  • src/components/AppController.tsx
  • src/stores/viewStore/createViewUtilitySlice.ts
  • src/stores/viewStore/createViewUpdateSlice.ts
🧠 Learnings (1)
📓 Common learnings
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.
🔇 Additional comments (2)
src/components/AppController.tsx (2)

26-33: Potential hash-change feedback loop

updateLogEventNum triggers its own updateWindowUrlHashParams. When invoked from a hashchange listener this could rewrite the hash again, causing an extra (though usually identical) hashchange event on some browsers. Consider short-circuiting in updateLogEventNum when the incoming value already matches the hash.


70-73: Double processing of view parameters

handleHashChange calls updateViewHashParams() which in turn calls updateLogEventNum, leading again to the feedback loop risk noted above. Confirm no infinite recursion occurs when the store writes back an unchanged hash.

Comment on lines 264 to 267
updateWindowUrlHashParams({logEventNum: newLogEventNum});
const {setLogEventNum} = useViewStore.getState();
setLogEventNum(newLogEventNum);
const {updateLogEventNum} = useViewStore.getState();
updateLogEventNum(newLogEventNum);
}, []);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Same redundancy as in Result.tsx

handleCursorExplicitPosChange updates the hash, then hands the same value to updateLogEventNum, which updates it again. This can bloat the browser history and cause an extra render.

Apply the same one-liner fix as suggested for Result.tsx.

🤖 Prompt for AI Agents
In src/components/Editor/index.tsx around lines 264 to 267, the function updates
the URL hash and then redundantly updates the same value in the state, causing
extra renders and bloating browser history. Refactor the code to update the
state first and then update the URL hash in a single step or combine the updates
into one call to avoid duplication and unnecessary renders, following the
one-liner fix applied in Result.tsx.

Comment on lines 163 to 166
const newLogEventNum = pageData.logEventNum;
updateWindowUrlHashParams({logEventNum: newLogEventNum});
const {updateLogEventNum} = get();
updateLogEventNum(newLogEventNum);
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Drop the second updateLogEventNum call

updatePageData already updates the URL hash; calling updateLogEventNum immediately afterwards sets the same state again and triggers another hash update, generating an extra render and history entry.

🤖 Prompt for AI Agents
In src/stores/viewStore/createViewUpdateSlice.ts around lines 163 to 166, remove
the second call to updateLogEventNum(newLogEventNum) because updatePageData
already updates the URL hash and state. This redundant call causes an extra
render and history entry. Keep only the updateWindowUrlHashParams call and the
initial assignment to newLogEventNum.

Comment on lines 131 to 134
const clampedLogEventNum = clamp(newLogEventNum, 1, numEvents);
const {beginLineNumToLogEventNum} = get();
const logEventNumsOnPage: number [] = Array.from(beginLineNumToLogEventNum.values());
set({logEventNum: clampedLogEventNum});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure logEventNumsOnPage is ordered before bounds checks

Array.from(beginLineNumToLogEventNum.values()) relies on insertion order. If the map is ever populated out of order, isWithinBounds and nearest-element lookup will misbehave.

-const logEventNumsOnPage: number [] = Array.from(beginLineNumToLogEventNum.values());
+const logEventNumsOnPage = [...beginLineNumToLogEventNum.values()].sort((a, b) => a - b);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const clampedLogEventNum = clamp(newLogEventNum, 1, numEvents);
const {beginLineNumToLogEventNum} = get();
const logEventNumsOnPage: number [] = Array.from(beginLineNumToLogEventNum.values());
set({logEventNum: clampedLogEventNum});
const clampedLogEventNum = clamp(newLogEventNum, 1, numEvents);
const {beginLineNumToLogEventNum} = get();
- const logEventNumsOnPage: number [] = Array.from(beginLineNumToLogEventNum.values());
+ const logEventNumsOnPage = [...beginLineNumToLogEventNum.values()].sort((a, b) => a - b);
set({logEventNum: clampedLogEventNum});
🤖 Prompt for AI Agents
In src/stores/viewStore/createViewUpdateSlice.ts around lines 131 to 134, the
array logEventNumsOnPage is created from a Map's values without sorting, which
can cause incorrect behavior if the Map is populated out of order. To fix this,
sort the logEventNumsOnPage array numerically after creating it from the Map
values to ensure it is always ordered before any bounds checks or
nearest-element lookups.

Copy link
Member

@junhaoliao junhaoliao left a comment

Choose a reason for hiding this comment

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

  1. For the PR title, how about:

    refactor: Move logEventNum update handling from AppController to viewStore; Split viewStore into slices.
    
  2. setNumPages / setPageNum / setBeginLineNumToLogEventNum are never used, right? Can we remove them?

  3. Following (2.), I believe setLogData should be removed as well, since logData can be set by updatePageData. We do use setLogData in loadFile to initialize logData, but I think it's better we also initialize other states, so it happens that we can just use updatePageData.

  4. I think we discussed that we want to create slices based on features in the very initial Zustand refactoring PR. can we slice the store this way instead:
    createViewPageSlice

    State:

    • pageNum
    • numPages
    • logData
    • beginLineNumToLogEventNum

    Actions:

    • loadPageByAction
    • updatePageData

    createViewEventSlice

    State:

    • logEventNum

    Actions:

    • updateLogEventNum

    createViewFormattingSlice

    State:

    • isPrettified

    Actions:

    • updateIsPrettified

    createViewFilterSlice

    State:

    • (none)

    Actions:

    • filterLogs

@Henry8192 Henry8192 changed the title refactor: Move logEventNum update handling from AppController to viewStore. refactor: Move logEventNum update handling from AppController to viewStore; Split viewStore into slices. Jun 19, 2025
Henry8192 and others added 2 commits June 19, 2025 15:50
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7911caf and 5084b21.

📒 Files selected for processing (7)
  • src/stores/logFileStore.ts (0 hunks)
  • src/stores/viewStore/createViewEventSlice.ts (1 hunks)
  • src/stores/viewStore/createViewFilterSlice.ts (1 hunks)
  • src/stores/viewStore/createViewFormattingSlice.ts (1 hunks)
  • src/stores/viewStore/createViewPageSlice.ts (1 hunks)
  • src/stores/viewStore/index.ts (1 hunks)
  • src/stores/viewStore/types.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/stores/logFileStore.ts
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}`: - Prefer `false == ` rather than `!`.

**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}: - Prefer false == <expression> rather than !<expression>.

  • src/stores/viewStore/index.ts
  • src/stores/viewStore/createViewFormattingSlice.ts
  • src/stores/viewStore/types.ts
  • src/stores/viewStore/createViewPageSlice.ts
  • src/stores/viewStore/createViewFilterSlice.ts
  • src/stores/viewStore/createViewEventSlice.ts
🔇 Additional comments (11)
src/stores/viewStore/index.ts (1)

10-15: LGTM: Clean store composition pattern

The store composition using Zustand slices follows a clear and maintainable pattern. The slice combination is straightforward and the type system ensures compile-time safety.

src/stores/viewStore/createViewFormattingSlice.ts (1)

34-38: LGTM: Efficient early return optimization

Good optimization to avoid unnecessary work when the prettification state hasn't actually changed.

src/stores/viewStore/createViewFilterSlice.ts (1)

26-49: LGTM: Well-structured async filtering operation

The filtering logic properly coordinates UI state, async operations, and error handling. The sequence of setting loading state, filtering logs, updating page data, and restarting queries is correct.

src/stores/viewStore/types.ts (2)

1-6: LGTM: Clean import structure without file extensions

The imports correctly omit TypeScript file extensions, maintaining tool-agnostic compatibility. The past review concern about .ts extensions appears to have been addressed.


27-44: Method naming is now more consistent

The action methods now consistently use descriptive prefixes that better reflect their behaviour: updateLogEventNum, updateIsPrettified, updatePageData for state changes with side effects, and loadPageByAction, filterLogs for specific operations. This addresses the past review concern about naming consistency.

src/stores/viewStore/createViewPageSlice.ts (3)

37-75: LGTM: Robust navigation cursor logic

The getPageNumCursor function properly handles all navigation actions with appropriate page clamping and event positioning. The switch statement covers all cases and returns null for unknown actions, providing good error handling.


110-126: LGTM: Comprehensive RELOAD validation logic

The RELOAD action handling includes proper validation of file source and log event number states, with descriptive error messages for debugging.


128-134: Good UI state validation prevents concurrent operations

Proper check for UI_STATE.READY prevents navigation during ongoing operations, with helpful console warning for debugging.

src/stores/viewStore/createViewEventSlice.ts (3)

37-37: LGTM! Coding guideline compliance.

Good adherence to the coding guideline by using false === isWithinBounds(...) instead of !isWithinBounds(...).


80-80: LGTM! Coding guideline compliance.

Good adherence to the coding guideline by using 0 === numEvents instead of !numEvents.


52-54: Excellent type safety documentation.

The detailed comments explaining why the type casting is safe are exemplary. This makes the code much more maintainable and demonstrates thorough understanding of the logic constraints.

Comment on lines +54 to +61
(async () => {
const {logFileManagerProxy} = useLogFileManagerStore.getState();
const pageData = await logFileManagerProxy.loadPage(cursor, newIsPrettified);

const {updatePageData} = get();
updatePageData(pageData);
})().catch(handleErrorWithNotification);
},
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Consider adding race condition protection

The async operation could potentially race with other state updates or be called multiple times rapidly. Consider adding a loading flag or debouncing mechanism to prevent concurrent executions.

 updateIsPrettified: (newIsPrettified: boolean) => {
     const {isPrettified} = get();
     if (newIsPrettified === isPrettified) {
         return;
     }
+
+    // Prevent concurrent updates
+    const currentState = get();
+    if (currentState.isUpdatingPrettification) {
+        return;
+    }
+    set({isUpdatingPrettification: true});

     const {setUiState} = useUiStore.getState();
     setUiState(UI_STATE.FAST_LOADING);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/stores/viewStore/createViewFormattingSlice.ts around lines 54 to 61, the
async function that loads page data can be triggered multiple times rapidly,
causing race conditions. To fix this, add a loading flag in the state to track
if the operation is in progress and prevent re-entry until it completes, or
implement a debounce mechanism to limit how often the function can be called.
Update the state accordingly before and after the async call to ensure only one
execution runs at a time.

Comment on lines +29 to +48
(async () => {
const {logFileManagerProxy} = useLogFileManagerStore.getState();
const {isPrettified, logEventNum} = get();
const pageData = await logFileManagerProxy.setFilter(
{
code: CURSOR_CODE.EVENT_NUM,
args: {
eventNum: logEventNum,
},
},
isPrettified,
filter
);

const {updatePageData} = get();
updatePageData(pageData);

const {startQuery} = useQueryStore.getState();
startQuery();
})().catch(handleErrorWithNotification);
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Consider adding concurrent operation protection

Similar to the formatting slice, this async operation could benefit from protection against concurrent executions to prevent race conditions.

🤖 Prompt for AI Agents
In src/stores/viewStore/createViewFilterSlice.ts around lines 29 to 48, the
async IIFE performing filter setting and page data updating lacks protection
against concurrent executions, risking race conditions. Introduce a concurrency
control mechanism such as a flag or a mutex to ensure only one instance of this
async operation runs at a time, preventing overlapping executions and
inconsistent state updates.

@Henry8192 Henry8192 requested a review from junhaoliao June 19, 2025 20:15
@Henry8192
Copy link
Contributor Author

  1. Following (2.), I believe setLogData should be removed as well, since logData can be set by updatePageData. We do use setLogData in loadFile to initialize logData, but I think it's better we also initialize other states, so it happens that we can just use updatePageData.

Do you think setFileName also applies to this?

Copy link
Member

@junhaoliao junhaoliao left a comment

Choose a reason for hiding this comment

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

all good except some nits

Co-authored-by: Junhao Liao <junhao@junhao.ca>
@Henry8192 Henry8192 requested a review from junhaoliao June 23, 2025 18:06
@junhaoliao
Copy link
Member

  1. Following (2.), I believe setLogData should be removed as well, since logData can be set by updatePageData. We do use setLogData in loadFile to initialize logData, but I think it's better we also initialize other states, so it happens that we can just use updatePageData.

Do you think setFileName also applies to this?

ah, setFileName is in the file store which is out of scope of this view store refactoring PR. that said, i do agree a similar refactoring can be done in the file store, in a separate PR if possible

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
src/stores/viewStore/index.ts (1)

10-15: Guard against key collisions when merging slices

Spreading multiple slice objects means duplicate keys are silently overwritten. Consider asserting uniqueness during dev builds (e.g., compare Object.keys) or giving each slice its own namespace.

src/stores/viewStore/createViewEventSlice.ts (2)

84-91: Consider performance optimization for frequent calls.

Creating a new array from beginLineNumToLogEventNum.values() on every call could be inefficient if updateLogEventNum is called frequently during user interactions. Consider caching or memoizing the array creation, or modify updateUrlIfEventOnPage to accept the Map directly.


94-107: Ensure UI state is reset on page loading failure.

The async page loading logic is well-structured, but if page loading fails, the UI state might remain in FAST_LOADING state since handleErrorWithNotification only handles error notification. Consider wrapping the async logic in try-catch-finally to properly reset the UI state in all cases.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92bf12c and 0d96f19.

📒 Files selected for processing (2)
  • src/stores/viewStore/createViewEventSlice.ts (1 hunks)
  • src/stores/viewStore/index.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}`: - Prefer `false == ` rather than `!`.

**/*.{cpp,hpp,java,js,jsx,tpp,ts,tsx}: - Prefer false == <expression> rather than !<expression>.

  • src/stores/viewStore/index.ts
  • src/stores/viewStore/createViewEventSlice.ts
🔇 Additional comments (1)
src/stores/viewStore/createViewEventSlice.ts (1)

33-61: LGTM! Proper use of boolean comparison and comprehensive bounds checking.

The helper function correctly uses false === isWithinBounds() following the coding guidelines and handles edge cases well with detailed comments explaining the safety of type casting.

Copy link
Member

@junhaoliao junhaoliao left a comment

Choose a reason for hiding this comment

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

sorry for missing a few things in the last review

@Henry8192 Henry8192 requested a review from junhaoliao June 23, 2025 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants