Skip to content

feat(console): CodeEditor completions prop for as-you-type suggestions - #597

Merged
rohitg00 merged 3 commits into
mainfrom
feat/codeeditor-completions
Jul 27, 2026
Merged

feat(console): CodeEditor completions prop for as-you-type suggestions#597
rohitg00 merged 3 commits into
mainfrom
feat/codeeditor-completions

Conversation

@rohitg00

@rohitg00 rohitg00 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Adds an opt-in completions?: readonly string[] prop to the shared CodeEditor (#579). Non-empty turns on the as-you-type suggest popup (the default stays prose-quiet, so markdown/json/yaml behaviour is byte-for-byte unchanged) and registers a Monaco completion provider for the editor's language offering those words, disposed on unmount.

First consumer is the database worker's SQL panel, which feeds it the live table names plus SQL keywords for schema-aware autocomplete.

Test

tsc + biome clean. Verified live in the console SQL editor: typing a keyword or table prefix pops the suggest list, and Ctrl+Space triggers it explicitly. Prose editors (markdown/json) are unaffected since they pass no completions.

Summary by CodeRabbit

  • New Features
    • Added optional as-you-type autocomplete suggestions to the code editor, configurable via a public completions list.
    • Introduced a new read-only database extension page with a schema sidebar, table viewer (sorting, pagination, row details), and an SQL panel with query history and EXPLAIN support.
  • Bug Fixes
    • Improved safe clipboard copy behavior for values.
  • Chores
    • Added database page styling, UI building blocks (schema tree, pagination, results grid), and read-only SQL safeguards.

@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview, Comment Jul 27, 2026 9:24am
workers-tech-spec Ready Ready Preview, Comment Jul 27, 2026 9:24am

Request Review

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@rohitg00, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 33 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3344183e-ff27-407b-ace1-4c54c54684ff

📥 Commits

Reviewing files that changed from the base of the PR and between e0416aa and ba9f896.

📒 Files selected for processing (7)
  • database/ui/src/page/RowDetail.tsx
  • database/ui/src/page/SchemaTree.tsx
  • database/ui/src/page/SqlPanel.tsx
  • database/ui/src/page/cells.ts
  • database/ui/src/page/db-data.ts
  • database/ui/src/page/index.tsx
  • database/ui/src/page/result-grid.tsx
📝 Walkthrough

Walkthrough

The PR adds a registered read-only database browser with schema exploration, paginated table data, row inspection, SQL execution, query history, and responsive styling. It also adds optional Monaco completion terms to the shared code editor.

Changes

Database browser

Layer / File(s) Summary
Database RPC and query data layer
database/ui/src/page/db-data.ts, database/ui/package.json
Adds validated database RPC responses, driver-specific schema/index introspection, read-only SQL checks, quoting, row counts, and paged reads.
Database page orchestration and registration
database/ui/page.tsx, database/ui/src/page/index.tsx, database/ui/src/page/useDatabaseRead.ts
Registers the database page and coordinates database/table loading, selection, refresh, and data/SQL modes.
Schema, table data, and row inspection
database/ui/src/page/SchemaTree.tsx, database/ui/src/page/TableDataPanel.tsx, database/ui/src/page/result-grid.tsx, database/ui/src/page/pagination.tsx, database/ui/src/page/RowDetail.tsx, database/ui/src/page/cells.ts
Adds lazy schema loading, sortable and selectable result grids, pagination, row details, typed cell rendering, and copying.
Read-only SQL panel and page presentation
database/ui/src/page/SqlPanel.tsx, database/ui/src/page/icons.tsx, database/ui/src/page/page-styles.ts
Adds SQL execution, explain actions, local query history, result display, inline icons, and scoped responsive styles.

Editor completions

Layer / File(s) Summary
Completion API and Monaco provider
console/web/src/components/ui/CodeEditor.tsx, packages/console-ui/index.d.ts
Adds readonly completion strings and registers, filters, and disposes an asynchronous language-specific Monaco completion provider.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: sergiofilhowz

Poem

A rabbit browses tables beneath the moon,
Finds rows and schemas, all in tune.
SQL whispers softly, read-only and bright,
While Monaco offers words just right.
Hop through the data, then close the pane!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes a real change in the PR, though it covers only one part of a much larger database UI update.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/codeeditor-completions

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.

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

skill-check — worker

0 verified, 49 skipped (no docs/).

Layer Result
structure
vale
ai
render

Four for four. Nicely done.

@rohitg00
rohitg00 requested a review from sergiofilhowz July 24, 2026 18:01
@rohitg00
rohitg00 marked this pull request as ready for review July 24, 2026 18:01
@rohitg00 rohitg00 added the no-ticket PR deliberately has no Linear ticket (bump/typo/CI-only) label Jul 24, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@console/web/src/components/ui/CodeEditor.tsx`:
- Around line 221-224: Update the completions cleanup logic around
editor.updateOptions to capture the editor’s original quickSuggestions and
wordBasedSuggestions values before applying completion-specific options, then
restore both values when completions becomes empty. Preserve the existing
behavior for active completions while ensuring cleanup returns the editor to its
prior completion settings.
- Around line 227-246: Update the completion provider created in CodeEditor’s
monaco.languages.registerCompletionItemProvider call to return no suggestions
unless the provideCompletionItems model is the owning editor model. Compare the
callback’s model against the editor’s current model, then preserve the existing
words mapping and range behavior for the owning model.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b40c2e4-2a9c-45c6-a2fd-31a347f41811

📥 Commits

Reviewing files that changed from the base of the PR and between 6452708 and bbb1442.

📒 Files selected for processing (2)
  • console/web/src/components/ui/CodeEditor.tsx
  • packages/console-ui/index.d.ts

Comment thread console/web/src/components/ui/CodeEditor.tsx
Comment thread console/web/src/components/ui/CodeEditor.tsx
Adds an opt-in `completions?: readonly string[]` to the shared CodeEditor
(#579). Non-empty turns on the suggest popup (the default stays prose-quiet,
so markdown/json/yaml behavior is byte-for-byte unchanged) and registers a
Monaco completion provider for the editor's language offering those words,
disposed on unmount. The database SQL panel is the first consumer, feeding
it the live table names plus SQL keywords.
…598)

* feat(database): injectable console page (schema browser + SQL panel)

Ships the database worker's #/ext/database page over the injectable-UI
protocol (#570): a schema tree with lazy per-driver column/PK/FK/index
introspection, a sortable paginated row grid with a row inspector, and a
read-only SQL panel (shared Monaco CodeEditor, EXPLAIN, per-db history,
client-side write-verb gate). Reads the live database via database::query
and database::listDatabases. Registered through host.pages.register in the
existing database/ui setup, alongside the function-trigger renderer.

The SQL editor feeds the live table names plus SQL keywords to the
CodeEditor completions prop for as-you-type suggestions.

* fix(database): address review on the injectable page

- read-only SQL gate hardened: single-statement only (semicolons in
  strings/comments ignored), reject any write/DDL keyword anywhere so
  mutating CTEs and EXPLAIN ANALYZE cannot slip past the leading keyword,
  and reject writable PRAGMA forms (journal_mode=WAL) while keeping read
  PRAGMAs
- listDbs throws on a shape mismatch like runQuery, so a malformed
  response is distinguishable from an empty database list
- fetchTablePage fetches a pageSize+1 sentinel row so pagination stays
  bounded when the row count is unknown; normalize page/size to
  non-negative integers before interpolating
- copyText swallows the async clipboard rejection via ?.catch, not just
  the sync call
- icons preserve caller aria-hidden/aria-label (labeled icons stay
  accessible) instead of forcing aria-hidden
- result grid sets aria-sort on sortable headers

Worker-side read-only transaction enforcement is out of scope here (it is
a database worker change); this tightens the client gate as defense in
depth. SqlPanel already remounts per database via its key, so no separate
db-change reset is needed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (3)
database/ui/src/page/SchemaTree.tsx (1)

65-82: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Failed schema loads never retry.

The guard only skips when the entry is undefined, so once a table is marked 'error' re-expanding it is a no-op and the user is stuck with "failed to read schema" until the parent remounts. Allow a retry when the cached value is 'error'.

♻️ Retry on re-expand after an error
-    if (schemaByTable[table.name] === undefined) {
+    const cached = schemaByTable[table.name]
+    if (cached === undefined || cached === 'error') {
       setSchemaByTable((cur) => ({ ...cur, [table.name]: 'loading' }))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@database/ui/src/page/SchemaTree.tsx` around lines 65 - 82, Update the
schema-loading guard in the expansion logic around tableColumns and tableIndexes
so loading starts when schemaByTable[table.name] is undefined or 'error'.
Preserve the existing loading, success, and error state transitions so
re-expanding a failed table retries the request.
database/ui/src/page/result-grid.tsx (2)

240-254: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Copy-on-click is silently disabled whenever onRowClick is set.

In that mode cells render bare content, so copied/copyCell are unreachable — yet the file header states every cell copies its value on click. Since TableDataPanel always passes onRowClick, the copy affordance never exists in the table browser. Either update the header comment to describe the two modes, or keep a non-nested copy trigger (e.g. copy on the cell's dblclick, or a hover icon) so the behavior matches the docs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@database/ui/src/page/result-grid.tsx` around lines 240 - 254, Update the cell
rendering in the result-grid component so copyCell remains reachable when
onRowClick is provided, preserving row-click behavior while adding a separate
copy trigger such as double-click or a hover control; alternatively revise the
file header to accurately document the two interaction modes. Ensure the
implemented behavior matches the chosen documentation and does not leave copied
state unreachable.

139-145: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated "copied for 1200ms" logic in result-grid.tsx and RowDetail.tsx. Both sites reimplement the same copy-then-flag-then-timeout block; the shared piece belongs next to cellText/copyText in cells.ts as a small useCopyFeedback() hook (which would also give a single place to clear the timer).

  • database/ui/src/page/result-grid.tsx#L139-L145: replace copyCell and the local copied state with the shared hook.
  • database/ui/src/page/RowDetail.tsx#L26-L32: replace copyValue and the local copied state with the same hook.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@database/ui/src/page/result-grid.tsx` around lines 139 - 145, The
copy-feedback behavior is duplicated across both components. Add a shared
useCopyFeedback() hook beside cellText/copyText in cells.ts that performs
copying, tracks the copied key/value, and manages a single timeout cleanup; then
replace copyCell and its local copied state in
database/ui/src/page/result-grid.tsx#L139-L145 and copyValue and its local
copied state in database/ui/src/page/RowDetail.tsx#L26-L32 with the hook.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@database/ui/src/page/index.tsx`:
- Around line 89-94: Update the subtitle rendering around activeDb?.url so the
fallback is gated on whether activeDb exists, not whether its optional url is
truthy: show the configured database state when activeDb is present without a
URL, and retain the worker-not-connected and no-database-configured messages for
the appropriate absent-database cases.
- Around line 206-207: Update the SqlPanel key in the active database rendering
to use only activeDb.name, removing bump from the key so refreshes reload
metadata without remounting SqlPanel or resetting its in-progress SQL editor
state.
- Around line 235-240: Export the existing quoteTableRef helper from db-data.ts
and update the onOpenInSql handler to use quoteTableRef(activeDb.driver, table)
when constructing seed SQL. Keep quoteIdent for single identifiers, but ensure
schema-qualified PostgreSQL table names are quoted component-wise.

In `@database/ui/src/page/result-grid.tsx`:
- Around line 222-227: Update the row rendering in the result-grid table around
the onRowClick handler so clickable rows are focusable and expose appropriate
row semantics, and add keyboard activation for Enter and Space that invokes
onRowClick with the same index as mouse clicks. Preserve non-clickable row
behavior and avoid triggering activation for unrelated keys.

In `@database/ui/src/page/SqlPanel.tsx`:
- Around line 126-130: Update the history state update in the setHistory
callback to enforce HISTORY_LIMIT before returning the list, while continuing to
persist the same bounded history through saveHistory. Ensure both component
state and storage retain only the most recent entries after deduplication.
- Line 109: Update the history state flow in SqlPanel around the history
useState initializer so it reloads from loadHistory(db) whenever the selected db
changes, replacing stale entries from the previous database and preserving the
existing database-keyed persistence behavior.

---

Nitpick comments:
In `@database/ui/src/page/result-grid.tsx`:
- Around line 240-254: Update the cell rendering in the result-grid component so
copyCell remains reachable when onRowClick is provided, preserving row-click
behavior while adding a separate copy trigger such as double-click or a hover
control; alternatively revise the file header to accurately document the two
interaction modes. Ensure the implemented behavior matches the chosen
documentation and does not leave copied state unreachable.
- Around line 139-145: The copy-feedback behavior is duplicated across both
components. Add a shared useCopyFeedback() hook beside cellText/copyText in
cells.ts that performs copying, tracks the copied key/value, and manages a
single timeout cleanup; then replace copyCell and its local copied state in
database/ui/src/page/result-grid.tsx#L139-L145 and copyValue and its local
copied state in database/ui/src/page/RowDetail.tsx#L26-L32 with the hook.

In `@database/ui/src/page/SchemaTree.tsx`:
- Around line 65-82: Update the schema-loading guard in the expansion logic
around tableColumns and tableIndexes so loading starts when
schemaByTable[table.name] is undefined or 'error'. Preserve the existing
loading, success, and error state transitions so re-expanding a failed table
retries the request.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4551f869-81b9-488b-89e1-63129bf49892

📥 Commits

Reviewing files that changed from the base of the PR and between bbb1442 and e0416aa.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • console/web/src/components/ui/CodeEditor.tsx
  • database/ui/package.json
  • database/ui/page.tsx
  • database/ui/src/page/RowDetail.tsx
  • database/ui/src/page/SchemaTree.tsx
  • database/ui/src/page/SqlPanel.tsx
  • database/ui/src/page/TableDataPanel.tsx
  • database/ui/src/page/cells.ts
  • database/ui/src/page/db-data.ts
  • database/ui/src/page/icons.tsx
  • database/ui/src/page/index.tsx
  • database/ui/src/page/page-styles.ts
  • database/ui/src/page/pagination.tsx
  • database/ui/src/page/result-grid.tsx
  • database/ui/src/page/useDatabaseRead.ts
  • packages/console-ui/index.d.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/console-ui/index.d.ts
  • console/web/src/components/ui/CodeEditor.tsx

Comment thread database/ui/src/page/index.tsx Outdated
Comment thread database/ui/src/page/index.tsx Outdated
Comment thread database/ui/src/page/index.tsx
Comment thread database/ui/src/page/result-grid.tsx
const [running, setRunning] = useState(false)
const [error, setError] = useState<string | null>(null)
const [outcome, setOutcome] = useState<AdhocResult | null>(null)
const [history, setHistory] = useState<string[]>(() => loadHistory(db))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reload history when the selected database changes.

Line 109 only loads history on mount. After a db switch, entries from the previous database remain in state and are subsequently saved under the new database’s key.

Proposed fix
+  useEffect(() => {
+    setHistory(loadHistory(db))
+    setHistoryOpen(false)
+  }, [db])
📝 Committable suggestion

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

Suggested change
const [history, setHistory] = useState<string[]>(() => loadHistory(db))
const [history, setHistory] = useState<string[]>(() => loadHistory(db))
useEffect(() => {
setHistory(loadHistory(db))
setHistoryOpen(false)
}, [db])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@database/ui/src/page/SqlPanel.tsx` at line 109, Update the history state flow
in SqlPanel around the history useState initializer so it reloads from
loadHistory(db) whenever the selected db changes, replacing stale entries from
the previous database and preserving the existing database-keyed persistence
behavior.

Comment thread database/ui/src/page/SqlPanel.tsx
- Subtitle: a database configured without a `url` no longer reads "no
  database configured"; it falls back to the database name, and the
  worker-unavailable / nothing-configured copy stays for the absent cases.
- SQL panel is keyed by database only, so a refresh reloads metadata
  instead of remounting the editor and discarding an in-progress
  statement and its results.
- "open in sql" seeds through quoteTableRef, so a schema-qualified
  postgres table quotes component-wise instead of becoming one
  identifier.
- Selectable grid rows are tabbable and activate on Enter/Space, matching
  the click path; non-clickable rows are unchanged.
- SQL history state is bounded by HISTORY_LIMIT, matching what is
  persisted.
- Re-expanding a table whose schema read failed retries instead of
  staying on the error row forever.
- Copy feedback moves into a shared useCopyFeedback hook that cancels its
  pending timer on unmount, replacing the duplicate implementations in
  the grid and the row inspector.
@rohitg00
rohitg00 merged commit 8e096ca into main Jul 27, 2026
20 checks passed
@rohitg00
rohitg00 deleted the feat/codeeditor-completions branch July 27, 2026 09:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-ticket PR deliberately has no Linear ticket (bump/typo/CI-only)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant