Skip to content

feat: Replace existing webui codebase with new-webui.#939

Merged
junhaoliao merged 42 commits into
y-scope:mainfrom
junhaoliao:replace-webui
Jun 28, 2025
Merged

feat: Replace existing webui codebase with new-webui.#939
junhaoliao merged 42 commits into
y-scope:mainfrom
junhaoliao:replace-webui

Conversation

@junhaoliao

@junhaoliao junhaoliao commented May 28, 2025

Copy link
Copy Markdown
Member

Description

  1. Remove existing webui codebase.
  2. Rename all references to log-viewer-webui as webui.
  3. Update package scripts to write all required settings for the webui.
  4. Update taskfiles.

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.

(docs to be updated in a separate PR)

Validation performed

  1. Verified that package building succeeded: task.
  2. Verified that linting passed on non-cpp components: task lint:check-no-cpp

Summary by CodeRabbit

  • New Features
    • Unified the web UI and log viewer into a single, consolidated component with a modern React client and Fastify server architecture.
  • Refactor
    • Removed all Meteor.js dependencies and legacy code, transitioning to a standalone client-server structure.
    • Updated configuration, build, and task files to reflect the new architecture and simplify development workflows.
    • Consolidated configuration settings and validation for client and server components.
    • Streamlined database and search job management by removing deprecated modules and classes.
  • Bug Fixes
    • Improved configuration validation for client and server settings.
  • Documentation
    • Updated and streamlined setup and usage instructions to match the new architecture.
    • Removed outdated documentation and references to legacy components.
  • Chores
    • Cleaned up obsolete files, tests, and styles related to the old implementation.
    • Simplified and reorganized npm scripts and package configurations.

@coderabbitai

coderabbitai Bot commented May 28, 2025

Copy link
Copy Markdown
Contributor
## Walkthrough

This change removes the separate log-viewer-webui component and merges its functionality into a unified webui component. All code, configuration, and documentation related to the Meteor-based log-viewer-webui are deleted. The build, validation, and startup logic are refactored to support the consolidated webui, now structured as a React client and a Fastify server.

## Changes

| Files/Paths (grouped)                                                                                          | Change Summary |
|----------------------------------------------------------------------------------------------------------------|---------------|
| `components/log-viewer-webui/**`, `components/webui/imports/**`, `components/webui/client/main.*`, `components/webui/client/package.json`, `components/webui/client/public/settings.json`, `components/webui/client/src/*`, `components/webui/server/**`, `components/webui/settings.json`, `components/webui/launcher.js`, `components/webui/tests/**` | Deleted all Meteor-based log-viewer-webui and webui code, React components, server code, config, and tests. |
| `components/clp-py-utils/clp_py_utils/clp_config.py`, `components/clp-package-utils/clp_package_utils/general.py`, `components/clp-package-utils/clp_package_utils/scripts/start_clp.py`, `components/clp-package-utils/clp_package_utils/scripts/stop_clp.py`, `components/clp-py-utils/clp_py_utils/s3_utils.py` | Removed log-viewer-webui references, consolidated config/validation/start logic for unified webui. |
| `components/package-template/src/etc/clp-config.yml`                                                           | Updated config template: removed log_viewer_webui block, added results_metadata_collection_name. |
| `components/webui/.gitignore`, `components/webui/client/package.json`, `components/webui/server/package.json`  | Updated ignore rules and package metadata for unified webui; renamed packages. |
| `components/webui/README.md`, `docs/src/dev-guide/components-webui.md`                                         | Updated documentation for new unified webui architecture, removed Meteor references. |
| `docs/src/dev-guide/components-log-viewer-webui.md`, `docs/src/dev-guide/index.md`                             | Removed documentation for the old log-viewer-webui component. |
| `taskfile.yaml`, `taskfiles/lint.yaml`, `taskfiles/deps/main.yaml`                                             | Refactored build, clean, and lint tasks to remove log-viewer-webui and support unified webui. |
| `components/webui/client/src/App.tsx`, `components/webui/client/src/main.tsx`, `components/webui/client/vite.config.ts` | Renamed and simplified App component; removed conditional logic for log-viewer-webui. |
| `components/webui/client/public/settings.json`, `components/webui/server/settings.json`                        | Reordered JSON keys for clarity. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant WebUI Client (React)
    participant WebUI Server (Fastify)
    participant CLP Core

    User->>WebUI Client (React): Initiate action (e.g., search, ingest)
    WebUI Client (React)->>WebUI Server (Fastify): API request (search, ingest, etc.)
    WebUI Server (Fastify)->>CLP Core: Query/command (if needed)
    CLP Core-->>WebUI Server (Fastify): Response/data
    WebUI Server (Fastify)-->>WebUI Client (React): API response
    WebUI Client (React)-->>User: Render results/UI update

Possibly related PRs

  • y-scope/clp#913: Replaces Meteor search methods with Fastify routes, directly related to the search API backend refactor in this PR.
  • y-scope/clp#596: Introduces new job types and methods for log viewer web UI, related as this PR removes that component entirely.
  • y-scope/clp#830: Adds UI cards in log-viewer-webui client code, which is removed and merged in this PR.

Suggested reviewers

  • haiqi96
  • kirkrodrigues

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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AR6iPXwBnSAkguLdEA4ozhQMNGJHb9F0E0RvEl7A541w+OjpVQz/7oCn/65vZ0bVISwbgOEzBUYMLkukHdIt4tzxRwMTBOZuxIbwkhqVALTAkYAzBDAHVHgYOoBj8BvAVoFbhaAHfBCyW9ADAHVGibgIBp5LEAibmgBp5LNHdmZz6SADcySAIldIoFUBp5LMA0APMAF5CHz5gPMAGAIsAibtPIYhONsUYB9BjoJFBmgs0FW4LQA7o/MBaAJFBErocV5gHdHW4Ild01PtGiboldp5OQrp5LQAGAIr80AETdHoz9AroxABIANPIwY/9HmgnPIGAATcQY7EB01BtHFo7EBmgmgB01E9ACbiHzOfQyd5gLEBErptHZgIlcCbgKsoY1AA55GDHaABmoGAPEAibpFAmY2gA8YyUAGAAIBErkTdZgPEBXo49HmYy9Ga6LMBmgnTHeo1NHrowIBIoLEA55ETcSAIxCBAPEBaALMBgY60ECbrMABAOmpZgNPI55AIAIY/syjo8TGibprGBAATdIoGLG6o4cQSSLMA55MjHuY5moW4HTHErgzHTY7EA5o5FAdEAIBmgvMBzozjGkrltG0AOVcqY8dBp5JFB1o8zGCboxC7wMjH9o2THJY80EibrEBHo/dH01N8zmggwA/Y7EBibkMgg4/MBErq0FErrNHNY67HhYyUBIoHtHE42VcBACXHno3QAcY80E5Y/XHzgJTHGYOLHoYwwAyrtzHDYy3B7o3szmglXH5gGgASAETcjY4lcA45nHnowIAbYwTdXY8THvmebHroySRIoCHGGAETcGAGjHZgBzHYY7VaUY4tGtY0TcLAtPHZY99GAY+vG55PPHoY4idaAJz60AN9H447QACbkrGtY07H7o3QASSIxCXowtGYhPXGiY2jH2gkHGvmRtGy498zIoATdErtLGcYzog55ETHb40lcSY9PIH42gAdY6jGooOmo7o+fGoAAIAFo5FASAAjHNoxkBfmW9GU45nH/o9jH01CQnZo+dGSAKAm55C3A55MKB0EzPiyY0PHYgKoAqgIldGIdgnErgPHE4+moZ6QTcdo1jG5Y0vG04wDGy4wwm3owwAuY7QByFcLGbmWQnaAArH24/LH01AvISACnHZY6zG844PGe43/GW463GoAANGs0MmBho6TFRo+LBLIvoAgAA== -->

<!-- internal state 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/clp&utm_content=939):

- 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 -->

@davemarco

Copy link
Copy Markdown
Contributor

as discussed in meeting. I will make changes but I need someone (@haiqi96 , @kirkrodrigues , other?) to review original PR which replaces webui. Once everything else is done it can be merged

