Skip to content

Staging#282

Merged
galshubeli merged 88 commits intomainfrom
staging
Dec 18, 2025
Merged

Staging#282
galshubeli merged 88 commits intomainfrom
staging

Conversation

@gkorland
Copy link
Copy Markdown
Contributor

@gkorland gkorland commented Oct 8, 2025

Summary by CodeRabbit

  • New Features

    • Ship a React + Vite SPA: chat interface (streaming queries), schema viewer, sidebar/header, auth flows, DB connect UI, token management, and many reusable UI components and services.
  • Bug Fixes / UX

    • Serve built SPA assets; add auth-status and logout endpoints; simplify DB error messages; auto-quote SQL identifiers to reduce query failures.
  • Chores

    • Migrate frontend to Vite/Tailwind; update CI workflows; remove legacy templates and legacy CSS.
  • Documentation

    • Update README and add SQL identifier quoting guide.
  • Style

    • ESLint: ignore unused names starting with "_".

✏️ Tip: You can customize this high-level summary in your review settings.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 8, 2025

Dependency Review Summary

The full dependency review summary is too large to display here. Please download the artifact named "dependency-review-summary" to view the complete report.

View full job summary

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 8, 2025

Walkthrough

Replace the legacy Jinja2 + vanilla TypeScript frontend with a React + Vite + Tailwind TypeScript app; remove legacy CSS, Jinja templates, and old TS modules; add React pages, components, contexts, hooks, services, E2E Playwright infra, and backend SQL identifier quoting utilities with tests and docs.

Changes

Cohort / File(s) Summary of Changes
Frontend build & config
app/package.json, app/vite.config.ts, app/tailwind.config.ts, app/postcss.config.js, app/components.json, app/eslint.config.cjs
Introduce Vite/React + Tailwind toolchain, set module type, update npm scripts, add plugins/dev deps, and adjust ESLint unused‑vars to ignore underscore-prefixed args/vars.
React app sources
app/src/main.tsx, app/src/App.tsx, app/src/pages/*, app/src/components/**/*, app/src/contexts/*, app/src/hooks/*, app/src/services/*, app/src/types/*, app/src/index.css, app/src/lib/utils.ts
Add full TypeScript React app: bootstrap, routing, providers (Auth/Database), UI primitives, components (Sidebar, Header, SchemaViewer, ChatInterface, modals), hooks (useIsMobile, use-toast), services (AuthService, ChatService, DatabaseService, TokenService), API config, types, Tailwind CSS and cn utility.
Remove legacy frontend assets & templates
app/public/css/*, app/templates/*.j2, app/templates/components/*, app/ts/*, app/ts/modules/*
Delete legacy CSS, Jinja2 templates, and prior TypeScript frontend modules (chat, graphs, schema, modals, tokens, messages, toolbar, input, config) and the old app bootstrap.
Frontend UI primitives & design system
app/src/components/ui/*, app/src/index.css, app/tailwind.config.ts
Add comprehensive Radix/Tailwind UI primitives (Dialog, AlertDialog, DropdownMenu, Button, Card, Table, Input, Select, Toast, ThemeToggle, Avatar, Badge, Progress, Skeleton, etc.) and Tailwind-based design tokens and global styles.
Contexts, hooks & utilities
app/src/contexts/*, app/src/hooks/*, app/src/lib/utils.ts
Add AuthContext, DatabaseContext, useIsMobile, use-toast hook + toast API and cn (clsx + twMerge) helper.
Frontend API/config & services
app/src/config/api.ts, app/src/services/*, app/src/types/api.ts
Add API_CONFIG and buildApiUrl, typed API shapes, and frontend services handling auth, streaming chat, database operations, tokens, and streaming parsing.
Backend: SPA serving & auth adjustments
api/app_factory.py, api/routes/auth.py, api/auth/user_management.py
Serve built SPA from app/dist (assets, favicon, SPA catch‑all), add /auth-status, adjust logout behavior, introduce token_optional decorator and identity/merge helpers, and add logging.
Backend loaders, logging & error messages
api/core/schema_loader.py, api/loaders/*, api/routes/graphs.py
Standardize loader error messages, add logging, and replace verbose exception strings with user-facing generic messages.
SQL sanitization & prompt guidance
api/core/text2sql.py, api/sql_utils/*, api/agents/analysis_agent.py, docs/SQL_IDENTIFIER_QUOTING.md, tests/test_sql_sanitizer.py
Add SQLIdentifierQuoter and DatabaseSpecificQuoter, integrate auto-quoting into text2sql (regular and destructive flows), enforce quoting guidance in the agent prompt, add unit tests and docs describing approach.
E2E infra & tests
e2e/**, e2e/docker-compose.test.yml, .github/workflows/playwright.yml
Add Playwright E2E infra: docker-compose DB init scripts, BrowserWrapper, API wrappers, POMs, test helpers, and multiple test suites for chat, DB connect/delete, sidebar, and user profile/token flows; add Playwright workflow.
CI / workflows / repo config
.github/workflows/tests.yml, .github/workflows/e2e-tests.yml (removed), .github/workflows/dependency-review.yml, .github/workflows/spellcheck.yml, .gitignore, Pipfile, README.md, .github/wordlist.txt
Remove legacy E2E workflow, add frontend build to tests workflow, expand triggers to staging, add Playwright workflow, update .gitignore for frontend outputs, bump Pipfile deps, update README to reflect React+Vite, and update wordlist.
Static & public
app/public/robots.txt, backend dist-serving changes
Add robots.txt; backend mounts app/dist assets and provides favicon/SPA catch‑all with 404/503 fallbacks when files are missing.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Browser
  participant SPA as React App
  participant API as FastAPI
  participant DB as Database

  Browser->>API: GET / or /assets/* or /favicon.ico
  API-->>Browser: FileResponse (app/dist/index.html or static asset) or 404/503
  Browser->>SPA: load JS/CSS → App init
  SPA->>API: GET /auth-status (with credentials)
  API-->>SPA: { authenticated, user? }
  SPA->>API: POST /graphs/{id}/chat (streaming request)
  API->>DB: execute query / schema operations
  DB-->>API: stream boundary-delimited JSON chunks
  API-->>SPA: streaming response (boundary-delimited)
  SPA->>SPA: ChatService.streamQuery parses chunks → emits StreamMessage events
  SPA-->>Browser: render incremental AI steps, SQL, results, follow-ups
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Attention points:

  • SPA serving: dist path detection, FileResponse usage, conditional mounts for /icons and /img, and 404/503 fallback behavior.
  • Streaming protocol: API_CONFIG.STREAM_BOUNDARY, server framing, ChatService.streamQuery parsing, and partial-chunk/error handling.
  • SQL sanitization: heuristics in SQLIdentifierQuoter, regex extraction, auto-quote replacements, DB-specific quote selection, and integration in text2sql for regular and destructive flows.
  • Auth: token_optional semantics, /auth-status contract, logout cookie clearing, and OAuth redirect flows.
  • Large frontend surface: TypeScript typings, Radix/Tailwind component patterns, cn utility, context/provider wiring, modal lifecycle, streaming UI concurrency and cleanup.
  • E2E infra & tests: docker-compose DB init scripts, ports/healthchecks, Playwright storageState usage, ApiCalls ↔ backend parity, and reducing test flakiness.
  • Removal of legacy assets/templates: ensure no remaining runtime references to deleted CSS/Jinja/TS assets.

Poem

"I hopped from Jinja to Vite with cheer,
Components sprouted far and near.
Streams of answers, chunks in flight,
Identifiers quoted, SQL done right.
A rabbit nods — the build is here! 🐇"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.60% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Staging' is vague and generic, providing no meaningful information about the actual changes in this comprehensive pull request that migrates from server-side templates to React+Vite, removes legacy JavaScript modules, adds extensive E2E testing infrastructure, and includes SQL identifier sanitization improvements. Replace 'Staging' with a descriptive title that reflects the main objective, such as 'Migrate frontend to React with Vite and add E2E testing infrastructure' or 'Refactor frontend architecture: legacy JS removal and React+Vite migration'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch staging

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@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: 0

🧹 Nitpick comments (1)
app/ts/modules/graph_select.ts (1)

25-25: Consider removing the underscore prefix for callback parameters.

The underscore prefix conventionally signals "intentionally unused parameter," but these callback parameters are meant to be used by implementations to know which graph was selected or deleted. Using name instead of _name would be clearer and avoid confusion.

Apply this diff to use clearer parameter names:

-export function addGraphOption(name: string, onSelect: (_name: string) => void, onDelete: (_name: string) => void, isDemo: boolean = false) {
+export function addGraphOption(name: string, onSelect: (name: string) => void, onDelete: (name: string) => void, isDemo: boolean = false) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f06e96c and d7a9c60.

⛔ Files ignored due to path filters (1)
  • app/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • app/eslint.config.cjs (1 hunks)
  • app/package.json (1 hunks)
  • app/ts/modules/graph_select.ts (1 hunks)
  • app/ts/modules/left_toolbar.ts (2 hunks)
  • app/ts/modules/messages.ts (1 hunks)
  • app/ts/modules/modals.ts (1 hunks)
  • app/ts/modules/tokens.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Frontend source changes in app/**/*.{ts,tsx} must be compiled before production runs

Files:

  • app/ts/modules/tokens.ts
  • app/ts/modules/modals.ts
  • app/ts/modules/left_toolbar.ts
  • app/ts/modules/messages.ts
  • app/ts/modules/graph_select.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: e2e-tests
  • GitHub Check: e2e-tests
  • GitHub Check: e2e-tests
  • GitHub Check: e2e-tests
🔇 Additional comments (8)
app/eslint.config.cjs (1)

23-26: LGTM! Standard pattern for unused variables.

The updated rule correctly ignores underscore-prefixed parameters and variables, which is a widely adopted convention for intentionally unused identifiers. This aligns well with the cleanup performed across the TypeScript modules in this PR.

app/ts/modules/messages.ts (1)

77-77: LGTM! Unused parameter correctly removed.

The index parameter was not used in the loop body, so removing it improves code clarity.

app/ts/modules/tokens.ts (1)

141-143: LGTM! Appropriate use of bare catch.

Since the error is not used in the catch block, the bare catch syntax is cleaner and aligns with modern TypeScript/ES2019+ conventions.

app/ts/modules/modals.ts (1)

270-271: LGTM! Improved clarity and reliability.

Reading dbTypeSelect.value directly is better than relying on this binding. This change:

  • Makes the code more explicit and easier to understand
  • Eliminates potential confusion about this context in the event handler
  • Improves maintainability
app/ts/modules/left_toolbar.ts (2)

33-35: LGTM! Bare catch is appropriate here.

Since the error is not used in the catch block, the bare catch syntax is cleaner.


57-63: LGTM! Unused parameter removed.

The event parameter was not used in the handler, so removing it improves clarity. The browser will still pass the event object; it's just not captured by the function signature.

app/package.json (2)

9-9: LGTM! Lint script now properly fails on errors.

Removing || true is an important improvement - the lint script will now correctly fail when there are linting errors or warnings, rather than always succeeding. This strengthens code quality enforcement in CI/CD pipelines.