junhaoliao and others added 9 commits June 12, 2025 15:05
# Conflicts:
#	components/log-viewer-webui/client/package-lock.json
#	components/log-viewer-webui/client/src/AntdApp.tsx
#	components/log-viewer-webui/client/src/pages/SearchPage/SearchResults/SearchResultsTimeline.tsx
# Conflicts:
#	components/log-viewer-webui/client/package-lock.json
@junhaoliao junhaoliao changed the title WIP - feat: Replace existing webui codebase with new-webui. feat: Replace existing webui codebase with new-webui. Jun 16, 2025
@junhaoliao junhaoliao marked this pull request as ready for review June 16, 2025 21:54
@junhaoliao junhaoliao requested a review from a team as a code owner June 16, 2025 21:54

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🔭 Outside diff range comments (4)
components/clp-py-utils/clp_py_utils/s3_utils.py (2)

104-108: Docstring still references removed component

The docstring mentions log_viewer, which no longer exists after the merge. Update for clarity and future maintainability.

-    :param component_type: Type of calling container (compression, log_viewer, or query).
+    :param component_type: Calling component name
+        (compression-scheduler/worker, webui, query-scheduler/worker).

112-120: Edge case: tuple check hides accidental plural

Using the singleton tuple (WEBUI_COMPONENT_NAME,) is correct; however, if someone later appends another element without the trailing comma, the comparison will silently break. Consider converting to a set for safer membership tests:

-    elif component_type in (WEBUI_COMPONENT_NAME,):
+    elif component_type in {WEBUI_COMPONENT_NAME}:
components/clp-py-utils/clp_py_utils/clp_config.py (1)

571-590: New field validated correctly – just one minor style tweak

Logic is fine and the validator signature matches pydantic’s expectations (Pylint’s E0213 is a false positive).
For readability, wrap the long error message at 100 chars to satisfy the project formatter.

-            raise ValueError(f"{WEBUI_COMPONENT_NAME}.results_metadata_collection_name cannot be empty.")
+            raise ValueError(
+                f"{WEBUI_COMPONENT_NAME}.results_metadata_collection_name cannot be empty."
+            )
components/clp-package-utils/clp_package_utils/scripts/start_clp.py (1)

842-968: Consider refactoring to reduce function complexity.

The function has 28 local variables (recommended maximum is 15) and 55 statements (recommended maximum is 50). Consider extracting the settings update logic into separate helper functions to improve readability and maintainability.

For example, you could extract:

  • Client settings update logic into _update_client_settings()
  • Server settings update logic into _update_server_settings()
  • S3 configuration logic into _configure_s3_settings()

Would you like me to generate the refactored code or open an issue to track this improvement?

♻️ Duplicate comments (1)
taskfiles/lint.yaml (1)

760-765: Same undefined variable used in js task

cd "{{.G_WEBUI_SRC_DIR}}" will fail for the same reason. Once the variable is re-established (see previous comment), this line becomes safe.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 948d6a6 and 7b2f7a2.

⛔ Files ignored due to path filters (7)
  • components/log-viewer-webui/package-lock.json is excluded by !**/package-lock.json
  • components/webui/client/package-lock.json is excluded by !**/package-lock.json
  • components/webui/client/public/clp-logo.png is excluded by !**/*.png
  • components/webui/client/public/favicon.svg is excluded by !**/*.svg
  • components/webui/linter/package-lock.json is excluded by !**/package-lock.json
  • components/webui/package-lock.json is excluded by !**/package-lock.json
  • components/webui/server/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (100)
  • components/clp-package-utils/clp_package_utils/general.py (1 hunks)
  • components/clp-package-utils/clp_package_utils/scripts/start_clp.py (6 hunks)
  • components/clp-package-utils/clp_package_utils/scripts/stop_clp.py (0 hunks)
  • components/clp-py-utils/clp_py_utils/clp_config.py (2 hunks)
  • components/clp-py-utils/clp_py_utils/s3_utils.py (2 hunks)
  • components/log-viewer-webui/.gitignore (0 hunks)
  • components/log-viewer-webui/README.md (0 hunks)
  • components/log-viewer-webui/client/src/AntdApp.tsx (0 hunks)
  • components/log-viewer-webui/client/src/App.tsx (0 hunks)
  • components/log-viewer-webui/package.json (0 hunks)
  • components/package-template/src/etc/clp-config.yml (1 hunks)
  • components/webui/.gitignore (1 hunks)
  • components/webui/.meteor/.finished-upgraders (0 hunks)
  • components/webui/.meteor/.gitignore (0 hunks)
  • components/webui/.meteor/.id (0 hunks)
  • components/webui/.meteor/packages (0 hunks)
  • components/webui/.meteor/platforms (0 hunks)
  • components/webui/.meteor/release (0 hunks)
  • components/webui/.meteor/versions (0 hunks)
  • components/webui/.meteorignore (0 hunks)
  • components/webui/README.md (1 hunks)
  • components/webui/client/main.css (0 hunks)
  • components/webui/client/main.html (0 hunks)
  • components/webui/client/main.jsx (0 hunks)
  • components/webui/client/package.json (1 hunks)
  • components/webui/client/public/settings.json (1 hunks)
  • components/webui/client/src/App.tsx (1 hunks)
  • components/webui/client/src/main.tsx (1 hunks)
  • components/webui/client/vite.config.ts (1 hunks)
  • components/webui/imports/api/constants.js (0 hunks)
  • components/webui/imports/api/ingestion/collections.js (0 hunks)
  • components/webui/imports/api/ingestion/constants.js (0 hunks)
  • components/webui/imports/api/ingestion/server/CompressionDbManager.js (0 hunks)
  • components/webui/imports/api/ingestion/server/StatsDbManager.js (0 hunks)
  • components/webui/imports/api/ingestion/server/publications.js (0 hunks)
  • components/webui/imports/api/ingestion/types.js (0 hunks)
  • components/webui/imports/api/search/SearchJobCollectionsManager.js (0 hunks)
  • components/webui/imports/api/search/collections.js (0 hunks)
  • components/webui/imports/api/search/constants.js (0 hunks)
  • components/webui/imports/api/search/server/QueryJobsDbManager.js (0 hunks)
  • components/webui/imports/api/search/server/collections.js (0 hunks)
  • components/webui/imports/api/search/server/methods.js (0 hunks)
  • components/webui/imports/api/search/server/publications.js (0 hunks)
  • components/webui/imports/api/search/types.js (0 hunks)
  • components/webui/imports/ui/App.jsx (0 hunks)
  • components/webui/imports/ui/App.scss (0 hunks)
  • components/webui/imports/ui/IngestView/IngestView.jsx (0 hunks)
  • components/webui/imports/ui/IngestView/IngestView.scss (0 hunks)
  • components/webui/imports/ui/IngestView/Panel.jsx (0 hunks)
  • components/webui/imports/ui/IngestView/panels/Details/DetailsRow.jsx (0 hunks)
  • components/webui/imports/ui/IngestView/panels/Details/index.jsx (0 hunks)
  • components/webui/imports/ui/IngestView/panels/IngestionJobs/IngestionJobRow.jsx (0 hunks)
  • components/webui/imports/ui/IngestView/panels/IngestionJobs/IngestionJobs.scss (0 hunks)
  • components/webui/imports/ui/IngestView/panels/IngestionJobs/PlaceholderText.jsx (0 hunks)
  • components/webui/imports/ui/IngestView/panels/IngestionJobs/PlaceholderText.scss (0 hunks)
  • components/webui/imports/ui/IngestView/panels/IngestionJobs/index.jsx (0 hunks)
  • components/webui/imports/ui/IngestView/panels/SpaceSavings.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsCaseSensitivity/SearchControlsCaseSensitivityCheck.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsCaseSensitivity/index.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsFilterDrawer.scss (0 hunks)
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsFilterLabel.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsTimeRangeInput/SearchControlsDatePicker.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsTimeRangeInput/SearchControlsTimeRangeInput.scss (0 hunks)
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsTimeRangeInput/index.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/index.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchControls/index.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsHeader/SearchResultsHeader.scss (0 hunks)
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsHeader/index.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsLoadSensor.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsLoadSensor.scss (0 hunks)
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss (0 hunks)
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTimeline/SearchResultsTimeline.scss (0 hunks)
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTimeline/index.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchResults/index.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchStatus.jsx (0 hunks)
  • components/webui/imports/ui/SearchView/SearchStatus.scss (0 hunks)
  • components/webui/imports/ui/SearchView/SearchView.jsx (0 hunks)
  • components/webui/imports/ui/Sidebar/Sidebar.jsx (0 hunks)
  • components/webui/imports/ui/Sidebar/Sidebar.scss (0 hunks)
  • components/webui/imports/ui/Sidebar/SidebarButton.jsx (0 hunks)
  • components/webui/imports/ui/bootstrap-customized.scss (0 hunks)
  • components/webui/imports/ui/constants.js (0 hunks)
  • components/webui/imports/utils/DbManager.js (0 hunks)
  • components/webui/imports/utils/datetime.js (0 hunks)
  • components/webui/imports/utils/logger.js (0 hunks)
  • components/webui/imports/utils/misc.js (0 hunks)
  • components/webui/imports/utils/mongo.js (0 hunks)
  • components/webui/launcher.js (0 hunks)
  • components/webui/linter/package.json (0 hunks)
  • components/webui/package.json (1 hunks)
  • components/webui/server/main.js (0 hunks)
  • components/webui/server/package.json (1 hunks)
  • components/webui/server/settings.json (1 hunks)
  • components/webui/settings.json (0 hunks)
  • components/webui/tests/main.js (0 hunks)
  • components/webui/tests/misc.js (0 hunks)
  • taskfile.yaml (8 hunks)
  • taskfiles/deps/main.yaml (1 hunks)
  • taskfiles/lint.yaml (2 hunks)
💤 Files with no reviewable changes (82)
  • components/webui/.meteor/release
  • components/webui/.meteor/.id
  • components/webui/.meteorignore
  • components/webui/.meteor/platforms
  • components/webui/imports/ui/IngestView/panels/IngestionJobs/PlaceholderText.scss
  • components/log-viewer-webui/README.md
  • components/webui/client/main.css
  • components/webui/.meteor/.gitignore
  • components/clp-package-utils/clp_package_utils/scripts/stop_clp.py
  • components/webui/imports/ui/App.scss
  • components/log-viewer-webui/.gitignore
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsHeader/SearchResultsHeader.scss
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsTimeRangeInput/SearchControlsTimeRangeInput.scss
  • components/webui/imports/ui/IngestView/panels/IngestionJobs/IngestionJobs.scss
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTimeline/SearchResultsTimeline.scss
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsLoadSensor.scss
  • components/webui/.meteor/.finished-upgraders
  • components/webui/imports/api/search/server/collections.js
  • components/webui/imports/ui/IngestView/IngestView.jsx
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsCaseSensitivity/SearchControlsCaseSensitivityCheck.jsx
  • components/log-viewer-webui/package.json
  • components/webui/imports/api/constants.js
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsFilterDrawer.scss
  • components/webui/client/main.html
  • components/webui/tests/main.js
  • components/log-viewer-webui/client/src/App.tsx
  • components/webui/imports/api/ingestion/types.js
  • components/webui/client/main.jsx
  • components/webui/.meteor/versions
  • components/webui/imports/ui/SearchView/SearchStatus.scss
  • components/webui/imports/ui/Sidebar/Sidebar.scss
  • components/webui/tests/misc.js
  • components/webui/imports/utils/mongo.js
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsFilterLabel.jsx
  • components/webui/imports/api/search/collections.js
  • components/webui/linter/package.json
  • components/webui/imports/ui/IngestView/panels/IngestionJobs/index.jsx
  • components/webui/imports/ui/IngestView/panels/Details/DetailsRow.jsx
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsCaseSensitivity/index.jsx
  • components/webui/imports/api/search/types.js
  • components/webui/imports/ui/IngestView/panels/Details/index.jsx
  • components/webui/imports/utils/DbManager.js
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsTimeRangeInput/SearchControlsDatePicker.jsx
  • components/webui/imports/ui/IngestView/panels/SpaceSavings.jsx
  • components/webui/imports/ui/constants.js
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsTable.scss
  • components/webui/imports/ui/IngestView/panels/IngestionJobs/PlaceholderText.jsx
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/index.jsx
  • components/webui/imports/api/ingestion/collections.js
  • components/webui/imports/ui/SearchView/SearchStatus.jsx
  • components/webui/imports/ui/Sidebar/Sidebar.jsx
  • components/webui/imports/api/ingestion/constants.js
  • components/webui/imports/ui/IngestView/IngestView.scss
  • components/webui/imports/ui/IngestView/panels/IngestionJobs/IngestionJobRow.jsx
  • components/webui/launcher.js
  • components/webui/imports/ui/Sidebar/SidebarButton.jsx
  • components/webui/imports/api/ingestion/server/CompressionDbManager.js
  • components/webui/imports/ui/App.jsx
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/SearchResultsLoadSensor.jsx
  • components/webui/imports/utils/misc.js
  • components/webui/server/main.js
  • components/webui/imports/ui/IngestView/Panel.jsx
  • components/webui/imports/api/ingestion/server/StatsDbManager.js
  • components/webui/imports/utils/logger.js
  • components/webui/imports/api/search/server/QueryJobsDbManager.js
  • components/webui/imports/ui/SearchView/SearchResults/index.jsx
  • components/webui/imports/api/search/server/publications.js
  • components/webui/imports/ui/SearchView/SearchView.jsx
  • components/log-viewer-webui/client/src/AntdApp.tsx
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTimeline/index.jsx
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsHeader/index.jsx
  • components/webui/imports/ui/SearchView/SearchResults/SearchResultsTable/index.jsx
  • components/webui/.meteor/packages
  • components/webui/imports/ui/bootstrap-customized.scss
  • components/webui/imports/ui/SearchView/SearchControls/SearchControlsFilterDrawer/SearchControlsTimeRangeInput/index.jsx
  • components/webui/imports/utils/datetime.js
  • components/webui/imports/api/search/server/methods.js
  • components/webui/imports/api/ingestion/server/publications.js
  • components/webui/settings.json
  • components/webui/imports/api/search/constants.js
  • components/webui/imports/api/search/SearchJobCollectionsManager.js
  • components/webui/imports/ui/SearchView/SearchControls/index.jsx
🧰 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>.

  • components/webui/client/vite.config.ts
  • components/webui/client/src/main.tsx
  • components/webui/client/src/App.tsx
🧬 Code Graph Analysis (2)
components/clp-package-utils/clp_package_utils/general.py (1)
components/clp-py-utils/clp_py_utils/clp_config.py (1)
  • CLPConfig (593-778)
components/clp-package-utils/clp_package_utils/scripts/start_clp.py (2)
components/clp-py-utils/clp_py_utils/clp_config.py (1)
  • CLPConfig (593-778)
components/clp-package-utils/clp_package_utils/general.py (3)
  • CLPDockerMounts (80-90)
  • get_clp_home (93-109)
  • validate_webui_config (512-519)
🪛 Pylint (3.3.7)
components/clp-package-utils/clp_package_utils/general.py

[convention] 512-512: Missing function or method docstring

(C0116)

components/clp-package-utils/clp_package_utils/scripts/start_clp.py

[convention] 869-869: Line too long (104/100)

(C0301)


[convention] 885-885: Line too long (104/100)

(C0301)


[convention] 842-842: Missing function or method docstring

(C0116)


[refactor] 842-842: Too many local variables (28/15)

(R0914)


[warning] 849-849: Use lazy % formatting in logging functions

(W1203)


[warning] 874-874: Using open without explicitly specifying an encoding

(W1514)


[refactor] 842-842: Too many statements (55/50)

(R0915)


[warning] 916-916: Using open without explicitly specifying an encoding

(W1514)

components/clp-py-utils/clp_py_utils/clp_config.py

[convention] 589-589: Line too long (105/100)

(C0301)


[convention] 587-587: Missing function or method docstring

(C0116)


[error] 587-587: Method 'validate_results_metadata_collection_name' should have "self" as first argument

(E0213)

⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: build-macos (macos-13, true)
  • GitHub Check: build-macos (macos-15, true)
  • GitHub Check: build-macos (macos-14, false)
  • GitHub Check: build-macos (macos-14, true)
  • GitHub Check: ubuntu-jammy-dynamic-linked-bins
  • GitHub Check: ubuntu-jammy-lint
  • GitHub Check: ubuntu-jammy-static-linked-bins
  • GitHub Check: centos-stream-9-static-linked-bins
  • GitHub Check: centos-stream-9-dynamic-linked-bins
  • GitHub Check: lint-check (macos-latest)