13-16: Dev dependency versions verified: typescript@^5.9.3, eslint@^9.37.0, @typescript-eslint/parser@^8.45.0 and @typescript-eslint/eslint-plugin@^8.45.0 are all published on npm and are minor/patch bumps within their major versions.

dependabot bot and others added 24 commits October 13, 2025 13:26
Bumps [psycopg2-binary](https://github.com/psycopg/psycopg2) from 2.9.10 to 2.9.11.
- [Changelog](https://github.com/psycopg/psycopg2/blob/master/NEWS)
- [Commits](psycopg/psycopg2@2.9.10...2.9.11)

---
updated-dependencies:
- dependency-name: psycopg2-binary
  dependency-version: 2.9.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
…-binary-2.9.11

Bump psycopg2-binary from 2.9.10 to 2.9.11
remove e2e old tests.
fix lint errors.
Bumps [esbuild](https://github.com/evanw/esbuild) from 0.25.10 to 0.27.0.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](evanw/esbuild@v0.25.10...v0.27.0)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.27.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
…es, etc.)

This commit addresses the issue where table names containing special characters
(especially dashes) cause SQL execution failures when the LLM forgets to quote them.

Solution implements a two-layer approach:

1. Enhanced LLM Prompt Layer:
   - Added explicit instructions in AnalysisAgent to quote identifiers with special chars
   - Emphasizes this as critical requirement for both PostgreSQL and MySQL

2. Automatic SQL Sanitization Layer (Safety Net):
   - New SQLIdentifierQuoter utility automatically detects and quotes table names
   - Database-aware: uses double quotes for PostgreSQL, backticks for MySQL
   - Integrated before query execution in both regular and destructive operations
   - Only quotes known tables from schema (safe, non-invasive)

Key Features:
- Safe: Only quotes known tables, not arbitrary strings or SQL keywords
- Smart: Avoids double-quoting already-quoted identifiers
- Fast: Regex-based parsing with minimal overhead
- Comprehensive: Handles FROM, JOIN, UPDATE, INSERT, DELETE, etc.
- Well-tested: Full unit test suite with 20+ test cases

Files Added:
- api/utils/sql_sanitizer.py - Core sanitization utility
- tests/test_sql_sanitizer.py - Comprehensive unit tests
- docs/SQL_IDENTIFIER_QUOTING.md - Complete documentation

Files Modified:
- api/core/text2sql.py - Integrated sanitizer into query pipeline
- api/agents/analysis_agent.py - Enhanced prompt with quoting requirements

This fix ensures reliable SQL execution for databases with non-standard table
naming conventions, addressing user feedback about persistent quoting issues.
- Add api/utils/__init__.py to make it a proper Python package
- Fix trailing whitespace in sql_sanitizer.py and test_sql_sanitizer.py
- Fix line-too-long issues by breaking long lines
- Remove unused pytest import in tests
- Fix unused variable warning by prefixing with underscore
- Add 'sanitization', 'Sanitization', 'JOINs', 'subqueries', 'subquery' to spellcheck wordlist
- Refactor text2sql.py to comply with pylint standards (line length, complexity)
- Update api/utils/__init__.py to properly export SQLIdentifierQuoter and DatabaseSpecificQuoter
- Add pylint disable comment for too-few-public-methods in DatabaseSpecificQuoter (utility class)
- Add pylint disable comments for too-many-statements/locals in complex async functions
- These are legitimate cases where the complexity is necessary for the functionality
- Change from 'from api.utils.sql_sanitizer import' to 'from api.utils import'
- This uses the __all__ export list defined in api/utils/__init__.py
- Avoids pylint module detection issues with submodule imports
BREAKING: There was already an api/utils.py file containing generate_db_description
Creating api/utils/ directory shadowed this module and broke existing imports.

Solution:
- Rename api/utils/ directory to api/sql_utils/
- Update all imports from 'api.utils' to 'api.sql_utils' for SQL sanitizer
- This preserves existing api.utils.py functionality (generate_db_description)
- Fixes E2E test failures caused by ImportError
…ging/esbuild-0.27.0

Bump esbuild from 0.25.10 to 0.27.0 in /app
Bumps [fastmcp](https://github.com/jlowin/fastmcp) from 2.12.4 to 2.13.0.1.
- [Release notes](https://github.com/jlowin/fastmcp/releases)
- [Changelog](https://github.com/jlowin/fastmcp/blob/main/docs/changelog.mdx)
- [Commits](PrefectHQ/fastmcp@v2.12.4...v2.13.0.1)

---
updated-dependencies:
- dependency-name: fastmcp
  dependency-version: 2.13.0.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Copy link
Copy Markdown
Contributor

@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: 2

♻️ Duplicate comments (1)
Pipfile (1)

17-17: Resolve python-multipart version mismatch.

The Pipfile constraint remains at ~=0.0.10 while Pipfile.lock pins 0.0.20, creating a mismatch. When running pipenv lock, this will either fail resolution or downgrade to 0.0.10, losing the intended patch release.

Apply this diff to align the constraint with the lockfile:

-python-multipart = "~=0.0.10"
+python-multipart = "~=0.0.20"

Then regenerate the lockfile with pipenv lock to ensure consistency.

Based on past review comments.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c718a01 and 13be2d3.

⛔ Files ignored due to path filters (1)
  • Pipfile.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • Pipfile (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
Pipfile

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Manage Python dependencies with pipenv; declare packages in Pipfile

Files:

  • Pipfile
🧠 Learnings (3)
📚 Learning: 2025-09-02T15:24:21.682Z
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to Pipfile : Manage Python dependencies with pipenv; declare packages in Pipfile

Applied to files:

  • Pipfile
📚 Learning: 2025-09-02T15:24:21.682Z
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to Pipfile.lock : Commit and update Pipfile.lock to lock dependency versions

Applied to files:

  • Pipfile
📚 Learning: 2025-09-02T15:24:21.682Z
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to .github/workflows/*.yml : GitHub Actions workflows should set up Python 3.12, use pipenv (sync --dev), create a CI .env using FALKORDB_URL, start FalkorDB for tests, and install Playwright browsers for E2E

Applied to files:

  • Pipfile
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Dependabot
  • GitHub Check: Dependabot
  • GitHub Check: Dependabot
  • GitHub Check: unit-tests
  • GitHub Check: dependency-review
  • GitHub Check: unit-tests
🔇 Additional comments (2)
Pipfile (2)

15-15: New jsonschema dependency looks appropriate.

The Python jsonschema package, released Aug 18, 2025, provides JSON Schema validation. The package has been scanned and no known vulnerabilities were found, and the project maintains a healthy version release cadence. The addition of jsonschema ~4.25.0 aligns with the backend validation enhancements mentioned in the PR summary.


24-25: Verify pylint 4.x configuration compatibility before upgrading.

The suggestion-mode option was removed in pylint 4.x; remove it from your config if defined. The async.py checker module has been renamed to async_checker.py. Ensure your project doesn't rely on internal APIs affected by these changes, and run CI to validate the upgrade.

Comment thread Pipfile
Comment thread Pipfile Outdated
Copy link
Copy Markdown
Contributor

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Pipfile (1)

15-15: Remove unused dependency or add implementation.

Version 4.25.0 of jsonschema exists on PyPI, but no imports of jsonschema are found in the codebase. Either implement the validation logic using this dependency or remove it from Pipfile.

♻️ Duplicate comments (5)
Pipfile (2)

17-17: python-multipart constraint still mismatched with lockfile.

This line remains at ~=0.0.10 while Pipfile.lock pins 0.0.20. This mismatch will cause pipenv lock to either fail or downgrade the package, losing the intended patched version. Update the constraint to ~=0.0.20 or ==0.0.20 to match the lockfile.

🔎 Apply this diff to fix the constraint:
-python-multipart = "~=0.0.10"
+python-multipart = "~=0.0.20"

Based on past review comments, this issue was previously flagged but remains unresolved.


20-20: fastmcp constraint may not resolve CVE-2025-66416 in mcp dependency.

While the constraint changed from ~=2.12.4 to >=2.13.1, previous reviews flagged that FastMCP 2.13.1 pins mcp<1.23.0, which does not include the DNS rebinding fix for CVE-2025-66416 (fixed in mcp 1.23.0). Verify that Pipfile.lock contains mcp >= 1.23.0 after regeneration. If not, either upgrade to fastmcp 2.14+ when available or explicitly pin mcp = ">=1.23.0" in the Pipfile.

#!/bin/bash
# Description: Check Pipfile.lock for mcp version to verify CVE-2025-66416 mitigation

echo "=== Checking Pipfile.lock for mcp version ==="
if [ -f "Pipfile.lock" ]; then
  mcp_version=$(cat Pipfile.lock | jq -r '.default.mcp.version // "mcp not found in lockfile"')
  echo "mcp version in Pipfile.lock: $mcp_version"
  
  if [[ "$mcp_version" != "mcp not found in lockfile" ]]; then
    # Extract version number (remove leading '==')
    version_number=$(echo "$mcp_version" | sed 's/^==//')
    echo ""
    echo "Checking if version >= 1.23.0..."
    python3 -c "from packaging import version; import sys; sys.exit(0 if version.parse('$version_number') >= version.parse('1.23.0') else 1)" && echo "✓ mcp version is >= 1.23.0 (CVE-2025-66416 fixed)" || echo "✗ mcp version is < 1.23.0 (CVE-2025-66416 NOT fixed)"
  fi
else
  echo "Pipfile.lock not found"
fi

Based on past review comments, this critical security issue was previously flagged but may remain unresolved.

app/src/components/chat/ChatInterface.tsx (3)

343-346: Add rel="noopener noreferrer" to external link.

The FalkorDB link uses target="_blank" without a rel attribute, which is a security risk allowing the opened page to access window.opener.

🔎 Apply this fix
-            <p className="text-gray-500 text-sm">
-              Powered by <a href="https://falkordb.com" target="_blank">FalkorDB</a>
-            </p>
+            <p className="text-gray-500 text-sm">
+              Powered by{" "}
+              <a
+                href="https://falkordb.com"
+                target="_blank"
+                rel="noopener noreferrer"
+              >
+                FalkorDB
+              </a>
+            </p>

Based on static analysis hints (Biome noBlankTarget rule).


223-233: Fix condition so SQL/analysis card is only added when there is content.

sqlQuery is initialized as an empty string (line 150), so sqlQuery !== undefined is always true. This causes the sql-query message to be appended even when neither SQL nor analysis info was returned.

🔎 Apply this fix
-      // Add SQL query message with analysis info (even if SQL is empty)
-      if (sqlQuery !== undefined || Object.keys(analysisInfo).length > 0) {
+      // Add SQL query/analysis card only when we have SQL text or analysis metadata
+      if (sqlQuery.trim().length > 0 || Object.keys(analysisInfo).length > 0) {

216-218: Handle schema_refresh events from the backend.

The streaming loop drops schema_refresh events that the backend emits after DDL statements. These fall through to the else branch and are logged as "Unknown message type", so users never see whether the automatic schema reload succeeded or failed.

🔎 Suggested addition
       } else if (message.type === 'confirmation' || message.type === 'destructive_confirmation') {
         // Handle confirmation request (also accept destructive_confirmation emitted by backend)
         finalContent = `This operation requires confirmation:\n\n${message.content}`;
+      } else if (message.type === 'schema_refresh') {
+        // Handle schema refresh notification after DDL statements
+        const refreshStatus = message.refresh_status || message.content || 'Schema refreshed';
+        toast({
+          title: "Schema Updated",
+          description: refreshStatus,
+        });
       } else {
         console.warn('Unknown message type received:', message.type, message);
       }
🧹 Nitpick comments (27)
.gitignore (1)

20-23: Frontend build outputs section is well-organized and appropriate.

The additions correctly ignore Vite build outputs and align with the React + Vite migration. One minor note: the pattern /app/public/js/* can be simplified to /app/public/js/ for consistency with gitignore conventions—both are valid, but the latter is more idiomatic.

🔎 Optional simplification (not required):
 # Frontend build outputs
-/app/public/js/*
+/app/public/js/
 /app/dist/
e2e/test-data/mysql-init.sql (1)

95-112: Consider adding idempotency handling for orders and order_items inserts.

Unlike the users and categories tables which use ON DUPLICATE KEY UPDATE, the inserts for orders (lines 95-101) and order_items (lines 103-112) lack idempotency safeguards. If the initialization script runs multiple times, these inserts may fail with duplicate key errors or create duplicate data.

🔎 Add ON DUPLICATE KEY UPDATE or conditional logic

For orders:

 INSERT INTO orders (user_id, status, total_amount, shipping_address) VALUES
 (1, 'completed', 1329.98, '123 Main St, New York, NY 10001'),
 (2, 'pending', 109.98, '456 Oak Ave, Los Angeles, CA 90001'),
 (3, 'shipped', 199.99, '789 Pine Rd, Chicago, IL 60601'),
 (1, 'completed', 54.98, '123 Main St, New York, NY 10001'),
-(4, 'pending', 89.99, '321 Elm St, Houston, TX 77001');
+(4, 'pending', 89.99, '321 Elm St, Houston, TX 77001')
+ON DUPLICATE KEY UPDATE id=id;

For order_items:

 INSERT INTO order_items (order_id, product_id, quantity, unit_price, subtotal) VALUES
 (1, 1, 1, 1299.99, 1299.99),
 (1, 2, 1, 29.99, 29.99),
 (2, 4, 1, 89.99, 89.99),
 (2, 3, 1, 19.99, 19.99),
 (3, 8, 1, 199.99, 199.99),
 (4, 5, 1, 49.99, 49.99),
 (4, 10, 1, 29.99, 29.99),
-(5, 4, 1, 89.99, 89.99);
+(5, 4, 1, 89.99, 89.99)
+ON DUPLICATE KEY UPDATE id=id;

Alternatively, you can wrap these inserts in conditional logic that checks if data already exists, though the ON DUPLICATE KEY approach is simpler for test data.

e2e/infra/ui/basePage.ts (1)

10-12: Consider specifying load state explicitly in initPage().

The initPage() method calls waitForLoadState() without parameters, which defaults to waiting for the 'load' event. Depending on your test requirements, you might want to wait for 'networkidle' to ensure all network activity completes, or explicitly document the default behavior.

🔎 Specify load state explicitly
 async initPage() {
-  await this.page.waitForLoadState();
+  await this.page.waitForLoadState('load'); // or 'networkidle' or 'domcontentloaded'
 }

This makes the behavior explicit and allows easier customization if tests require different load states.

e2e/test-data/postgres-init.sql (1)

88-105: Consider adding idempotency handling for orders and order_items inserts.

Similar to the MySQL script, the PostgreSQL inserts for orders (lines 88-94) and order_items (lines 96-105) lack idempotency safeguards. The users and categories tables use ON CONFLICT DO NOTHING, but orders and order_items don't, which could cause issues if the script runs multiple times.

🔎 Add ON CONFLICT DO NOTHING

For orders:

 INSERT INTO orders (user_id, status, total_amount, shipping_address) VALUES
 (1, 'completed', 1329.98, '123 Main St, New York, NY 10001'),
 (2, 'pending', 109.98, '456 Oak Ave, Los Angeles, CA 90001'),
 (3, 'shipped', 199.99, '789 Pine Rd, Chicago, IL 60601'),
 (1, 'completed', 54.98, '123 Main St, New York, NY 10001'),
-(4, 'pending', 89.99, '321 Elm St, Houston, TX 77001');
+(4, 'pending', 89.99, '321 Elm St, Houston, TX 77001')
+ON CONFLICT DO NOTHING;

For order_items:

 INSERT INTO order_items (order_id, product_id, quantity, unit_price, subtotal) VALUES
 (1, 1, 1, 1299.99, 1299.99),
 (1, 2, 1, 29.99, 29.99),
 (2, 4, 1, 89.99, 89.99),
 (2, 3, 1, 19.99, 19.99),
 (3, 8, 1, 199.99, 199.99),
 (4, 5, 1, 49.99, 49.99),
 (4, 10, 1, 29.99, 29.99),
-(5, 4, 1, 89.99, 89.99);
+(5, 4, 1, 89.99, 89.99)
+ON CONFLICT DO NOTHING;

Note: This requires a unique constraint on the id column (which is implicit for PRIMARY KEY) to work properly.

app/src/components/layout/Sidebar.tsx (4)

4-10: Remove unused import BrainCircuit.

BrainCircuit is imported but only referenced in commented-out code on line 112. Remove it to keep imports clean.

🔎 Apply this diff:
 import {
   PanelLeft,
-  BrainCircuit,
   BookOpen,
   LifeBuoy,
   Waypoints,
 } from 'lucide-react';

37-86: Consider lifting TooltipProvider to parent level.

Creating a new TooltipProvider for each SidebarIcon is inefficient. Typically, a single TooltipProvider should wrap the entire tree (or sidebar), allowing all tooltips to share delay configuration and internal state.

🔎 Suggested approach:
-const SidebarIcon = ({ icon: Icon, label, active, onClick, href, testId }: {
+const SidebarIcon = ({ icon: Icon, label, active, onClick, href, testId }: {
   icon: React.ElementType,
   label: string,
   active?: boolean,
   onClick?: () => void,
   href?: string,
   testId?: string
 }) => (
-  <TooltipProvider delayDuration={300} skipDelayDuration={0}>
-    <Tooltip delayDuration={0}>
+  <Tooltip delayDuration={0}>
       <TooltipTrigger asChild>
         {/* ... button/link content ... */}
       </TooltipTrigger>
       <TooltipContent side="right">{label}</TooltipContent>
-    </Tooltip>
-  </TooltipProvider>
+  </Tooltip>
 );

Then wrap the Sidebar content with a single TooltipProvider:

const Sidebar = (...) => {
  return (
    <TooltipProvider delayDuration={300} skipDelayDuration={0}>
      <aside ...>
        {/* sidebar content */}
      </aside>
    </TooltipProvider>
  );
};

68-81: Fallback Link to "#" is a dead-code path.

The third branch renders a Link to="#" which navigates nowhere. If neither onClick nor href is provided, the icon becomes non-functional. Consider removing this branch and making onClick or href required, or provide a meaningful default behavior.


43-75: Extract repeated className into a shared constant or utility.

The icon styling classes are duplicated across all three branches (button, anchor, Link). Extract to a variable or helper for DRY.

🔎 Example:
const getIconClasses = (active?: boolean) =>
  `flex h-10 w-10 items-center justify-center rounded-lg transition-colors ${
    active
      ? 'bg-purple-600 text-white'
      : 'text-gray-400 hover:bg-gray-800 hover:text-white'
  }`;
e2e/docker-compose.test.yml (1)

50-50: Password visible in healthcheck command.

The MySQL healthcheck includes -ppassword which will appear in docker ps output and logs. While acceptable for local test environments, be aware this can leak if CI logs are public.

An alternative approach is to use MYSQL_ALLOW_EMPTY_PASSWORD=yes for test containers or use environment variables in the healthcheck:

healthcheck:
  test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]

This works because mysqladmin can use MYSQL_PWD environment variable or the client defaults file.

Also applies to: 68-68

e2e/tests/auth.setup.ts (2)

17-17: Use const instead of let for variables that aren't reassigned.

The response variables are never reassigned after declaration.

-    let response = await api.loginWithEmail(
+    const response = await api.loginWithEmail(

Also applies to: 52-52, 87-87


9-116: Consider extracting duplicate authentication logic into a helper function.

The same login-or-signup pattern is repeated three times with minor variations (user credentials and file paths). Extracting this into a reusable function would improve maintainability.

🔎 Example refactor:
async function authenticateUser(
  api: apiCalls,
  request: APIRequestContext,
  user: { email: string; password: string },
  firstName: string,
  lastName: string,
  authFile: string,
  userLabel: string,
  context: BrowserContext
) {
  try {
    const response = await api.loginWithEmail(user.email, user.password, request);
    if (!response.success) {
      const signupResponse = await api.signupWithEmail(
        firstName, lastName, user.email, user.password, request
      );
      if (!signupResponse.success) {
        throw new Error(`Failed to create ${userLabel}: ${signupResponse.error || 'Unknown error'}`);
      }
      // Login after signup
      await api.loginWithEmail(user.email, user.password, request);
    }
  } catch (error) {
    throw new Error(`Authentication failed for ${userLabel}. Error: ${(error as Error).message}`);
  }
  await context.storageState({ path: authFile });
}
.github/workflows/playwright.yml (2)

59-66: Replace sleep 20 with active healthcheck polling.

Using a fixed sleep 20 is fragile—databases may be ready earlier (wasting CI time) or later (causing flaky failures). Use docker compose --wait or poll the healthchecks.

🔎 Example using docker compose wait:
     - name: Start test databases
       run: |
-        docker compose -f e2e/docker-compose.test.yml up -d
-        # Wait for databases to be healthy
-        echo "Waiting for databases to be ready..."
-        sleep 20
+        docker compose -f e2e/docker-compose.test.yml up -d --wait
+        echo "All databases are healthy"
         docker ps -a
         # Verify all containers are running
         docker compose -f e2e/docker-compose.test.yml ps

Note: --wait requires Docker Compose v2.1+ and waits for healthchecks to pass.


134-134: Consider adding webkit for broader browser coverage.

Currently only chromium and firefox are installed. Adding webkit would provide Safari-like testing coverage, which is valuable for cross-browser compatibility.

-      run: npx playwright install --with-deps chromium firefox
+      run: npx playwright install --with-deps chromium firefox webkit
app/src/components/modals/DeleteDatabaseModal.tsx (1)

27-30: Consider handling async onConfirm for better UX.

If onConfirm is async (e.g., API call to delete), the modal closes immediately while the operation might still be in progress. Consider adding loading state handling.

🔎 Example for async handling:
const [isDeleting, setIsDeleting] = useState(false);

const handleConfirm = async () => {
  setIsDeleting(true);
  try {
    await onConfirm();
    onOpenChange(false);
  } finally {
    setIsDeleting(false);
  }
};

// In the button:
<Button
  variant="destructive"
  onClick={handleConfirm}
  disabled={isDeleting}
>
  {isDeleting ? 'Deleting...' : 'Delete Database'}
</Button>
e2e/infra/api/apiRequests.ts (1)

6-48: Consider standardizing parameter order across request helpers.

The parameter order differs between methods:

  • getRequest and deleteRequest: (url, headers?, body?, availableRequest?)
  • postRequest and patchRequest: (url, body?, availableRequest?, headers?)

This inconsistency can lead to mistakes when switching between methods. Consider aligning all four to a single order (e.g., url, body?, availableRequest?, headers?) for better developer experience.

</parameter_order>

e2e/tests/chat.spec.ts (1)

189-189: Consider extracting hardcoded database URL to config.

The second database URL 'postgresql://postgres:postgres@localhost:5433/testdb_delete' is hardcoded here. Consider extracting it to getTestDatabases() in the config for consistency with other test database URLs (like line 178 where you use getTestDatabases().postgres).

app/src/components/schema/SchemaViewer.tsx (3)

122-123: Consider removing or gating debug console.log statements for production.

Multiple console.log calls remain throughout the component (force configuration, schema data loading, memoized graph data). These create noisy output in production and may expose schema details in browser consoles.

Consider either removing them or gating behind a development flag:

🔎 Example approach
+const DEBUG = process.env.NODE_ENV === 'development';
+
 // Then wrap logs:
-console.log('Forces already configured, skipping reconfiguration');
+if (DEBUG) console.log('Forces already configured, skipping reconfiguration');

Or simply remove the debug logging for production readiness.

Also applies to: 133-133, 140-140, 165-166, 179-179, 225-227, 367-377


352-360: Add height fallback in nodePointerAreaPaint to match nodeCanvasObject.

nodeCanvasObject (line 280-282) calculates a fallback height when node.height is undefined, but nodePointerAreaPaint uses node.height directly without a fallback. If this function is called before nodeCanvasObject sets the height, hit areas will be malformed.

🔎 Suggested fix
 const nodePointerAreaPaint = (node: any, color: string, ctx: CanvasRenderingContext2D) => {
   ctx.fillStyle = color;
   const padding = 5;
+  const lineHeight = 14;
+  const headerHeight = 20;
+  const nodePadding = 8;
+  const height = node.height || (headerHeight + (node.columns?.length || 0) * lineHeight + nodePadding * 2);
   ctx.fillRect(
     node.x - NODE_WIDTH / 2 - padding,
-    node.y - node.height / 2 - padding,
+    node.y - height / 2 - padding,
     NODE_WIDTH + padding * 2,
-    node.height + padding * 2
+    height + padding * 2
   );
 };

38-38: Consider adding proper typing for graphRef.

Using any for the graph ref loses type safety. If react-force-graph-2d exports a ref type, consider using it.

app/src/components/chat/ChatInterface.tsx (1)

109-110: Fix inconsistent indentation.

Line 110 has inconsistent indentation compared to the rest of the function body.

 const handleSendMessage = async (query: string) => {
-  if (isProcessing || disabled) return; // Prevent multiple submissions or when disabled by parent
+    if (isProcessing || disabled) return; // Prevent multiple submissions or when disabled by parent
e2e/logic/api/apiCalls.ts (3)

124-136: Remove unnecessary async from synchronous URL helper methods.

getGoogleLoginUrl and getGithubLoginUrl don't perform any asynchronous operations but are marked as async, which adds unnecessary overhead and can mislead callers.

🔎 Suggested fix
-  async getGoogleLoginUrl(): Promise<string> {
+  getGoogleLoginUrl(): string {
     const baseUrl = getBaseUrl();
     return `${baseUrl}/login/google`;
   }

-  async getGithubLoginUrl(): Promise<string> {
+  getGithubLoginUrl(): string {
     const baseUrl = getBaseUrl();
     return `${baseUrl}/login/github`;
   }

252-267: Consider adding error handling for malformed JSON in streaming response.

parseStreamingResponse splits the response body and parses each segment as JSON. If any segment is malformed, JSON.parse will throw and the entire parsing fails. Consider handling individual parse failures gracefully.

🔎 Suggested improvement
   async parseStreamingResponse(
     response: APIResponse
   ): Promise<StreamMessage[]> {
     try {
       const body = await response.text();
       const messages = body
         .split("|||FALKORDB_MESSAGE_BOUNDARY|||")
         .filter((msg) => msg.trim())
-        .map((msg) => JSON.parse(msg.trim()));
+        .map((msg) => {
+          try {
+            return JSON.parse(msg.trim());
+          } catch {
+            console.warn('Failed to parse streaming message:', msg.substring(0, 100));
+            return null;
+          }
+        })
+        .filter((msg): msg is StreamMessage => msg !== null);
       return messages;
     } catch (error) {

273-300: Consider adding type for chat parameter instead of any[].

The chat parameter in confirmGraphOperation is typed as any[]. Consider using ConversationMessage[] or a more specific type for better type safety.

e2e/logic/pom/userProfile.ts (1)

352-370: Consider using inherited BasePage methods instead of redefining.

getCurrentUrl() and reloadPage() shadow similar methods in BasePage (getCurrentURL() and refreshPage()). Note that refreshPage() waits for networkidle while reloadPage() doesn't—if this difference is intentional, consider documenting it; otherwise, prefer the inherited methods for consistency.

e2e/logic/pom/homePage.ts (3)

147-165: Consider using getByTestId for form inputs for consistency.

These form inputs use locator('#id') while the rest of the class uses getByTestId. Using test IDs is generally preferred in Playwright as they're more resilient to refactoring and explicitly signal testing intent.

🔎 Example for one field:
 private get hostInput(): Locator {
-  return this.page.locator('#host');
+  return this.page.getByTestId("host-input");
 }

This would require adding corresponding data-testid attributes to the frontend form elements.


1088-1110: ensureDatabaseConnected silently continues after API errors.

The catch block logs the error but proceeds to connect anyway. If getGraphs() fails due to auth issues or network problems, the subsequent connectDatabase call will likely also fail. Consider re-throwing certain error types or adding more specific error handling.

🔎 Suggested improvement:
 async ensureDatabaseConnected(apiCall: ApiCalls): Promise<boolean> {
   try {
     // Check if any databases exist (returns string[] of graph IDs)
     const graphs = await apiCall.getGraphs();

     // If we have graphs, database is already connected
     if (graphs && graphs.length > 0) {
       return false;
     }
   } catch (error) {
-    console.log('Error checking existing graphs, will attempt to connect:', error);
+    // Only proceed if this is a "no graphs" type error, not auth/network failure
+    if (error instanceof Error && !error.message.includes('404')) {
+      throw error;
+    }
+    console.log('No existing graphs found, will attempt to connect');
   }

822-829: Minor: await on a synchronous getter is unnecessary.

this.databaseStatusBadge is a synchronous getter, so the await on line 824 has no effect. This doesn't cause issues but could be simplified.

🔎 Apply this diff:
 async getDatabaseStatusBadgeText(): Promise<string> {
   try {
-    const badge = await this.databaseStatusBadge;
+    const badge = this.databaseStatusBadge;
     return await badge.textContent() || '';
   } catch {
     return '';
   }
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13be2d3 and 60db6ef.

⛔ Files ignored due to path filters (2)
  • Pipfile.lock is excluded by !**/*.lock
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (33)
  • .github/workflows/playwright.yml (1 hunks)
  • .gitignore (1 hunks)
  • Pipfile (2 hunks)
  • app/src/components/chat/ChatInterface.tsx (1 hunks)
  • app/src/components/chat/ChatMessage.tsx (1 hunks)
  • app/src/components/chat/QueryInput.tsx (1 hunks)
  • app/src/components/layout/Sidebar.tsx (1 hunks)
  • app/src/components/modals/DatabaseModal.tsx (1 hunks)
  • app/src/components/modals/DeleteDatabaseModal.tsx (1 hunks)
  • app/src/components/modals/LoginModal.tsx (1 hunks)
  • app/src/components/modals/TokensModal.tsx (1 hunks)
  • app/src/components/schema/SchemaViewer.tsx (1 hunks)
  • app/src/components/ui/theme-toggle.tsx (1 hunks)
  • app/src/components/ui/toaster.tsx (1 hunks)
  • app/src/pages/Index.tsx (1 hunks)
  • e2e/config/urls.ts (1 hunks)
  • e2e/docker-compose.test.yml (1 hunks)
  • e2e/infra/api/apiRequests.ts (1 hunks)
  • e2e/infra/ui/basePage.ts (1 hunks)
  • e2e/infra/ui/browserWrapper.ts (1 hunks)
  • e2e/infra/utils.ts (1 hunks)
  • e2e/logic/api/apiCalls.ts (1 hunks)
  • e2e/logic/api/apiResponses.ts (1 hunks)
  • e2e/logic/pom/homePage.ts (1 hunks)
  • e2e/logic/pom/sidebar.ts (1 hunks)
  • e2e/logic/pom/userProfile.ts (1 hunks)
  • e2e/test-data/mysql-init.sql (1 hunks)
  • e2e/test-data/postgres-init.sql (1 hunks)
  • e2e/tests/auth.setup.ts (1 hunks)
  • e2e/tests/chat.spec.ts (1 hunks)
  • e2e/tests/database.spec.ts (1 hunks)
  • e2e/tests/sidebar.spec.ts (1 hunks)
  • e2e/tests/userProfile.spec.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/src/components/modals/LoginModal.tsx
  • app/src/components/modals/DatabaseModal.tsx
  • app/src/components/ui/theme-toggle.tsx
🧰 Additional context used
📓 Path-based instructions (3)
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Frontend source changes in app/**/*.{ts,tsx} must be compiled before production runs

Files:

  • app/src/components/schema/SchemaViewer.tsx
  • app/src/components/layout/Sidebar.tsx
  • app/src/components/chat/ChatInterface.tsx
  • app/src/components/chat/ChatMessage.tsx
  • app/src/components/modals/DeleteDatabaseModal.tsx
  • app/src/components/ui/toaster.tsx
  • app/src/components/modals/TokensModal.tsx
  • app/src/pages/Index.tsx
  • app/src/components/chat/QueryInput.tsx
.github/workflows/*.yml

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

GitHub Actions workflows should set up Python 3.12, use pipenv (sync --dev), create a CI .env using FALKORDB_URL, start FalkorDB for tests, and install Playwright browsers for E2E

Files:

  • .github/workflows/playwright.yml
Pipfile

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Manage Python dependencies with pipenv; declare packages in Pipfile

Files:

  • Pipfile
🧠 Learnings (7)
📚 Learning: 2025-09-02T15:24:21.682Z
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to .github/workflows/*.yml : GitHub Actions workflows should set up Python 3.12, use pipenv (sync --dev), create a CI .env using FALKORDB_URL, start FalkorDB for tests, and install Playwright browsers for E2E

Applied to files:

  • .github/workflows/playwright.yml
  • Pipfile
📚 Learning: 2025-09-02T15:24:21.682Z
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to tests/e2e/test_*.py : E2E test files should be placed under tests/e2e/test_*.py for Playwright runs

Applied to files:

  • .github/workflows/playwright.yml
  • e2e/tests/sidebar.spec.ts
  • e2e/tests/auth.setup.ts
  • e2e/tests/chat.spec.ts
  • .gitignore
  • e2e/infra/ui/basePage.ts
📚 Learning: 2025-09-02T15:24:21.682Z
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to tests/e2e/pages/**/*.py : Use the Page Object Model for Playwright tests under tests/e2e/pages

Applied to files:

  • e2e/tests/userProfile.spec.ts
  • e2e/infra/ui/browserWrapper.ts
  • e2e/infra/ui/basePage.ts
📚 Learning: 2025-09-02T15:24:21.682Z
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to app/**/*.{ts,tsx} : Frontend source changes in app/**/*.{ts,tsx} must be compiled before production runs

Applied to files:

  • .gitignore
📚 Learning: 2025-09-02T15:24:21.682Z
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to app/public/js/app.js : Do not edit the generated frontend bundle app/public/js/app.js directly; build it via make build-prod or npm run build

Applied to files:

  • .gitignore
📚 Learning: 2025-09-02T15:24:21.682Z
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to Pipfile : Manage Python dependencies with pipenv; declare packages in Pipfile

Applied to files:

  • Pipfile
📚 Learning: 2025-09-02T15:24:21.682Z
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to Pipfile.lock : Commit and update Pipfile.lock to lock dependency versions

Applied to files:

  • Pipfile
🧬 Code graph analysis (14)
app/src/components/schema/SchemaViewer.tsx (3)
app/src/contexts/DatabaseContext.tsx (1)
  • useDatabase (104-110)
app/src/hooks/use-toast.ts (2)
  • useToast (186-186)
  • toast (186-186)
app/src/services/database.ts (1)
  • DatabaseService (9-253)
e2e/tests/sidebar.spec.ts (3)
e2e/infra/ui/browserWrapper.ts (1)
  • BrowserWrapper (13-113)
e2e/logic/pom/sidebar.ts (1)
  • Sidebar (14-141)
e2e/config/urls.ts (1)
  • getBaseUrl (55-57)
e2e/tests/userProfile.spec.ts (2)
e2e/logic/pom/userProfile.ts (3)
  • isGitHubLinkVisible (422-424)
  • isGenerateTokenBtnVisible (275-277)
  • isNewTokenAlertVisible (279-281)
e2e/config/urls.ts (2)
  • getBaseUrl (55-57)
  • getTestUser3 (76-78)
e2e/tests/auth.setup.ts (1)
e2e/config/urls.ts (3)
  • getTestUser (62-64)
  • getTestUser2 (69-71)
  • getTestUser3 (76-78)
app/src/components/chat/ChatMessage.tsx (4)
app/src/components/ui/card.tsx (2)
  • Card (43-43)
  • CardContent (43-43)
app/src/components/ui/avatar.tsx (3)
  • Avatar (38-38)
  • AvatarImage (38-38)
  • AvatarFallback (38-38)
app/src/components/ui/badge.tsx (1)
  • Badge (29-29)
app/src/components/ui/progress.tsx (1)
  • Progress (23-23)
app/src/components/modals/DeleteDatabaseModal.tsx (2)
app/src/components/ui/dialog.tsx (6)
  • Dialog (85-85)
  • DialogContent (90-90)
  • DialogHeader (91-91)
  • DialogTitle (93-93)
  • DialogDescription (94-94)
  • DialogFooter (92-92)
app/src/components/ui/button.tsx (1)
  • Button (47-47)
app/src/components/ui/toaster.tsx (1)
app/src/components/ui/toast.tsx (6)
  • ToastProvider (104-104)
  • Toast (106-106)
  • ToastTitle (107-107)
  • ToastDescription (108-108)
  • ToastClose (109-109)
  • ToastViewport (105-105)
app/src/pages/Index.tsx (10)
app/src/contexts/AuthContext.tsx (1)
  • useAuth (66-72)
app/src/contexts/DatabaseContext.tsx (1)
  • useDatabase (104-110)
app/src/hooks/use-toast.ts (2)
  • useToast (186-186)
  • toast (186-186)
app/src/services/database.ts (2)
  • uploadSchema (114-148)
  • DatabaseService (9-253)
e2e/logic/api/apiCalls.ts (1)
  • logout (102-118)
api/routes/auth.py (1)
  • logout (670-692)
app/src/components/ui/badge.tsx (1)
  • Badge (29-29)
app/src/components/ui/dropdown-menu.tsx (5)
  • DropdownMenu (164-164)
  • DropdownMenuTrigger (165-165)
  • DropdownMenuContent (166-166)
  • DropdownMenuItem (167-167)
  • DropdownMenuSeparator (171-171)
app/src/components/ui/button.tsx (1)
  • Button (47-47)
app/src/components/ui/avatar.tsx (3)
  • Avatar (38-38)
  • AvatarImage (38-38)
  • AvatarFallback (38-38)
e2e/infra/ui/browserWrapper.ts (1)
e2e/infra/ui/basePage.ts (1)
  • BasePage (3-30)
e2e/tests/database.spec.ts (3)
e2e/infra/ui/browserWrapper.ts (1)
  • BrowserWrapper (13-113)
e2e/logic/pom/homePage.ts (1)
  • HomePage (7-1111)
e2e/config/urls.ts (2)
  • getBaseUrl (55-57)
  • getTestDatabases (83-85)
e2e/logic/pom/userProfile.ts (2)
e2e/infra/ui/basePage.ts (1)
  • BasePage (3-30)
e2e/infra/utils.ts (1)
  • waitForElementToBeVisible (9-25)
app/src/components/chat/QueryInput.tsx (2)
app/src/components/ui/textarea.tsx (1)
  • Textarea (21-21)
app/src/components/ui/button.tsx (1)
  • Button (47-47)
e2e/logic/api/apiCalls.ts (3)
e2e/logic/api/apiResponses.ts (12)
  • AuthStatusResponse (13-16)
  • LoginResponse (18-21)
  • SignupResponse (23-26)
  • LogoutResponse (28-30)
  • GraphsListResponse (34-34)
  • GraphDataResponse (52-55)
  • GraphUploadResponse (57-61)
  • StreamMessage (88-110)
  • DeleteGraphResponse (63-67)
  • GenerateTokenResponse (123-126)
  • TokenListResponse (119-121)
  • DeleteTokenResponse (128-130)
e2e/config/urls.ts (1)
  • getBaseUrl (55-57)
e2e/infra/api/apiRequests.ts (3)
  • getRequest (50-50)
  • postRequest (50-50)
  • deleteRequest (50-50)
e2e/logic/pom/sidebar.ts (2)
e2e/logic/pom/homePage.ts (1)
  • HomePage (7-1111)
e2e/infra/utils.ts (1)
  • waitForElementToBeVisible (9-25)
🪛 Biome (2.1.2)
app/src/components/chat/ChatInterface.tsx

[error] 345-345: Avoid using target="_blank" without rel="noopener" or rel="noreferrer".

Opening external links in new tabs without rel="noopener" is a security risk. See the explanation for more details.
Safe fix: Add the rel="noopener" attribute.

(lint/security/noBlankTarget)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Dependabot
  • GitHub Check: test
  • GitHub Check: unit-tests
  • GitHub Check: test
  • GitHub Check: unit-tests
🔇 Additional comments (24)
.gitignore (1)

29-34: Playwright E2E test ignores are security-conscious and appropriate.

Auth file exclusions (/playwright/.auth/ and e2e/.auth/) prevent accidental credential leaks, and report/cache directories are standard outputs. Well-organized and no concerns.

Pipfile (1)

7-11: All package versions are valid and accessible.

FastAPI 0.124.0 was released on Dec 6, 2025, and uvicorn 0.38.0 is the latest version with no known vulnerabilities. LiteLLM 1.80.9 is the latest version with no known vulnerabilities. FalkorDB 1.2.2 is available on PyPI, and psycopg2-binary 2.9.11 (latest as of Oct 10, 2025) has no known security issues. The version bumps are routine updates using the compatible release operator (~=). No breaking changes are indicated in recent changelogs for these minor and patch version increments.

e2e/test-data/mysql-init.sql (1)

6-62: LGTM! Schema design is well-structured.

The table definitions follow best practices with proper constraints, foreign keys, indexes, and character encoding. The use of IF NOT EXISTS ensures idempotency for schema creation.

app/src/components/chat/QueryInput.tsx (1)

1-53: LGTM! Well-implemented input component with proper event handling.

The component correctly:

  • Handles form submission with trim validation
  • Prevents submission when disabled
  • Supports Enter to submit and Shift+Enter for newlines
  • Includes proper accessibility attributes (aria-label)
  • Provides test IDs for E2E testing
  • Clears input after successful submission

The event handling logic is sound, and the component follows React best practices.

e2e/infra/utils.ts (1)

9-61: LGTM! Wait utility functions follow good retry patterns.

The wait functions implement proper retry logic with configurable delays and timeouts. The error handling logs issues without throwing, which is appropriate for polling scenarios. Returning boolean success indicators allows callers to handle failures gracefully.

e2e/config/urls.ts (1)

1-85: LGTM! Clean configuration structure with sensible defaults.

The configuration module properly:

  • Centralizes URLs and credentials for E2E tests
  • Uses environment variables with fallback defaults
  • Provides type-safe access via as const and accessor functions
  • Includes clear documentation for each configuration section

This follows best practices for test configuration management.

e2e/tests/sidebar.spec.ts (1)

18-66: LGTM! Well-structured E2E tests with proper assertions.

The test cases effectively verify:

  • Theme toggle functionality switches between dark and light modes
  • Documentation and support links point to correct URLs
  • Schema panel opens and closes on button clicks

Each test follows best practices with proper setup, full-screen consistency, and cleanup. The use of page objects abstracts UI interactions appropriately.

app/src/components/ui/toaster.tsx (1)

1-24: LGTM! Proper toast notification rendering with good React patterns.

The Toaster component correctly:

  • Uses the useToast hook to access toast state
  • Provides unique keys (id) for each toast in the list
  • Conditionally renders optional elements (title, description, action)
  • Includes test IDs for E2E verification
  • Properly composes Toast subcomponents within ToastProvider

The implementation follows React best practices for list rendering and component composition.

e2e/infra/ui/basePage.ts (1)

1-30: LGTM! Clean base page implementation following Page Object Model.

The BasePage class provides a solid foundation for page objects with essential navigation and waiting utilities. The methods are simple wrappers around Playwright APIs, which is appropriate for a base class.

Based on learnings, this correctly follows the Page Object Model pattern for E2E tests.

e2e/test-data/postgres-init.sql (1)

4-55: LGTM! PostgreSQL schema is well-designed with proper constraints.

The table definitions use appropriate PostgreSQL syntax with:

  • SERIAL for auto-increment primary keys
  • Proper foreign key relationships with CASCADE deletes
  • IF NOT EXISTS for idempotent schema creation
  • Good use of test_schema namespace
app/src/components/layout/Sidebar.tsx (1)

89-134: LGTM on the sidebar layout and mobile handling.

The responsive collapse behavior with desktop/mobile differentiation is well-implemented. The use of sr-only labels for accessibility and proper external link attributes (target="_blank", rel="noopener noreferrer") are good practices.

e2e/docker-compose.test.yml (1)

1-36: PostgreSQL services look good.

The PostgreSQL test database configuration with healthchecks, separate ports for delete tests, and init scripts is well-structured for E2E testing.

.github/workflows/playwright.yml (2)

120-130: LGTM on environment configuration.

The FastAPI step correctly sets FALKORDB_URL, DISABLE_MCP, and passes necessary Azure secrets for schema analysis. This aligns with the coding guidelines for CI environment setup.


162-168: Good cleanup step with if: always().

The cleanup properly handles both docker-compose services and the standalone FalkorDB container, using || true to prevent failures from blocking other cleanups.

app/src/components/modals/DeleteDatabaseModal.tsx (2)

12-18: Interface is well-designed.

The DeleteDatabaseModalProps interface clearly defines the component's contract with appropriate optionality (isDemo defaults to false).


32-88: LGTM on modal structure and accessibility.

The modal correctly uses dialog primitives, has appropriate styling for destructive action (red icon, destructive button variant), provides clear warning text, and includes proper test IDs. The demo mode handling gracefully prevents deletion of shared databases.

e2e/logic/api/apiResponses.ts (1)

1-147: Well-structured API response type definitions.

The interfaces are well-organized with clear section comments, appropriate use of optional fields, and good type narrowing (e.g., success: true literal in LogoutResponse). The any type for StreamMessage.data is reasonable given the dynamic nature of streaming response payloads.

app/src/components/chat/ChatInterface.tsx (2)

84-97: Good fix: Conversation history now resets on graph change.

The useEffect correctly clears conversationHistory.current and resets messages when selectedGraph?.id changes, preventing history leakage between databases.


213-215: Good fix: destructive_confirmation events are now handled.

The handler now correctly accepts both confirmation and destructive_confirmation message types.

e2e/logic/pom/sidebar.ts (1)

1-141: Well-structured Page Object Model implementation.

The Sidebar class follows a clean three-layer architecture (locators → interaction helpers → high-level actions) with consistent error handling and good documentation. The extension of HomePage allows reuse of common page elements while providing sidebar-specific functionality.

e2e/logic/api/apiCalls.ts (1)

22-44: Clean error handling pattern.

The try-catch pattern with descriptive error wrapping is consistent and helpful for debugging test failures.

e2e/logic/pom/userProfile.ts (1)

1-9: Well-structured POM implementation.

The layered architecture (locators → interact with visible → high-level actions) is clean and promotes maintainability. Good use of the shared waitForElementToBeVisible utility.

e2e/logic/pom/homePage.ts (2)

1-7: Comprehensive POM with good layered structure.

The class provides extensive coverage for home page interactions with well-organized layers. Good use of both visibility and enabled-state checks for interactive elements like buttons.


974-993: The 500ms initial wait is a pragmatic choice for UI settling.

This pattern is common when dealing with async UI state changes. The approach of checking visibility first and returning early if the indicator never appeared is good defensive coding.

Comment thread app/src/components/chat/ChatMessage.tsx
Comment thread e2e/docker-compose.test.yml
Comment thread e2e/infra/utils.ts
Comment thread e2e/logic/api/apiCalls.ts
Comment thread e2e/logic/pom/userProfile.ts
Comment thread e2e/tests/auth.setup.ts
Comment thread Pipfile
Comment thread app/src/components/schema/SchemaViewer.tsx Fixed
Comment thread app/src/components/schema/SchemaViewer.tsx Fixed
Comment thread app/src/components/schema/SchemaViewer.tsx Fixed
Comment thread app/src/components/chat/ChatMessage.tsx Fixed
Comment thread app/src/components/layout/Sidebar.tsx Fixed
Comment thread app/src/components/modals/DatabaseModal.tsx Fixed
Comment thread app/src/components/schema/SchemaViewer.tsx Fixed
Comment thread app/src/services/auth.ts Fixed
Comment thread app/src/pages/Index.tsx Fixed
Comment thread e2e/infra/utils.ts Fixed
Copy link
Copy Markdown
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api/core/text2sql.py (1)

778-801: Potential information disclosure in error messages.

Exposing raw exception messages to clients via str(e) can leak sensitive information such as:

  • Database connection details or internal paths
  • Table/column names (schema enumeration)
  • Driver-specific error codes that aid attackers

Consider sanitizing the error message or providing a generic user-facing message while logging the full exception server-side (which is already done at line 779).

🔎 Suggested fix:
             except Exception as e:  # pylint: disable=broad-exception-caught
                 logging.error("Error executing confirmed SQL query: %s", str(e))  # nosemgrep
-                error_message = str(e) if str(e) else "Error executing query"
+                # Provide generic message to avoid leaking sensitive details
+                error_message = "Error executing query. Please check your SQL syntax and try again."

                 # Save failed confirmed query to memory

If you need to show some error context, consider a whitelist approach for known safe error types (e.g., syntax errors) while hiding others.

♻️ Duplicate comments (3)
app/src/components/chat/ChatMessage.tsx (1)

44-111: LGTM! The duplicate closing div issue has been resolved.

The confirmation message JSX structure is now properly balanced with three opening divs (lines 44, 45, 51) matched by three closing divs (lines 108, 109, 110).

app/src/components/chat/ChatInterface.tsx (2)

246-255: Fix the condition to prevent empty SQL cards.

The condition sqlQuery !== undefined is always true because sqlQuery is initialized as an empty string on line 156. This causes an empty SQL card to be displayed even when there's no SQL or analysis info.

🔎 Apply this diff to fix the condition:
-      // Add SQL query message with analysis info (even if SQL is empty)
-      if (sqlQuery !== undefined || Object.keys(analysisInfo).length > 0) {
+      // Add SQL query message with analysis info only when there's content
+      if (sqlQuery.trim().length > 0 || Object.keys(analysisInfo).length > 0) {
         const sqlMessage: ChatMessageData = {
           id: (Date.now() + 2).toString(),
           type: "sql-query",
           content: sqlQuery,
           analysisInfo: analysisInfo,
           timestamp: new Date(),
         };
         setMessages(prev => [...prev, sqlMessage]);
       }

545-549: Add rel="noopener noreferrer" to the external link for security.

The FalkorDB link opens in a new tab but lacks the rel attribute, allowing the opened page to access window.opener. This is a security risk.

🔎 Apply this diff to fix the security issue:
           <div className="text-center mt-4">
             <p className="text-gray-500 text-sm">
-              Powered by <a href="https://falkordb.com" target="_blank">FalkorDB</a>
+              Powered by <a href="https://falkordb.com" target="_blank" rel="noopener noreferrer">FalkorDB</a>
             </p>
           </div>
🧹 Nitpick comments (7)
e2e/logic/pom/homePage.ts (5)

159-177: Consider using getByTestId for consistency.

These locators use CSS ID selectors (#host, #port, etc.) while the rest of the class consistently uses getByTestId. Consider adding data-testid attributes to these form inputs in the frontend for uniformity and maintainability.


238-260: Optional: Extract common visibility check pattern into a helper.

The interact methods follow a repetitive pattern. Consider extracting a reusable helper to reduce boilerplate.

🔎 Example helper approach
private async interactWhenVisible(
  locator: Locator,
  elementName: string,
  checkEnabled: boolean = false
): Promise<Locator> {
  const isVisible = await waitForElementToBeVisible(locator);
  if (!isVisible) throw new Error(`${elementName} is not visible!`);
  if (checkEnabled) {
    const isEnabled = await waitForElementToBeEnabled(locator);
    if (!isEnabled) throw new Error(`${elementName} is not enabled!`);
  }
  return locator;
}

// Usage:
private async interactWithLogoImage(): Promise<Locator> {
  return this.interactWhenVisible(this.logoImage, "Logo image");
}

834-841: Unnecessary await on synchronous getter.

this.databaseStatusBadge is a synchronous getter returning a Locator. The await is superfluous.

🔎 Apply this diff
   async getDatabaseStatusBadgeText(): Promise<string> {
     try {
-      const badge = await this.databaseStatusBadge;
-      return await badge.textContent() || '';
+      return await this.databaseStatusBadge.textContent() || '';
     } catch {
       return '';
     }
   }

978-980: The timeout-to-retry conversion is non-obvious.

waitForElementToBeVisible takes (locator, waitTime, retryCount). Passing timeoutMs / 1000 as the retry count works but the relationship between the parameter name (timeoutMs) and actual usage (retry count) is confusing. Consider adding a clarifying comment or renaming the parameter.


1152-1161: Consider using interactWhenVisible pattern for consistency.

These methods directly call .click() without visibility/enabled checks, unlike other button click methods in this class. While tests using these likely call waitForConfirmationMessage first, adding visibility checks would improve robustness.

🔎 Apply this diff for consistency
+  private async interactWithConfirmationConfirmBtn(): Promise<Locator> {
+    const isVisible = await waitForElementToBeVisible(this.confirmationConfirmBtn);
+    if (!isVisible) throw new Error("Confirmation confirm button is not visible!");
+    return this.confirmationConfirmBtn;
+  }
+
+  private async interactWithConfirmationCancelBtn(): Promise<Locator> {
+    const isVisible = await waitForElementToBeVisible(this.confirmationCancelBtn);
+    if (!isVisible) throw new Error("Confirmation cancel button is not visible!");
+    return this.confirmationCancelBtn;
+  }
+
   async clickConfirmButton(): Promise<void> {
-    await this.confirmationConfirmBtn.click();
+    const element = await this.interactWithConfirmationConfirmBtn();
+    await element.click();
   }

   async clickCancelButton(): Promise<void> {
-    await this.confirmationCancelBtn.click();
+    const element = await this.interactWithConfirmationCancelBtn();
+    await element.click();
   }
e2e/tests/chat.spec.ts (1)

187-189: Consider extracting hardcoded database URL to config.

The second database URL is hardcoded while the first comes from getTestDatabases(). Consider adding a second test database to the configuration for consistency and maintainability.

🔎 Suggested approach
// In config/urls.ts, add:
// postgres2: 'postgresql://postgres:postgres@localhost:5433/testdb_delete'

// Then in test:
const { postgres: postgresUrl, postgres2: secondDbUrl } = getTestDatabases();
api/core/text2sql.py (1)

666-697: Consider extracting shared auto-quoting logic into a helper function.

This block duplicates the auto-quoting logic from query_database() (lines 320-345). The pattern of extracting known tables, getting the quote character, and calling auto_quote_identifiers appears twice.

Additionally, lines 667-669 re-fetch sql_query from confirm_data, but this was already done at line 637. This redundancy could be removed.

🔎 Suggested helper function to reduce duplication:
async def _auto_quote_sql(
    sql_query: str,
    known_tables: set[str],
    db_url: str
) -> str:
    """Auto-quote identifiers with special characters in SQL query."""
    if not sql_query:
        return sql_query
    
    db_type, _ = get_database_type_and_loader(db_url)
    quote_char = DatabaseSpecificQuoter.get_quote_char(db_type or 'postgresql')
    
    sanitized_sql, was_modified = SQLIdentifierQuoter.auto_quote_identifiers(
        sql_query, known_tables, quote_char
    )
    
    if was_modified:
        logging.info("SQL query auto-sanitized: quoted identifiers with special characters")
        return sanitized_sql
    
    return sql_query

Then both call sites can use:

sql_query = await _auto_quote_sql(sql_query, known_tables, db_url)
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60db6ef and f97d39b.

📒 Files selected for processing (7)
  • api/core/text2sql.py (7 hunks)
  • app/src/components/chat/ChatInterface.tsx (1 hunks)
  • app/src/components/chat/ChatMessage.tsx (1 hunks)
  • app/src/services/chat.ts (1 hunks)
  • app/src/types/api.ts (1 hunks)
  • e2e/logic/pom/homePage.ts (1 hunks)
  • e2e/tests/chat.spec.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • app/src/services/chat.ts
  • app/src/types/api.ts
🧰 Additional context used
📓 Path-based instructions (2)
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Frontend source changes in app/**/*.{ts,tsx} must be compiled before production runs

Files:

  • app/src/components/chat/ChatMessage.tsx
  • app/src/components/chat/ChatInterface.tsx
**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

All Python code should pass pylint (use make lint)

Files:

  • api/core/text2sql.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to app/**/*.{ts,tsx} : Frontend source changes in app/**/*.{ts,tsx} must be compiled before production runs
🧬 Code graph analysis (3)
app/src/components/chat/ChatMessage.tsx (5)
app/src/components/ui/avatar.tsx (3)
  • Avatar (38-38)
  • AvatarFallback (38-38)
  • AvatarImage (38-38)
app/src/components/ui/card.tsx (2)
  • Card (43-43)
  • CardContent (43-43)
app/src/components/ui/button.tsx (1)
  • Button (47-47)
app/src/components/ui/badge.tsx (1)
  • Badge (29-29)
app/src/components/ui/progress.tsx (1)
  • Progress (23-23)
api/core/text2sql.py (1)
api/sql_utils/sql_sanitizer.py (4)
  • SQLIdentifierQuoter (7-151)
  • DatabaseSpecificQuoter (154-171)
  • get_quote_char (158-171)
  • auto_quote_identifiers (107-151)
e2e/logic/pom/homePage.ts (2)
e2e/infra/ui/basePage.ts (1)
  • BasePage (3-30)
e2e/infra/utils.ts (2)
  • waitForElementToBeVisible (9-25)
  • waitForElementToBeEnabled (45-61)
🪛 Biome (2.1.2)
app/src/components/chat/ChatInterface.tsx

[error] 547-547: Avoid using target="_blank" without rel="noopener" or rel="noreferrer".

Opening external links in new tabs without rel="noopener" is a security risk. See the explanation for more details.
Safe fix: Add the rel="noopener" attribute.

(lint/security/noBlankTarget)

🪛 Ruff (0.14.8)
api/core/text2sql.py

680-680: Do not catch blind exception: Exception

(BLE001)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: test
  • GitHub Check: unit-tests
  • GitHub Check: unit-tests
  • GitHub Check: test
  • GitHub Check: dependency-review
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (19)
app/src/components/chat/ChatInterface.tsx (5)

90-103: LGTM! Conversation history is now properly reset when the database changes.

The useEffect hook correctly clears the conversation history and resets messages when selectedGraph?.id changes, preventing cross-database history leakage.


219-240: LGTM! Destructive confirmation events are now properly handled.

The code now recognizes both 'confirmation' and 'destructive_confirmation' message types, creating the appropriate confirmation UI for destructive operations.


401-411: LGTM! Schema refresh events are now properly handled.

The streaming loop now includes an explicit case for schema_refresh events, displaying the refresh status to users instead of silently discarding these messages.


127-142: LGTM! History snapshot prevents duplicate user messages.

The code now takes a snapshot of conversationHistory.current before adding the new user message, ensuring the backend receives only prior turns in history and the current query separately.


366-400: LGTM! Excellent user-friendly error handling.

The error message cleanup logic effectively transforms technical database errors into clear, actionable messages for users. The handling of duplicate keys, foreign key violations, and not-null constraints significantly improves the user experience.

e2e/logic/pom/homePage.ts (4)

1-6: LGTM!

Imports are well-organized and appropriate for a Playwright Page Object Model class.


700-705: LGTM!

The deleteDatabase workflow correctly waits for modal visibility before proceeding to confirm. The discarded return value from interactWithDeleteDatabaseModal() is intentional for synchronization.


986-1005: Timing assumption in processing indicator check.

The 500ms delay before checking indicator visibility is a reasonable workaround for race conditions, but could cause flakiness if the indicator takes longer to appear or processing completes very quickly. This is acceptable for E2E tests but worth monitoring.


1100-1122: LGTM!

The method provides a robust helper for test setup. The error-tolerant approach on getGraphs failure (proceeding to connect anyway) is appropriate for E2E test resilience where the goal is ensuring a database is available.

e2e/tests/chat.spec.ts (8)

7-22: LGTM!

Test setup provides good isolation with fresh browser and API instances per test. The 60-second timeout is appropriate for chat operations that involve API calls and UI interactions.


24-42: LGTM!

Good use of a separate storage state (user2.json) to test the no-database scenario, ensuring proper isolation from other tests.


44-74: LGTM!

Test comprehensively validates the full query flow: SQL generation, results display, and AI response. The row count assertion (toBe(1)) assumes deterministic test data, which is appropriate for E2E tests with controlled fixtures.


76-105: LGTM!

Good test for validating off-topic query handling. The distinction between SQL message visibility (for query analysis) vs. actual SQL content is well-documented in the comments.


107-141: LGTM!

Validates that conversation history persists across multiple queries by tracking message counts.


158-174: Potential timing sensitivity.

The test checks disabled state immediately after sendQuery, which could be flaky if processing completes very quickly. Consider adding a small delay or checking disabled state within sendQuery before the click completes. However, this is likely fine with typical network latency.


229-268: LGTM!

Good use of Date.now() for unique test data to avoid conflicts. The test comprehensively validates the confirmation flow for destructive operations.


270-293: LGTM!

Good test for validating user-friendly error messages on duplicate records. The random username ensures test isolation.

api/core/text2sql.py (2)

21-21: LGTM!

The import is correctly structured and aligns with the module exports in api/sql_utils/__init__.py.


320-345: The implementation correctly applies auto-quoting with database-specific quote characters.

The logic properly extracts table names from the result structure (which is List[List[Any]] per the find() function return type), determines the appropriate database-specific quote character, and sanitizes the SQL query only when modifications are needed. The code correctly handles edge cases by checking if original_sql exists and defaulting known_tables to an empty set if result is None.

Comment thread e2e/tests/chat.spec.ts Outdated
Comment thread app/src/components/schema/SchemaViewer.tsx Dismissed
Comment thread app/src/pages/Index.tsx Dismissed
Comment thread e2e/logic/pom/homePage.ts Dismissed
Comment thread e2e/infra/ui/browserWrapper.ts Dismissed
Copy link
Copy Markdown
Contributor

@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: 6

♻️ Duplicate comments (3)
app/src/components/chat/ChatMessage.tsx (1)

136-194: Remove duplicate closing tag.

There's an extra </div> at line 193. The JSX structure has:

  • Line 142: Opening <div className="px-6">
  • Line 143: Opening <div className="flex gap-3 mb-6 items-start">
  • Line 148: Opening <div className="flex-1 min-w-0">
  • Line 190: Closes line 148
  • Line 191: Closes line 143
  • Line 192: Closes line 142
  • Line 193: Extra closing tag (must be removed)

This will cause a JSX/React error.

🔎 Fix by removing the duplicate closing tag:
         </div>
       </div>
-      </div>
     );
   }
app/src/components/schema/SchemaViewer.tsx (1)

351-360: Add height fallback in nodePointerAreaPaint for robustness.

The function uses node.height directly (line 356) without a fallback. While nodeCanvasObject ensures height is set (lines 279-281), if nodePointerAreaPaint is invoked before the height is calculated, it could produce incorrect hit areas.

🔎 Apply this diff to mirror the height calculation from `nodeCanvasObject`:
 const nodePointerAreaPaint = (node: any, color: string, ctx: CanvasRenderingContext2D) => {
+  const lineHeight = 14;
+  const padding = 8;
+  const headerHeight = 20;
+  
+  if (!node.height) {
+    node.height = headerHeight + (node.columns?.length || 0) * lineHeight + padding * 2;
+  }
+
   ctx.fillStyle = color;
   const padding = 5;

Note: You'll need to rename one of the padding variables to avoid conflict (e.g., hitPadding for the pointer area padding).

app/src/components/layout/Sidebar.tsx (1)

4-9: Previous review comment has been addressed.

The unused BrainCircuit import mentioned in the previous review has already been removed. All current imports are properly used in the component.

🧹 Nitpick comments (9)
e2e/logic/pom/userProfile.ts (1)

259-273: Consider unifying visibility check patterns.

The login button visibility methods use try-catch with direct isVisible(), while most other visibility checks use the waitForElementToBeVisible utility. While the current approach works, unifying the pattern would improve consistency.

🔎 Optional: align with the waitForElementToBeVisible pattern
 async isGoogleLoginBtnVisible(): Promise<boolean> {
-  try {
-    return await this.googleLoginBtn.isVisible();
-  } catch {
-    return false;
-  }
+  return await waitForElementToBeVisible(this.googleLoginBtn);
 }

 async isGithubLoginBtnVisible(): Promise<boolean> {
-  try {
-    return await this.githubLoginBtn.isVisible();
-  } catch {
-    return false;
-  }
+  return await waitForElementToBeVisible(this.githubLoginBtn);
 }
app/src/components/chat/ChatMessage.tsx (2)

19-19: Consider stricter typing for queryData.

Using any[] reduces type safety. Since query results are objects with dynamic keys, consider using Record<string, unknown>[] instead to maintain some type constraints while supporting dynamic column names.

🔎 Apply this diff to improve type safety:
-  queryData?: any[]; // For table data
+  queryData?: Record<string, unknown>[]; // For table data

231-233: Optional: Improve type safety for cell values.

The value: any parameter could be typed as unknown for better type safety. Additionally, consider handling null/undefined explicitly before string conversion, though String(value) is safe for these cases.

🔎 View suggested improvement:
-                            {Object.values(row).map((value: any, cellIndex) => (
+                            {Object.values(row).map((value: unknown, cellIndex) => (
                               <td key={cellIndex} className="px-3 py-2 text-gray-200 whitespace-nowrap">
-                                {String(value)}
+                                {value === null || value === undefined ? '' : String(value)}
                               </td>
                             ))}
app/src/components/schema/SchemaViewer.tsx (2)

121-121: Remove or gate debug console.log statements.

Multiple console.log statements remain throughout the component (force configuration, data loading, graph data memoization). These create noise in production browser consoles and were flagged in the previous review as not yet addressed.

Consider removing them entirely or gating behind a dev-only flag:

const DEBUG = import.meta.env.DEV;

if (DEBUG) {
  console.log('Forces already configured, skipping reconfiguration');
}

Also applies to: 132-132, 139-139, 164-165, 178-178, 224-226, 366-376


398-401: Remove redundant isOpen checks after the early return.

Three locations check isOpen after the guard clause on line 393 ensures it's always true:

  1. Line 398-401: The mobile overlay is wrapped with {isOpen && (...)} but is unreachable when isOpen is false.
  2. Line 407: The ternary ${isOpen ? 'translate-x-0' : '-translate-x-full pointer-events-none'} will always use the first branch.
  3. Line 412: The condition isOpen && window.innerWidth >= 768 can be simplified to just window.innerWidth >= 768.
🔎 Apply these diffs to simplify:
-      {isOpen && (
-        <div 
-          className="fixed inset-0 bg-black/50 z-40 md:hidden"
-          onClick={onClose}
-        />
-      )}
+      <div 
+        className="fixed inset-0 bg-black/50 z-40 md:hidden"
+        onClick={onClose}
+      />
-        className={`fixed top-0 h-full bg-gray-900 border-r border-gray-700 flex flex-col transition-all duration-300
-          ${isOpen ? 'translate-x-0' : '-translate-x-full pointer-events-none'}
+        className={`fixed top-0 h-full bg-gray-900 border-r border-gray-700 flex flex-col transition-all duration-300
+          translate-x-0
           md:z-30 z-50
         style={{
-          ...(isOpen && window.innerWidth >= 768 ? {
+          ...(window.innerWidth >= 768 ? {
             left: `${sidebarWidth}px`,
             width: `${width}px`
           } : {})

Also applies to: 407-407, 412-412

app/src/components/layout/Sidebar.tsx (2)

111-111: Remove commented-out code.

Commented-out code (lines 111 and 128) should be removed to keep the codebase clean. Use version control to track removed features if needed.

🔎 Apply this diff
           <ThemeToggle />
-          {/* <SidebarIcon icon={BrainCircuit} label="Query" active /> */}
           <SidebarIcon
             icon={Waypoints}
             label="Schema"
         <SidebarIcon icon={BookOpen} label="Documentation" href="https://docs.falkordb.com/" testId="documentation-link" />
         <SidebarIcon icon={LifeBuoy} label="Support" href="https://discord.com/invite/jyUgBweNQz" testId="support-link" />
-        {/* <SidebarIcon icon={Settings} label="Settings" /> */}
       </nav>

Also applies to: 128-128


91-91: Remove unnecessary fragment wrapper.

The empty fragment wrapping only the aside element serves no purpose and can be removed for cleaner code.

🔎 Apply this diff
 const Sidebar = ({ className, onSchemaClick, isSchemaOpen, isCollapsed = false, onToggleCollapse }: SidebarProps) => {
   const isMobile = useIsMobile();
   return (
-    <>
       <aside className={cn(
         ...
       )}>
         ...
       </aside>
-    </>
   );
 };

Also applies to: 131-131

app/src/components/modals/DatabaseModal.tsx (2)

63-210: Consider adding request cancellation capability.

If the user closes the modal while a connection attempt is in progress, the fetch request continues running in the background. Adding an AbortController would allow you to cancel the request cleanly, improving resource usage and user experience.

🔎 Pattern to implement request cancellation:

Add an abort controller ref and cleanup:

const abortControllerRef = useRef<AbortController | null>(null);

useEffect(() => {
  return () => {
    // Cancel any ongoing request when component unmounts
    abortControllerRef.current?.abort();
  };
}, []);

Then in handleConnect, create and use the controller:

const handleConnect = async () => {
  // ... validation code ...
  
  // Cancel any previous request
  abortControllerRef.current?.abort();
  abortControllerRef.current = new AbortController();
  
  setIsConnecting(true);
  setConnectionSteps([]);
  
  try {
    // ... URL building ...
    
    const response = await fetch(buildApiUrl('/database'), {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ url: dbUrl }),
      credentials: 'include',
      signal: abortControllerRef.current.signal,  // Add this
    });
    
    // ... rest of the code ...
  } catch (error) {
    // Ignore abort errors
    if (error instanceof Error && error.name === 'AbortError') {
      return;
    }
    // ... existing error handling ...
  }
};

22-34: Optional: Consider consolidating state with useReducer.

The component manages 10 related pieces of state with separate useState calls. While this works correctly, consolidating connection-related state (database type, mode, URL, manual fields) into a useReducer could make state transitions more predictable and the reset logic (lines 150-158) cleaner.

This is a minor refinement that could improve maintainability as the form grows more complex, but the current approach is perfectly functional.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f97d39b and 48ff79c.

📒 Files selected for processing (9)
  • app/src/components/chat/ChatMessage.tsx (1 hunks)
  • app/src/components/layout/Sidebar.tsx (1 hunks)
  • app/src/components/modals/DatabaseModal.tsx (1 hunks)
  • app/src/components/schema/SchemaViewer.tsx (1 hunks)
  • app/src/pages/Index.tsx (1 hunks)
  • app/src/services/auth.ts (1 hunks)
  • e2e/infra/utils.ts (1 hunks)
  • e2e/logic/pom/userProfile.ts (1 hunks)
  • e2e/tests/chat.spec.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • e2e/tests/chat.spec.ts
  • app/src/pages/Index.tsx
  • e2e/infra/utils.ts
🧰 Additional context used
📓 Path-based instructions (1)
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Frontend source changes in app/**/*.{ts,tsx} must be compiled before production runs

Files:

  • app/src/components/layout/Sidebar.tsx
  • app/src/components/schema/SchemaViewer.tsx
  • app/src/services/auth.ts
  • app/src/components/modals/DatabaseModal.tsx
  • app/src/components/chat/ChatMessage.tsx
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: FalkorDB/QueryWeaver PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-02T15:24:21.682Z
Learning: Applies to app/**/*.{ts,tsx} : Frontend source changes in app/**/*.{ts,tsx} must be compiled before production runs
🧬 Code graph analysis (4)
app/src/components/layout/Sidebar.tsx (4)
app/src/components/ui/tooltip.tsx (4)
  • TooltipProvider (29-29)
  • Tooltip (29-29)
  • TooltipTrigger (29-29)
  • TooltipContent (29-29)
app/hooks/use-mobile.ts (1)
  • useIsMobile (4-18)
app/src/lib/utils.ts (1)
  • cn (4-6)
app/src/components/ui/separator.tsx (1)
  • Separator (20-20)
app/src/components/schema/SchemaViewer.tsx (3)
app/src/contexts/DatabaseContext.tsx (1)
  • useDatabase (104-110)
app/src/hooks/use-toast.ts (2)
  • useToast (186-186)
  • toast (186-186)
app/src/services/database.ts (1)
  • DatabaseService (9-253)
app/src/services/auth.ts (2)
app/src/types/api.ts (1)
  • AuthStatus (13-16)
app/src/config/api.ts (2)
  • buildApiUrl (40-42)
  • API_CONFIG (2-37)
app/src/components/chat/ChatMessage.tsx (5)
app/src/components/ui/avatar.tsx (3)
  • Avatar (38-38)
  • AvatarFallback (38-38)
  • AvatarImage (38-38)
app/src/components/ui/card.tsx (2)
  • Card (43-43)
  • CardContent (43-43)
app/src/components/ui/button.tsx (1)
  • Button (47-47)
app/src/components/ui/badge.tsx (1)
  • Badge (29-29)
app/src/components/ui/progress.tsx (1)
  • Progress (23-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: test
  • GitHub Check: unit-tests
  • GitHub Check: dependency-review
  • GitHub Check: test
  • GitHub Check: unit-tests
🔇 Additional comments (16)
e2e/logic/pom/userProfile.ts (4)

1-9: Well-structured POM with clear layering.

The class structure with three distinct layers (locators, interaction helpers, high-level actions) is excellent for maintainability and follows Playwright best practices.


215-229: Excellent pattern for testing API interactions.

Setting up the response listener before triggering the delete action prevents race conditions and ensures the API call is captured. This is the recommended approach for E2E tests that need to verify backend operations.


372-390: Previous issue resolved: empty array guards are now in place.

The empty array guards added at lines 374-376 and 384-386 properly prevent runtime errors when no token rows exist. This addresses the concern raised in the previous review.


323-426: Robust token management utilities with proper edge case handling.

The token utility methods demonstrate good defensive programming:

  • getAllTokenRows() gracefully handles the no-tokens case
  • findTokenInList() performs comprehensive validation of token format and metadata
  • waitForTokenRowToDisappear() uses Playwright's built-in waiting mechanisms effectively
app/src/components/chat/ChatMessage.tsx (1)

1-8: Past unused import issue resolved.

The previously flagged unused imports (User, Bot, ArrowRight) have been removed. All current lucide-react imports are now used in the component.

app/src/services/auth.ts (2)

13-36: LGTM! Authentication status check is well-implemented.

The method correctly handles different response states (403 for unauthenticated, other errors for demo mode) and includes helpful logging for debugging.


91-122: LGTM! Logout and user fetching are correctly implemented.

Both methods properly handle errors (logout propagates, getCurrentUser returns null), include credentials for session management, and have appropriate logging.

app/src/components/schema/SchemaViewer.tsx (7)

1-34: LGTM!

The imports and type definitions are well-structured and appropriate for the force-directed graph visualization.


116-186: LGTM!

The force configuration logic is well-designed with inverse scaling for small graphs and proper guarding against reconfiguration on resize. The retry mechanism for d3 availability is appropriate.


187-216: LGTM!

The resize handling now correctly uses the sidebarWidth prop instead of a hardcoded value, and the bounds checking and event listener cleanup are properly implemented.


265-349: LGTM!

The canvas rendering logic is well-implemented with theme-aware colors, proper height calculation, and smart text ellipsization for type fields that don't fit.


362-391: LGTM!

The memoized graph data prevents unnecessary recreations during resize, and the theme-aware color functions are straightforward and correct. (Note: Console.log statements were already flagged separately.)


218-263: LGTM!

Data loading includes proper error handling with user-facing toasts, and the zoom/center controls correctly use the ForceGraph2D API with appropriate parameters.


462-511: LGTM!

The render logic properly handles loading, data, and empty states. The ForceGraph2D configuration is comprehensive with appropriate force parameters, custom rendering functions, and theme-aware styling.

app/src/components/layout/Sidebar.tsx (1)

20-26: LGTM!

The interface is well-defined with appropriate optional properties for a flexible sidebar component.

app/src/components/modals/DatabaseModal.tsx (1)

114-116: Well done addressing the previous null-check concern!

The guard against response.body being null is now in place and throws a descriptive error, preventing runtime crashes in environments where the body might be absent. This keeps error handling consistent through the existing catch block.

Comment thread app/src/components/layout/Sidebar.tsx
Comment thread app/src/components/layout/Sidebar.tsx
Comment thread app/src/components/modals/DatabaseModal.tsx
Comment thread app/src/services/auth.ts
Comment thread app/src/services/auth.ts
Comment thread app/src/services/auth.ts
@galshubeli galshubeli merged commit bb2063c into main Dec 18, 2025
18 checks passed
gkorland pushed a commit that referenced this pull request Feb 22, 2026
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.

4 participants