🔇 Additional comments (17)
components/webui/.gitignore (1)

1-1: Add a header to group dependency rules
The # Dependencies comment improves readability by clearly separating dependency patterns from other ignores.

components/webui/server/settings.json (1)

11-11: Reordering JSON keys is cosmetic.
Moving "MongoDbStreamFilesCollectionName" below "MongoDbSearchResultsMetadataCollectionName" does not change any values or runtime behaviour.

components/webui/server/package.json (1)

2-2: Package name updated to unified component.
Renaming "name" to "webui-server" aligns with the consolidated WebUI architecture. Ensure there are no leftover references to the old package name by running:

#!/bin/bash
# Search for legacy package name
rg -l '"log-viewer-webui-server"'
components/webui/client/vite.config.ts (1)

27-27: Updated comment path for .env location.
The comment now correctly points to components/webui/server/.env, matching the refactored server layout.

components/webui/client/public/settings.json (1)

2-3: Key order swap is non-functional.
Reordering "ClpStorageEngine" and "MongoDbSearchResultsMetadataCollectionName" has no impact on the JSON semantics or application behaviour.

components/webui/client/package.json (2)

10-10: Simplified start script.
Removing the "antd" script streamlines the workflow. Confirm that all development and build tasks still succeed with npm start.


2-2: Client package name updated.
Changing "name" to "webui-client" matches the merged WebUI structure. Verify no stale references to the old name remain:

#!/bin/bash
# Search for legacy client package name
rg -l '"log-viewer-webui-client"'
taskfiles/deps/main.yaml (1)

52-55: Confirm new variable .G_WEBUI_SRC_DIR exists in all include chains

OUTPUT_DIR now relies on .G_WEBUI_SRC_DIR, but this variable is not declared in the local vars: block. Please verify it’s exported by one of the included taskfiles (utils.yaml, yscope-dev-utils/.../utils.yaml) or the global environment; otherwise this task will fail at runtime when yscope-dev-utils:remote:download-and-extract-tar tries to resolve the path.
If it’s missing, add it alongside the other directory vars.

components/webui/client/src/main.tsx (1)

16-19: Simplified entry point looks correct

Removing the VITE_USE_ANTD_APP branch reduces complexity and the remaining JSX is straightforward. No concerns.

components/package-template/src/etc/clp-config.yml (1)

61-65: Double-check downstream support for result_metadata_collection_name

result_metadata_collection_name is now the only tunable under webui.
Ensure the server code that consumes this value (e.g., results-metadata DAO, validation layer) reads the key from the new location; otherwise custom configs will be silently ignored.

components/webui/client/src/App.tsx (1)

1-6: RouterProvider import appears to target the wrong package

RouterProvider is exported by react-router-dom; importing from react-router will break at runtime once the bundle is loaded.

-import {RouterProvider} from "react-router";
+import {RouterProvider} from "react-router-dom";

Please adjust before shipping.

⛔ Skipped due to learnings
Learnt from: davemarco
PR: y-scope/clp#797
File: components/log-viewer-webui/client/src/routes/routes.tsx:1-1
Timestamp: 2025-04-04T15:15:59.432Z
Learning: In React Router v7, `createBrowserRouter` and other router primitives should be imported from `react-router` package, not from `react-router-dom` as in previous versions. This represents a significant change in the library's structure where router primitives are now in the core package.
Learnt from: davemarco
PR: y-scope/clp#797
File: components/log-viewer-webui/client/src/components/Layout/MainLayout.tsx:2-5
Timestamp: 2025-04-08T22:32:05.366Z
Learning: In this codebase using React Router v7.4.1, components should be imported directly from "react-router" (e.g., `import { Link, Outlet } from "react-router";`) rather than from "react-router-dom" as was common in previous versions of React Router.
components/webui/package.json (1)

3-16: npm clean-install may not be available on older npm versions

npm clean-install is an alias introduced in newer npm releases. If the CI or downstream users run an older npm (≤ 8.5), these scripts will fail. Consider switching to the widely-supported npm ci.

-    "init": "npm clean-install && (cd client && npm clean-install) && (cd server && npm clean-install)",
+    "init": "npm ci && (cd client && npm ci) && (cd server && npm ci)",
taskfile.yaml (5)

39-44: Good approach to separate checksum files.

The separation of checksum files for different node_modules directories (client, log-viewer, package, server) provides better dependency tracking and allows for more granular rebuilds. This is a clean architectural improvement.


84-90: Comprehensive cleanup task.

The clean-webui task properly removes all node_modules directories from the consolidated webui structure. This ensures a clean state for rebuilds.


157-158: Correct use of npm clean-install for production.

Using npm clean-install in the production package build ensures reproducible builds by installing from package-lock.json. The path correctly points to the consolidated webui server directory.


261-302: Well-structured webui build process.

The consolidated webui build task properly handles all three components:

  • Client build with Vite
  • Server TypeScript compilation with package files
  • Log-viewer build

The use of PATH override ensures consistent Node.js version usage across all build steps.


350-356: Excellent documentation of the node_modules structure.

The comment clearly explains why there are four different node_modules directories, which helps future maintainers understand the architecture. This is a great practice.

Comment thread components/webui/.gitignore Outdated
Comment thread components/webui/README.md Outdated
Comment thread components/webui/README.md Outdated
Comment thread components/webui/client/src/App.tsx Outdated
Comment on lines 512 to 518
def validate_webui_config(clp_config: CLPConfig,
client_settings_json_path: pathlib.Path,
server_settings_json_path: pathlib.Path):
for path in [client_settings_json_path, server_settings_json_path]:
if not path.exists():
raise ValueError(f"{WEBUI_COMPONENT_NAME} {path} is not a valid path to settings.json")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Strengthen validation & add minimal docstring

  1. The helper does not verify that the paths point to files named settings.json; it only checks existence.
  2. It silently accepts directories.
  3. A short docstring would suppress Pylint C0116.
 def validate_webui_config(clp_config: CLPConfig,
                           client_settings_json_path: pathlib.Path,
                           server_settings_json_path: pathlib.Path):
-    for path in [client_settings_json_path, server_settings_json_path]:
-        if not path.exists():
-            raise ValueError(f"{WEBUI_COMPONENT_NAME} {path} is not a valid path to settings.json")
+    """
+    Validate WebUI port and that both settings.json files exist and are regular files.
+    """
+    for path in (client_settings_json_path, server_settings_json_path):
+        if not path.is_file() or path.name != "settings.json":
+            raise ValueError(
+                f"{WEBUI_COMPONENT_NAME}: '{path}' must be an existing settings.json file"
+            )
📝 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
def validate_webui_config(clp_config: CLPConfig,
client_settings_json_path: pathlib.Path,
server_settings_json_path: pathlib.Path):
for path in [client_settings_json_path, server_settings_json_path]:
if not path.exists():
raise ValueError(f"{WEBUI_COMPONENT_NAME} {path} is not a valid path to settings.json")
def validate_webui_config(clp_config: CLPConfig,
client_settings_json_path: pathlib.Path,
server_settings_json_path: pathlib.Path):
"""
Validate WebUI port and that both settings.json files exist and are regular files.
"""
for path in (client_settings_json_path, server_settings_json_path):
if not path.is_file() or path.name != "settings.json":
raise ValueError(
f"{WEBUI_COMPONENT_NAME}: '{path}' must be an existing settings.json file"
)
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 512-512: Missing function or method docstring

(C0116)

🤖 Prompt for AI Agents
In components/clp-package-utils/clp_package_utils/general.py around lines 512 to
518, the validate_webui_config function only checks if the paths exist but does
not verify that they point to files named settings.json and allows directories.
Add a docstring briefly describing the function's purpose. Then, enhance the
validation by checking that each path is a file and that its name is exactly
settings.json, raising a ValueError if these conditions are not met.

Comment thread taskfiles/lint.yaml
Comment on lines +60 to 63
- "{{.G_WEBUI_SRC_DIR}}/**/*"
- exclude: "{{.G_WEBUI_SRC_DIR}}/**/dist/*"
- "{{.ROOT_DIR}}/taskfile.yaml"
- "{{.TASKFILE}}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

G_WEBUI_SRC_DIR is referenced but no longer defined

The variable was deleted from the vars: block in this Taskfile yet is still used here. Task invocation will abort with “undefined variable” errors.

Update the variable reference or add a replacement definition (G_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/webui").

🤖 Prompt for AI Agents
In taskfiles/lint.yaml around lines 60 to 63, the variable G_WEBUI_SRC_DIR is
used but no longer defined, causing undefined variable errors. To fix this,
either add a definition for G_WEBUI_SRC_DIR in the vars: block, for example
setting it to "{{.ROOT_DIR}}/components/webui", or update the references here to
use an existing defined variable that points to the correct directory.

# Read, update, and write back client's and server's settings.json
client_settings_json_updates = {
"ClpStorageEngine": clp_config.package.storage_engine,
"MongoDbSearchResultsMetadataCollectionName": clp_config.webui.results_metadata_collection_name,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Fix line length violations.

Lines 869 and 885 exceed the 100-character limit. Consider breaking them into multiple lines for better readability.

-        "MongoDbSearchResultsMetadataCollectionName": clp_config.webui.results_metadata_collection_name,
+        "MongoDbSearchResultsMetadataCollectionName": (
+            clp_config.webui.results_metadata_collection_name
+        ),
-        "MongoDbSearchResultsMetadataCollectionName": clp_config.webui.results_metadata_collection_name,
+        "MongoDbSearchResultsMetadataCollectionName": (
+            clp_config.webui.results_metadata_collection_name
+        ),

Also applies to: 885-885

🧰 Tools
🪛 Pylint (3.3.7)

[convention] 869-869: Line too long (104/100)

(C0301)

🤖 Prompt for AI Agents
In components/clp-package-utils/clp_package_utils/scripts/start_clp.py at lines
869 and 885, the lines exceed the 100-character limit. To fix this, break these
long lines into multiple shorter lines by splitting after commas or operators,
aligning the continued lines properly for readability and adhering to the line
length limit.

Comment on lines +874 to +875
with open(client_settings_json_path, "w") as client_settings_json_file:
client_settings_json_file.write(json.dumps(client_settings_json))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Specify encoding when opening files.

When opening files for reading or writing, it's best practice to explicitly specify the encoding to avoid potential issues with non-ASCII characters.

-    with open(client_settings_json_path, "w") as client_settings_json_file:
-        client_settings_json_file.write(json.dumps(client_settings_json))
+    with open(client_settings_json_path, "w", encoding="utf-8") as client_settings_json_file:
+        client_settings_json_file.write(json.dumps(client_settings_json))
-    with open(server_settings_json_path, "w") as settings_json_file:
-        settings_json_file.write(json.dumps(server_settings_json))
+    with open(server_settings_json_path, "w", encoding="utf-8") as settings_json_file:
+        settings_json_file.write(json.dumps(server_settings_json))

Also applies to: 916-917

🧰 Tools
🪛 Pylint (3.3.7)

[warning] 874-874: Using open without explicitly specifying an encoding

(W1514)

🤖 Prompt for AI Agents
In components/clp-package-utils/clp_package_utils/scripts/start_clp.py at lines
874-875 and also at lines 916-917, the open() calls for writing files do not
specify the encoding, which can cause issues with non-ASCII characters. Fix this
by adding the encoding="utf-8" parameter to the open() function calls to
explicitly set the file encoding when opening files for writing.



def start_log_viewer_webui(
def start_webui(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Add a docstring to document the function.

The function is missing documentation. Consider adding a docstring that describes the purpose, parameters, and any exceptions that might be raised.

 def start_webui(
     instance_id: str,
     clp_config: CLPConfig,
     container_clp_config: CLPConfig,
     mounts: CLPDockerMounts,
 ):
+    """
+    Starts the web UI component with both client and server configurations.
+    
+    :param instance_id: Unique identifier for this CLP instance.
+    :param clp_config: Host CLP configuration.
+    :param container_clp_config: Container-specific CLP configuration.
+    :param mounts: Docker mount configurations.
+    :raises ValueError: If settings JSON files are invalid.
+    """
     component_name = WEBUI_COMPONENT_NAME
📝 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
def start_webui(
def start_webui(
instance_id: str,
clp_config: CLPConfig,
container_clp_config: CLPConfig,
mounts: CLPDockerMounts,
):
"""
Starts the web UI component with both client and server configurations.
:param instance_id: Unique identifier for this CLP instance.
:param clp_config: Host CLP configuration.
:param container_clp_config: Container-specific CLP configuration.
:param mounts: Docker mount configurations.
:raises ValueError: If settings JSON files are invalid.
"""
component_name = WEBUI_COMPONENT_NAME
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 842-842: Missing function or method docstring

(C0116)


[refactor] 842-842: Too many local variables (28/15)

(R0914)


[refactor] 842-842: Too many statements (55/50)

(R0915)

🤖 Prompt for AI Agents
In components/clp-package-utils/clp_package_utils/scripts/start_clp.py at line
842, the function start_webui lacks a docstring. Add a clear docstring
immediately below the function definition that explains the function's purpose,
describes its parameters, and notes any exceptions it may raise to improve code
readability and maintainability.

Comment thread taskfile.yaml
Comment on lines +404 to 425
- task: "clean-webui"
- "PATH='{{.G_NODEJS_22_BIN_DIR}}':$PATH npm run init"
- |-
cd yscope-log-viewer
PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm install
PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm clean-install
# These commands must be last
- task: "utils:checksum:compute"
vars:
CHECKSUM_FILE: "{{.CLIENT_CHECKSUM_FILE}}"
CHECKSUM_FILE: "{{.G_WEBUI_CLIENT_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.CLIENT_OUTPUT_DIR}}"]
- task: "utils:checksum:compute"
vars:
CHECKSUM_FILE: "{{.LOG_VIEWER_CHECKSUM_FILE}}"
CHECKSUM_FILE: "{{.G_WEBUI_LOG_VIEWER_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.LOG_VIEWER_OUTPUT_DIR}}"]
- task: "utils:checksum:compute"
vars:
CHECKSUM_FILE: "{{.PACKAGE_CHECKSUM_FILE}}"
CHECKSUM_FILE: "{{.G_WEBUI_PACKAGE_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.PACKAGE_OUTPUT_DIR}}"]
- task: "utils:checksum:compute"
vars:
CHECKSUM_FILE: "{{.SERVER_CHECKSUM_FILE}}"
CHECKSUM_FILE: "{{.G_WEBUI_SERVER_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.SERVER_OUTPUT_DIR}}"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Consider using parallel checksum computation.

The checksum computation commands are executed sequentially. Since they operate on independent directories, you could potentially speed up the build by computing them in parallel.

However, the current sequential approach is perfectly fine and may be easier to debug if issues arise.

🤖 Prompt for AI Agents
In taskfile.yaml around lines 404 to 425, the checksum computation tasks are run
sequentially, which can be slow. To improve build speed, refactor these tasks to
run in parallel since they operate on independent directories. You can achieve
this by defining a single task that triggers all checksum computations
concurrently or by using a parallel execution feature if supported by the task
runner. Ensure that the parallel execution does not affect dependencies or order
of other tasks.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 f655fad and 2a74251.

📒 Files selected for processing (3)
  • docs/src/dev-guide/components-log-viewer-webui.md (0 hunks)
  • docs/src/dev-guide/components-webui.md (1 hunks)
  • docs/src/dev-guide/index.md (0 hunks)
💤 Files with no reviewable changes (2)
  • docs/src/dev-guide/index.md
  • docs/src/dev-guide/components-log-viewer-webui.md
🧰 Additional context used
🪛 LanguageTool
docs/src/dev-guide/components-webui.md

[grammar] ~52-~52: The word ‘lint’ is a noun or an adjective. A verb or adverb is missing or misspelled here, or maybe a comma is missing.
Context: ...gs in .env. ## Linting You can lint this component either as part of the en...

(PRP_MD_NN)

🪛 markdownlint-cli2 (0.17.2)
docs/src/dev-guide/components-webui.md

27-27: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


47-47: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


66-66: Link and image reference definitions should be needed
Unused link or image reference definition: "eslint"

(MD053, link-image-reference-definitions)


70-70: Files should end with a single newline character
null

(MD047, single-trailing-newline)

⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: ubuntu-jammy-static-linked-bins
  • GitHub Check: centos-stream-9-dynamic-linked-bins
  • GitHub Check: centos-stream-9-static-linked-bins
  • GitHub Check: ubuntu-jammy-dynamic-linked-bins
  • GitHub Check: ubuntu-jammy-lint
  • GitHub Check: build-macos (macos-14, false)
  • GitHub Check: build-macos (macos-14, true)
  • GitHub Check: lint-check (macos-latest)
🔇 Additional comments (10)
docs/src/dev-guide/components-webui.md (10)

3-4: Approve updated component description.
The removal of Meteor.js and the clarification that the WebUI uses a React client and Fastify server (while still serving the log-viewer) is accurate and aligns with the new architecture.


8-8: Node.js requirement bump is correct.
Updating the requirement to Node.js v22+ matches the removal of Meteor.js and is consistent with the PR objectives.


11-11: Setup section header is clear.
The new “## Setup” heading correctly introduces the installation steps.


13-17: Step 1 instructions for log-viewer dependency remain valid.
Running task deps:log-viewer to fetch the log-viewer source is still required before installing dependencies.


30-30: Running section header is correct.
“## Running” appropriately introduces the development run steps.


32-37: Client development instructions are accurate.
The commands to start the React client under components/webui/client match the new layout.


39-44: Server development instructions are accurate.
The Fastify server startup under components/webui/server is correctly documented.


50-50: Linting section header is clear.
“## Linting” succinctly introduces the linting instructions.


54-58: Lint check commands are correct.
The task lint:check-js invocation is consistent with the updated task definitions.


60-64: Lint fix commands are correct.
The task lint:fix-js command properly covers the auto-fix step.

Comment thread docs/src/dev-guide/components-webui.md Outdated
Comment thread docs/src/dev-guide/components-webui.md

@kirkrodrigues kirkrodrigues left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Some comments about the docs.

Comment thread docs/src/dev-guide/components-webui.md Outdated
Comment thread docs/src/dev-guide/components-webui.md Outdated
Comment thread docs/src/dev-guide/components-webui.md Outdated
Comment thread docs/src/dev-guide/components-webui.md Outdated
Comment on lines +66 to +70
[eslint]: https://eslint.org/
[nvm]: https://github.com/nvm-sh/nvm
[Fastify]: https://www.fastify.io/
[log-viewer]: https://github.com/y-scope/yscope-log-viewer
[React]: https://reactjs.org/ No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Alphabetize

Comment thread docs/src/dev-guide/components-webui.md Outdated
Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
docs/src/dev-guide/components-webui.md (1)

70-70: Ensure single trailing newline
Please confirm the file ends with exactly one newline to satisfy MD047.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2a74251 and 1a7d10c.

📒 Files selected for processing (1)
  • docs/src/dev-guide/components-webui.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/src/dev-guide/components-webui.md

[grammar] ~52-~52: The word ‘lint’ is a noun or an adjective. A verb or adverb is missing or misspelled here, or maybe a comma is missing.
Context: ...gs in .env. ## Linting You can lint this component either as part of the en...

(PRP_MD_NN)

🪛 markdownlint-cli2 (0.17.2)
docs/src/dev-guide/components-webui.md

27-27: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


47-47: Trailing spaces
Expected: 0 or 2; Actual: 1

(MD009, no-trailing-spaces)


66-66: Link and image reference definitions should be needed
Unused link or image reference definition: "eslint"

(MD053, link-image-reference-definitions)


70-70: Files should end with a single newline character
null

(MD047, single-trailing-newline)

🔇 Additional comments (10)
docs/src/dev-guide/components-webui.md (10)

3-4: Component description aligns with new architecture
The intro correctly reflects the unified WebUI with a React client and Fastify server, replacing Meteor.


8-8: Node.js version requirement is clear
Specifying "Node.js v22 or higher" matches the updated tech stack.


11-11: The "## Setup" header is unchanged in meaning and appears correctly.


13-17: Step 1 instructions are accurate
The task command to fetch the log-viewer source is clear and uses the updated task deps:log-viewer.


19-25: Step 2 dependency install path is correct
The path has been updated from log-viewer-webui to components/webui and splits client/server installs.


34-37: Client run command is properly scoped
The development start instructions for components/webui/client are clear.


42-43: Server run command is properly scoped
The development start instructions for components/webui/server match expectations.


57-58: Lint check command is correct
task lint:check-js is the proper command for JS lint validation.


63-64: Lint fix command is correct
task lint:fix-js properly triggers auto-fixable lint corrections.


68-70: Link definitions are consistent with references
All three definitions (Fastify, log-viewer, React) are used in the text and valid.

Comment thread docs/src/dev-guide/components-webui.md Outdated
## Linting

To integrate ESLint into IDEs like WebStorm and VSCode, follow these steps:
You can lint this component either as part of the entire project.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Improve grammar in linting description
Remove "either" to correct "You can lint this component as part of the entire project."

🧰 Tools
🪛 LanguageTool

[grammar] ~52-~52: The word ‘lint’ is a noun or an adjective. A verb or adverb is missing or misspelled here, or maybe a comma is missing.
Context: ...gs in .env. ## Linting You can lint this component either as part of the en...

(PRP_MD_NN)

🤖 Prompt for AI Agents
In docs/src/dev-guide/components-webui.md at line 52, the sentence "You can lint
this component either as part of the entire project." contains a grammatical
error due to the unnecessary use of "either." Remove the word "either" so the
sentence reads "You can lint this component as part of the entire project."

Comment thread docs/src/dev-guide/components-webui.md
junhaoliao and others added 3 commits June 19, 2025 19:14
…view

Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com>
Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com>
Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a6e46a6 and b7a6e51.

📒 Files selected for processing (1)
  • components/webui/client/index.html (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: gibber9809
PR: y-scope/clp#504
File: components/core/src/clp_s/search/kql/CMakeLists.txt:29-29
Timestamp: 2024-10-22T15:36:04.655Z
Learning: When reviewing pull requests, focus on the changes within the PR and avoid commenting on issues outside the scope of the PR.
Learnt from: junhaoliao
PR: y-scope/clp#596
File: components/log-viewer-webui/client/src/api/query.js:16-23
Timestamp: 2024-11-21T15:51:33.203Z
Learning: In `components/log-viewer-webui/client/src/api/query.js`, the `ExtractJsonResp` type definition is accurate as-is and does not require modification. When suggesting changes to type definitions, ensure they align with the server-side definitions, referencing the source code if necessary.
Learnt from: haiqi96
PR: y-scope/clp#523
File: components/core/src/clp/clp/FileCompressor.hpp:58-78
Timestamp: 2024-10-24T14:25:17.978Z
Learning: When reviewing legacy code refactors, avoid suggesting changes that would extend the scope of the PR.
Learnt from: junhaoliao
PR: y-scope/clp#939
File: components/package-template/src/etc/clp-config.yml:64-64
Timestamp: 2025-06-22T04:01:43.409Z
Learning: The new webui architecture uses Fastify with Pino logging instead of the previous Winston-based logging system that was removed during the webui refactoring.
Learnt from: junhaoliao
PR: y-scope/clp#937
File: components/log-viewer-webui/client/src/AntdApp.tsx:16-24
Timestamp: 2025-05-29T20:33:40.653Z
Learning: In components/log-viewer-webui React codebase: Return type annotations (like `: JSX.Element`) are unnecessary and not preferred for React components in JSX/TSX files.
Learnt from: davemarco
PR: y-scope/clp#1015
File: components/log-viewer-webui/server/src/routes/static.ts:65-70
Timestamp: 2025-06-16T13:05:27.349Z
Learning: In components/log-viewer-webui/server/src/routes/static.ts, when decorateReply is set to true in fastifyStatic configuration, the reply.sendFile() method automatically uses the root directory configured in the static plugin registration, eliminating the need to pass the root directory as a second parameter.
Learnt from: junhaoliao
PR: y-scope/clp#939
File: components/package-template/src/etc/clp-config.yml:64-64
Timestamp: 2025-06-22T04:01:43.409Z
Learning: The webui server logging can be configured via LOG_LEVEL and WEBUI_LOGS_DIR environment variables, with file logging enabled automatically in non-TTY environments when a logs directory is specified.
Learnt from: davemarco
PR: y-scope/clp#892
File: components/log-viewer-webui/client/src/api/socket/MongoCollectionSocket.ts:27-31
Timestamp: 2025-05-09T19:15:26.180Z
Learning: For the MongoDB real-time updates implementation in components/log-viewer-webui/client/src/api/socket, a socket singleton pattern is used where a single shared socket connection is maintained rather than creating multiple connections. The socket lifecycle is managed centrally, with unsubscription handling in the useCursor React hook's cleanup function.
Learnt from: junhaoliao
PR: y-scope/clp#596
File: components/log-viewer-webui/client/src/api/query.js:35-41
Timestamp: 2024-11-19T19:52:43.429Z
Learning: For internal APIs in `components/log-viewer-webui/client/src/api/query.js`, runtime validation of parameters may not be necessary since the APIs are not exposed to end users, and JsDoc type annotations may be sufficient.
components/webui/client/index.html (1)
Learnt from: junhaoliao
PR: y-scope/clp#596
File: components/log-viewer-webui/client/src/api/query.js:16-23
Timestamp: 2024-11-21T15:51:33.203Z
Learning: In `components/log-viewer-webui/client/src/api/query.js`, the `ExtractJsonResp` type definition is accurate as-is and does not require modification. When suggesting changes to type definitions, ensure they align with the server-side definitions, referencing the source code if necessary.
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: build-macos (macos-15, true)
  • GitHub Check: build-macos (macos-13, false)
  • GitHub Check: build-macos (macos-13, true)
  • GitHub Check: build-macos (macos-14, true)
  • GitHub Check: build-macos (macos-14, false)
  • GitHub Check: centos-stream-9-static-linked-bins
  • GitHub Check: ubuntu-jammy-static-linked-bins
  • GitHub Check: ubuntu-jammy-lint
  • GitHub Check: ubuntu-jammy-dynamic-linked-bins
  • GitHub Check: centos-stream-9-dynamic-linked-bins

Comment on lines 4 to 8
<title>Log Viewer Web UI</title>
<meta charset="utf-8"/>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="description" content="YScope Log Viewer Web UI">
<meta name="description" content="YScope CLP">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Title remains outdated – update for consistency with the new branding

The <title> tag (line 4) still reads “Log Viewer Web UI” while the neighbouring description meta (line 7) now says “YScope CLP”. Keeping two different product names in the page header is confusing for users and hurts SEO. Please align the title with the new branding, e.g.:

-    <title>Log Viewer Web UI</title>
+    <title>YScope CLP Web UI</title>
📝 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
<title>Log Viewer Web UI</title>
<meta charset="utf-8"/>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="description" content="YScope Log Viewer Web UI">
<meta name="description" content="YScope CLP">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>YScope CLP Web UI</title>
<meta charset="utf-8"/>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="description" content="YScope CLP">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
🤖 Prompt for AI Agents
In components/webui/client/index.html around lines 4 to 8, the <title> tag
currently reads "Log Viewer Web UI" which is inconsistent with the updated
branding "YScope CLP" used in the meta description. Update the <title> tag
content to "YScope CLP" to ensure consistent product naming and improve user
clarity and SEO.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
taskfile.yaml (3)

39-45: Checksum-file vars still repetitive

A prior review proposed grouping these four paths under a single map to remove duplication; that feedback hasn’t been applied.


84-90: Unconditional rm -rf negates node_modules caching

clean-webui still wipes every node_modules regardless of checksum validity, forcing re-installs even when nothing changed—exactly the issue flagged earlier.


273-274: Node-modules exclude pattern not fully recursive

Using **/node_modules/* excludes contents but not the directory itself; the empty dir’s mtime triggers rebuilds. The earlier suggestion to use **/node_modules/** remains unaddressed.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b7a6e51 and 1094e7f.

📒 Files selected for processing (1)
  • taskfile.yaml (7 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: gibber9809
PR: y-scope/clp#504
File: components/core/src/clp_s/search/kql/CMakeLists.txt:29-29
Timestamp: 2024-10-22T15:36:04.655Z
Learning: When reviewing pull requests, focus on the changes within the PR and avoid commenting on issues outside the scope of the PR.
Learnt from: junhaoliao
PR: y-scope/clp#596
File: components/log-viewer-webui/client/src/api/query.js:16-23
Timestamp: 2024-11-21T15:51:33.203Z
Learning: In `components/log-viewer-webui/client/src/api/query.js`, the `ExtractJsonResp` type definition is accurate as-is and does not require modification. When suggesting changes to type definitions, ensure they align with the server-side definitions, referencing the source code if necessary.
Learnt from: haiqi96
PR: y-scope/clp#523
File: components/core/src/clp/clp/FileCompressor.hpp:58-78
Timestamp: 2024-10-24T14:25:17.978Z
Learning: When reviewing legacy code refactors, avoid suggesting changes that would extend the scope of the PR.
Learnt from: junhaoliao
PR: y-scope/clp#939
File: components/package-template/src/etc/clp-config.yml:64-64
Timestamp: 2025-06-22T04:01:43.409Z
Learning: The new webui architecture uses Fastify with Pino logging instead of the previous Winston-based logging system that was removed during the webui refactoring.
Learnt from: junhaoliao
PR: y-scope/clp#937
File: components/log-viewer-webui/client/src/AntdApp.tsx:16-24
Timestamp: 2025-05-29T20:33:40.653Z
Learning: In components/log-viewer-webui React codebase: Return type annotations (like `: JSX.Element`) are unnecessary and not preferred for React components in JSX/TSX files.
Learnt from: davemarco
PR: y-scope/clp#1015
File: components/log-viewer-webui/server/src/routes/static.ts:65-70
Timestamp: 2025-06-16T13:05:27.349Z
Learning: In components/log-viewer-webui/server/src/routes/static.ts, when decorateReply is set to true in fastifyStatic configuration, the reply.sendFile() method automatically uses the root directory configured in the static plugin registration, eliminating the need to pass the root directory as a second parameter.
Learnt from: junhaoliao
PR: y-scope/clp#939
File: components/package-template/src/etc/clp-config.yml:64-64
Timestamp: 2025-06-22T04:01:43.409Z
Learning: The webui server logging can be configured via LOG_LEVEL and WEBUI_LOGS_DIR environment variables, with file logging enabled automatically in non-TTY environments when a logs directory is specified.
Learnt from: davemarco
PR: y-scope/clp#892
File: components/log-viewer-webui/client/src/api/socket/MongoCollectionSocket.ts:27-31
Timestamp: 2025-05-09T19:15:26.180Z
Learning: For the MongoDB real-time updates implementation in components/log-viewer-webui/client/src/api/socket, a socket singleton pattern is used where a single shared socket connection is maintained rather than creating multiple connections. The socket lifecycle is managed centrally, with unsubscription handling in the useCursor React hook's cleanup function.
Learnt from: junhaoliao
PR: y-scope/clp#596
File: components/log-viewer-webui/client/src/api/query.js:35-41
Timestamp: 2024-11-19T19:52:43.429Z
Learning: For internal APIs in `components/log-viewer-webui/client/src/api/query.js`, runtime validation of parameters may not be necessary since the APIs are not exposed to end users, and JsDoc type annotations may be sufficient.
taskfile.yaml (7)
Learnt from: junhaoliao
PR: y-scope/clp#939
File: components/package-template/src/etc/clp-config.yml:64-64
Timestamp: 2025-06-22T04:01:43.409Z
Learning: The new webui architecture uses Fastify with Pino logging instead of the previous Winston-based logging system that was removed during the webui refactoring.
Learnt from: junhaoliao
PR: y-scope/clp#939
File: components/package-template/src/etc/clp-config.yml:64-64
Timestamp: 2025-06-22T04:01:43.409Z
Learning: The webui server logging can be configured via LOG_LEVEL and WEBUI_LOGS_DIR environment variables, with file logging enabled automatically in non-TTY environments when a logs directory is specified.
Learnt from: kirkrodrigues
PR: y-scope/clp#881
File: components/core/tools/scripts/lib_install/macos/install-all.sh:15-23
Timestamp: 2025-05-06T09:46:42.639Z
Learning: For temporary solutions in installation scripts like those in `components/core/tools/scripts/lib_install/`, checksumming downloaded files is considered optional, particularly when working with trusted sources like GitHub raw content.
Learnt from: junhaoliao
PR: y-scope/clp#596
File: components/log-viewer-webui/client/src/api/query.js:16-23
Timestamp: 2024-11-21T15:51:33.203Z
Learning: In `components/log-viewer-webui/client/src/api/query.js`, the `ExtractJsonResp` type definition is accurate as-is and does not require modification. When suggesting changes to type definitions, ensure they align with the server-side definitions, referencing the source code if necessary.
Learnt from: haiqi96
PR: y-scope/clp#523
File: components/core/src/clp/clp/FileCompressor.hpp:58-78
Timestamp: 2024-10-24T14:25:17.978Z
Learning: When reviewing legacy code refactors, avoid suggesting changes that would extend the scope of the PR.
Learnt from: anlowee
PR: y-scope/clp#925
File: components/core/src/clp_s/search/sql/CMakeLists.txt:8-19
Timestamp: 2025-05-26T18:39:51.727Z
Learning: In CMakeLists.txt files, anlowee prefers to explicitly list source files one by one rather than using file(GLOB ...) or file(GLOB_RECURSE ...) to automatically include files, maintaining consistency with other CMake files in the project.
Learnt from: anlowee
PR: y-scope/clp#925
File: taskfiles/deps/main.yaml:97-106
Timestamp: 2025-05-28T18:33:30.155Z
Learning: In the taskfiles dependency system (taskfiles/deps/main.yaml), echo commands are used to generate .cmake settings files that are consumed by the main CMake build process. These files set variables like ANTLR_RUNTIME_HEADER to point to dependency locations for use during compilation.
⏰ Context from checks skipped due to timeout of 90000ms (10)
  • GitHub Check: centos-stream-9-dynamic-linked-bins
  • GitHub Check: centos-stream-9-static-linked-bins
  • GitHub Check: ubuntu-jammy-lint
  • GitHub Check: ubuntu-jammy-dynamic-linked-bins
  • GitHub Check: ubuntu-jammy-static-linked-bins
  • GitHub Check: build-macos (macos-13, false)
  • GitHub Check: build-macos (macos-14, true)
  • GitHub Check: build-macos (macos-14, false)
  • GitHub Check: build-macos (macos-13, true)
  • GitHub Check: lint-check (macos-latest)

Comment thread taskfile.yaml
Comment thread taskfile.yaml
Comment on lines +388 to +404
CHECKSUM_FILE: "{{.G_WEBUI_CLIENT_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.CLIENT_OUTPUT_DIR}}"]
EXCLUDE_PATTERNS:
- ".tmp"
- ".vite-temp"
- task: "utils:checksum:validate"
vars:
CHECKSUM_FILE: "{{.SERVER_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.SERVER_OUTPUT_DIR}}"]
CHECKSUM_FILE: "{{.G_WEBUI_LOG_VIEWER_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.LOG_VIEWER_OUTPUT_DIR}}"]
- task: "utils:checksum:validate"
vars:
CHECKSUM_FILE: "{{.PACKAGE_CHECKSUM_FILE}}"
CHECKSUM_FILE: "{{.G_WEBUI_PACKAGE_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.PACKAGE_OUTPUT_DIR}}"]
- task: "utils:checksum:validate"
vars:
CHECKSUM_FILE: "{{.LOG_VIEWER_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.LOG_VIEWER_OUTPUT_DIR}}"]
CHECKSUM_FILE: "{{.G_WEBUI_SERVER_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.SERVER_OUTPUT_DIR}}"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Inconsistent checksum validation allows cache thrash

Only the client directory ignores transient .tmp / .vite-temp files; the log-viewer, package, and server validations don’t, so ephemeral files break the cache.

@@
       - task: "utils:checksum:validate"
         vars:
           CHECKSUM_FILE: "{{.G_WEBUI_LOG_VIEWER_NODE_MODULES_CHECKSUM_FILE}}"
           INCLUDE_PATTERNS: ["{{.LOG_VIEWER_OUTPUT_DIR}}"]
+          EXCLUDE_PATTERNS:
+            - ".tmp"
+            - ".vite-temp"
@@
       - task: "utils:checksum:validate"
         vars:
           CHECKSUM_FILE: "{{.G_WEBUI_PACKAGE_NODE_MODULES_CHECKSUM_FILE}}"
           INCLUDE_PATTERNS: ["{{.PACKAGE_OUTPUT_DIR}}"]
+          EXCLUDE_PATTERNS:
+            - ".tmp"
+            - ".vite-temp"
@@
       - task: "utils:checksum:validate"
         vars:
           CHECKSUM_FILE: "{{.G_WEBUI_SERVER_NODE_MODULES_CHECKSUM_FILE}}"
           INCLUDE_PATTERNS: ["{{.SERVER_OUTPUT_DIR}}"]
+          EXCLUDE_PATTERNS:
+            - ".tmp"
+            - ".vite-temp"

Ensures all directories share identical ignore rules and stabilises caching.

📝 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
CHECKSUM_FILE: "{{.G_WEBUI_CLIENT_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.CLIENT_OUTPUT_DIR}}"]
EXCLUDE_PATTERNS:
- ".tmp"
- ".vite-temp"
- task: "utils:checksum:validate"
vars:
CHECKSUM_FILE: "{{.SERVER_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.SERVER_OUTPUT_DIR}}"]
CHECKSUM_FILE: "{{.G_WEBUI_LOG_VIEWER_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.LOG_VIEWER_OUTPUT_DIR}}"]
- task: "utils:checksum:validate"
vars:
CHECKSUM_FILE: "{{.PACKAGE_CHECKSUM_FILE}}"
CHECKSUM_FILE: "{{.G_WEBUI_PACKAGE_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.PACKAGE_OUTPUT_DIR}}"]
- task: "utils:checksum:validate"
vars:
CHECKSUM_FILE: "{{.LOG_VIEWER_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.LOG_VIEWER_OUTPUT_DIR}}"]
CHECKSUM_FILE: "{{.G_WEBUI_SERVER_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.SERVER_OUTPUT_DIR}}"]
- task: "utils:checksum:validate"
vars:
CHECKSUM_FILE: "{{.G_WEBUI_LOG_VIEWER_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.LOG_VIEWER_OUTPUT_DIR}}"]
EXCLUDE_PATTERNS:
- ".tmp"
- ".vite-temp"
- task: "utils:checksum:validate"
vars:
CHECKSUM_FILE: "{{.G_WEBUI_PACKAGE_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.PACKAGE_OUTPUT_DIR}}"]
EXCLUDE_PATTERNS:
- ".tmp"
- ".vite-temp"
- task: "utils:checksum:validate"
vars:
CHECKSUM_FILE: "{{.G_WEBUI_SERVER_NODE_MODULES_CHECKSUM_FILE}}"
INCLUDE_PATTERNS: ["{{.SERVER_OUTPUT_DIR}}"]
EXCLUDE_PATTERNS:
- ".tmp"
- ".vite-temp"
🤖 Prompt for AI Agents
In taskfile.yaml around lines 388 to 404, the checksum validation for the
log-viewer, package, and server tasks lacks the EXCLUDE_PATTERNS that ignore
transient files like ".tmp" and ".vite-temp" present in the client task. To fix
this, add the same EXCLUDE_PATTERNS list with ".tmp" and ".vite-temp" to each of
these tasks to ensure consistent ignore rules and prevent cache thrashing caused
by ephemeral files.

@junhaoliao junhaoliao requested a review from kirkrodrigues June 27, 2025 23:11
@junhaoliao junhaoliao merged commit bb8244c into y-scope:main Jun 28, 2025
22 checks passed
@junhaoliao junhaoliao deleted the replace-webui branch June 28, 2025 02:30
quinntaylormitchell pushed a commit to quinntaylormitchell/clp that referenced this pull request Jul 4, 2025
Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com>
junhaoliao added a commit to junhaoliao/clp that referenced this pull request May 17, 2026
Co-authored-by: kirkrodrigues <2454684+kirkrodrigues@users.noreply.github.com>
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.

3 participants