Skip to content

fix(connectors): connectors polish bundle (#1043) - #1080

Merged
alfredo1996 merged 4 commits into
release/1.1from
fix/issue-1043-connectors-polish
Jun 13, 2026
Merged

fix(connectors): connectors polish bundle (#1043)#1080
alfredo1996 merged 4 commits into
release/1.1from
fix/issue-1043-connectors-polish

Conversation

@alfredo1996

@alfredo1996 alfredo1996 commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Closes #1043

Dogfood session 2 (#895) P2 connectors polish bundle — one change per checklist item.

Changes

  • Actionable connection-test errors — the [id]/test route now classifies thrown driver errors (mirrors test-inline), and both routes replace the dead-end "Connection check returned false" with an actionable message + code when the check returns false without throwing.
  • Write-in-preview errors — new mapPreviewError maps blocked-write driver errors (pg wrapped-write syntax error at or near "DELETE", Neo4j "Writing in read access mode not allowed", read-only transaction) to a clear "Writes aren't allowed from widget queries" message in the preview panel.
  • Rename connections — edit dialog gains a Name field; rename persists via the existing PATCH (name) and fires a "Connection updated" toast.
  • Create-form validation — form is noValidate and reports all missing required fields at once (extracted missingRequiredConnectionFields) instead of native one-at-a-time tooltips.
  • Client URI validationvalidateConnectionUri blocks save of a malformed URI (e.g. not-a-uri) on create and edit with an inline error, before it can persist as an Error-badge connection.
  • Preview limit hint — "Preview shows up to 25 rows" surfaces the silent LIMIT.
  • Per-type icons — connections list renders distinct Neo4j / PostgreSQL logos via a new optional ConnectionCard icon prop (app passes the asset; the library stays asset-free).

Item 7 (stale Cypher query auto-running against a PostgreSQL connection after a switch) was already prevented: handleConnectionChange calls clearQueryState() on connector-type change, so a cross-language query can't survive a switch. No code change — verified, not fabricated.

Tests

  • Unit: classifyConnectionError boolean-false + thrown-error classification (both test routes); mapPreviewError (pg/Neo4j/read-only/negatives); validateConnectionUri; missingRequiredConnectionFields. PATCH-name rename already covered.
  • Component (jsdom): ConnectionCard renders a custom connector-type icon.
  • E2E: edit-dialog rename + toast; malformed-URI blocks save with inline error. Existing connections (14) + dashboard-states (12, exercises the preview panel) all green.

All app (169) + component unit suites, tsc, and root lint green.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added form validation for connections with required field checks and URI format validation.
    • Connection cards now display connector-specific icons.
    • Enhanced connection test error messages with actionable guidance for host, port, and credential verification.
  • Bug Fixes

    • Connection updates now display confirmation toast notifications.
    • Malformed URIs keep dialogs open with inline validation errors.
    • Improved error classification for connection test failures.
  • Tests

    • Added comprehensive test coverage for connection form validation and URI validation.

alfredorubin96 and others added 2 commits June 13, 2026 23:41
…1043 items 1,5)

- Route the boolean-false connection check and the [id]/test catch path
  through classifyConnectionError; replace the dead-end 'Connection check
  returned false' with an actionable message + code.
- Add mapPreviewError: map blocked-write driver errors (pg wrapped-write
  syntax error, Neo4j read-access-mode, read-only transaction) to a clear
  'Writes aren't allowed from widget queries' message in the preview panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s 2,3,4,6,8,9)

- Edit dialog gains a Name field; rename persists via the existing PATCH
  (name) and fires a 'Connection updated' toast.
- Create form is noValidate and reports all missing required fields at
  once (extracted missingRequiredConnectionFields) instead of native
  one-at-a-time tooltips.
- Client-side URI format validation (validateConnectionUri) blocks save
  of malformed URIs on both create and edit, with an inline error.
- Preview panel shows a 'Preview shows up to 25 rows' hint so the silent
  LIMIT is visible.
- Connections list renders a distinct Neo4j / PostgreSQL logo via a new
  optional ConnectionCard `icon` prop (app passes the asset; library
  stays asset-free).

Item 7 (stale-query auto-run on connection switch) was already prevented
by clearQueryState on connector-type change — no code change needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@alfredo1996, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 47 minutes and 8 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a79c6181-103d-4a08-b960-f087a1abf662

📥 Commits

Reviewing files that changed from the base of the PR and between 33b07bc and 0d3bb7e.

📒 Files selected for processing (1)
  • app/src/app/(dashboard)/connections/page.tsx

Walkthrough

This PR implements a comprehensive set of improvements to connection management, addressing validation, error messaging, UI/UX polish, and renaming support. Client-side form and URI validation are added to prevent invalid connections from being saved, shared error-classification helpers standardize test-route responses, and the connections UI gains rename support, connector-specific icons, toast confirmations, and improved preview error messaging for write-attempt detection.

Changes

Connections Polish & Validation

Layer / File(s) Summary
Connection validation helpers and test contracts
app/src/lib/connector/connection-error-classifier.ts, app/src/lib/connector/connection-form-validation.ts, app/src/lib/connector/connection-test-result.ts, app/src/lib/connector/validate-connection-uri.ts, app/src/lib/connector/__tests__/*
New missingRequiredConnectionFields() checks for blank/whitespace name, URI, username, password. New validateConnectionUri() parses URI, enforces host presence, and validates protocol scheme against connector type (neo4j vs postgresql). New ConnectionTestResult interface and factories connectionCheckFalseResult() and connectionTestErrorResult() standardize error response shapes. CONNECTION_CHECK_FALSE_MESSAGE provides actionable guidance to verify host/port/credentials. Comprehensive unit tests cover all validation paths and error classification scenarios.
Connection test routes refactored to use shared result helpers
app/src/app/api/connections/[id]/test/route.ts, app/src/app/api/connections/test-inline/route.ts, app/src/app/api/connections/[id]/test/__tests__/route.test.ts, app/src/app/api/connections/test-inline/__tests__/route.test.ts
Both /connections/[id]/test and /connections/test-inline now use shared connectionCheckFalseResult() and connectionTestErrorResult() helpers to produce consistent error classifications and messages. Imports cleaned up to remove duplicate error-handling logic. Tests expanded to assert code values (network, auth_failed, unknown) and verify actionable error messages replace the previous opaque "Connection check returned false" text.
Preview error mapping for write-attempt detection
app/src/lib/query/preview-error.ts, app/src/lib/query/__tests__/preview-error.test.ts, app/src/components/widget-editor/widget-preview-panel.tsx
New mapPreviewError() detects blocked write attempts (PostgreSQL wrapped-write syntax containing DELETE/UPDATE/INSERT, Neo4j read-access phrases) and maps them to "Writes aren't allowed" instead of the confusing wrapper error. Widget preview panel uses the mapping to choose "Writes not allowed" vs "Query failed" heading and displays mapped message. Success render now appends "Preview shows up to 25 rows" footer hint. Tests cover Neo4j/PostgreSQL write patterns and non-write error pass-through.
ConnectionCard icon prop for type differentiation
component/src/components/composed/connection-card.tsx, component/src/components/composed/__tests__/connection-card.test.tsx
ConnectionCardProps accepts optional icon: ReactNode for custom connector icons. Component renders provided icon or falls back to generic Database icon. Tests verify custom icon rendering, actions dropdown presence/absence by handler availability, and "Duplicate" menu item visibility.
Connections page: form validation, rename support, icons, toast
app/src/app/(dashboard)/connections/page.tsx
Create dialog validates all required fields at once and URI format before submit; edit dialog enforces non-empty trimmed name and validates URI format when non-blank. Both disable native browser validation (noValidate) in favor of inline error display. Edit dialog now includes explicit "Name" input field enabling connection renaming. ConnectionCard renders connector-specific icons (Neo4j or PostgreSQL logo) instead of generic icon. Successful edit emits "Connection updated" toast before test/refetch. All validation failures block submission and show actionable error inline.
End-to-end tests: rename and URI validation
app/e2e/connections.spec.ts
New test verifies creating a Neo4j connection, opening edit dialog, renaming, saving, and observing "Connection updated" toast and updated card name. New test verifies attempting to save malformed URI keeps dialog open and renders inline validation error without creating the connection.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • alfredo1996/neoboard#941: Modifies PostgreSQL checkConnection to throw instead of returning false, which alters the error path exercised by the refactored test result helpers in this PR.
  • alfredo1996/neoboard#594: Refactors widget-preview-panel.tsx preview rendering into helper functions; this PR adds error mapping and capped-row footer to the same component.

Suggested labels

enhancement, pkg:app, pkg:connection, pkg:component, area:connectors, testing

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% 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 'fix(connectors): connectors polish bundle (#1043)' directly references the issue being closed and accurately summarizes the primary change: a cohesive polish bundle addressing multiple connector UI/UX improvements.
Linked Issues check ✅ Passed All nine required fixes from #1043 are implemented: actionable connection-test errors via classifyConnectionError, rename support with toast, all-fields-at-once validation, client URI validation, write-error mapping via mapPreviewError, preview-limit hint, connection-switch behavior verified as already handled, per-type icons via ConnectionCard icon prop, and toast on edit save.
Out of Scope Changes check ✅ Passed All code changes directly support the nine requirements in #1043; no unrelated modifications detected. Test infrastructure additions (Vitest suites, E2E cases, component tests) are within scope as required by the issue.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-1043-connectors-polish

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.

…1043)

SonarCloud flagged 4.3% duplication on new code: the [id]/test and
test-inline routes had near-identical false/catch handling. Extract
connectionCheckFalseResult + connectionTestErrorResult so both routes
build the result identically, with a direct unit test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

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

🧹 Nitpick comments (4)
app/src/components/widget-editor/widget-preview-panel.tsx (1)

168-182: 💤 Low value

Error mapping logic is correct; IIFE is slightly less readable.

The code correctly maps preview errors via mapPreviewError, displays "Writes not allowed" for blocked-write attempts, and falls back to "Query failed" with the raw message otherwise. Optional chaining on line 170 safely handles null errors.

The IIFE pattern works but extracting writeMsg before the return (e.g., const writeMsg = mapPreviewError(previewQuery.error?.message);) would be marginally clearer. Not a blocker.

🤖 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 `@app/src/components/widget-editor/widget-preview-panel.tsx` around lines 168 -
182, Extract the IIFE result into a local variable for clarity: call
mapPreviewError(previewQuery.error?.message) once at the top of the component
(e.g., const writeMsg = mapPreviewError(previewQuery.error?.message);) and then
replace the immediately-invoked function expression with the JSX that uses
writeMsg (the AlertCircle block that shows the title {writeMsg ? "Writes not
allowed" : "Query failed"} and the message {writeMsg ??
previewQuery.error?.message}). This preserves the existing logic and optional
chaining but removes the IIFE for improved readability.
app/src/lib/query/preview-error.ts (2)

32-38: ⚡ Quick win

The phrase "cannot execute" might be too broad and could match non-write errors.

Line 37 includes "cannot execute" to catch PostgreSQL read-only transaction errors like "cannot execute DELETE in a read-only transaction" (verified by the test on line 31). However, this phrase is generic and could match unrelated errors such as "cannot execute query: connection timeout" or "cannot execute query due to insufficient permissions", incorrectly mapping them to the write-not-allowed message.

If false positives become an issue, consider narrowing the phrase to "in a read-only transaction" or matching the full pattern "cannot execute .* in a read-only transaction".

🤖 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 `@app/src/lib/query/preview-error.ts` around lines 32 - 38, The
READ_ONLY_PHRASES entry "cannot execute" is too broad and causes false
positives; narrow it to target read-only transaction messages by replacing that
entry with either the specific substring "in a read-only transaction" or a regex
pattern like "cannot execute .* in a read-only transaction" and update the
lookup logic that matches READ_ONLY_PHRASES (wherever READ_ONLY_PHRASES is used)
to support regex matching if you choose the pattern approach so only messages
explicitly about read-only transactions are caught.

19-30: 💤 Low value

Trailing spaces on "set " and "remove " are trimmed away and provide no precision benefit.

Lines 28-29 include trailing spaces on "set " and "remove ", likely to avoid false matches. However, the regex on line 42 captures [a-z]+ (no spaces), and line 44 applies .trim() to each keyword before comparison, so the trailing spaces are discarded. The intent might have been to distinguish SET (session config) from data writes, but the trim removes that distinction.

Additionally, SET in PostgreSQL is typically a session-level command (SET search_path = ...), not a data write. Wrapping it triggers a syntax error, but mapping it to "Writes aren't allowed" could be misleading since it's config, not data mutation.

Consider either removing the trailing spaces for clarity or being more specific about which SET/REMOVE patterns constitute writes.

🤖 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 `@app/src/lib/query/preview-error.ts` around lines 19 - 30, The WRITE_KEYWORDS
array contains entries "set " and "remove " whose trailing spaces are discarded
by the existing regex capture ([a-z]+) and the subsequent .trim(), so remove the
trailing spaces and make the match precise: update WRITE_KEYWORDS to use "set"
and "remove" (no trailing spaces) and tighten the keyword extraction regex to
use word boundaries (e.g., \b([a-z]+)\b) so keywords are matched as whole words;
leave the existing .trim() in place or remove it if you rely on the
word-boundary regex.
app/src/lib/query/__tests__/preview-error.test.ts (1)

7-47: ⚡ Quick win

Test coverage is solid for the main cases.

The suite covers the primary scenarios: PostgreSQL wrapped-write syntax errors (DELETE/UPDATE/INSERT), Neo4j read-access violations, PostgreSQL read-only transaction errors, and appropriate null returns for non-write and empty inputs.

For completeness, consider adding assertions for the other WRITE_KEYWORDS (MERGE, CREATE, DROP, ALTER, TRUNCATE, SET, REMOVE) and READ_ONLY_PHRASES ("write operations are not allowed", "read-only transaction", "read only transaction"). Not critical since the logic is straightforward, but broader coverage would guard against future regressions.

🤖 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 `@app/src/lib/query/__tests__/preview-error.test.ts` around lines 7 - 47, Add
tests to preview-error.test.ts to assert that mapPreviewError returns
PREVIEW_WRITE_NOT_ALLOWED_MESSAGE for the remaining WRITE_KEYWORDS (MERGE,
CREATE, DROP, ALTER, TRUNCATE, SET, REMOVE) and for additional read-only phrases
from READ_ONLY_PHRASES such as "write operations are not allowed", "read-only
transaction", and "read only transaction"; keep using the same test style as
existing cases (call mapPreviewError with the phrase and expect
PREVIEW_WRITE_NOT_ALLOWED_MESSAGE) and reference the existing symbols
mapPreviewError and PREVIEW_WRITE_NOT_ALLOWED_MESSAGE so the test suite covers
these extra inputs.
🤖 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 `@app/src/app/`(dashboard)/connections/page.tsx:
- Around line 415-427: The validation and payload assembly use raw editForm
fields so whitespace-only values can be treated as truthy and overwrite stored
creds; before validating or building the PATCH payload, normalize (trim)
editForm.name, editForm.uri, editForm.username and editForm.password and use
those trimmed values for the checks and for buildEditConfig() so "blank keeps
existing" behavior is preserved—specifically, replace truthiness checks on
editForm.uri/username/password with checks on their trimmed counterparts, pass
the trimmed values into validateConnectionUri(editForm.uri, editTarget.type) and
into buildEditConfig() (or have buildEditConfig accept/derive trimmed values) so
whitespace-only inputs are ignored and not sent.

---

Nitpick comments:
In `@app/src/components/widget-editor/widget-preview-panel.tsx`:
- Around line 168-182: Extract the IIFE result into a local variable for
clarity: call mapPreviewError(previewQuery.error?.message) once at the top of
the component (e.g., const writeMsg =
mapPreviewError(previewQuery.error?.message);) and then replace the
immediately-invoked function expression with the JSX that uses writeMsg (the
AlertCircle block that shows the title {writeMsg ? "Writes not allowed" : "Query
failed"} and the message {writeMsg ?? previewQuery.error?.message}). This
preserves the existing logic and optional chaining but removes the IIFE for
improved readability.

In `@app/src/lib/query/__tests__/preview-error.test.ts`:
- Around line 7-47: Add tests to preview-error.test.ts to assert that
mapPreviewError returns PREVIEW_WRITE_NOT_ALLOWED_MESSAGE for the remaining
WRITE_KEYWORDS (MERGE, CREATE, DROP, ALTER, TRUNCATE, SET, REMOVE) and for
additional read-only phrases from READ_ONLY_PHRASES such as "write operations
are not allowed", "read-only transaction", and "read only transaction"; keep
using the same test style as existing cases (call mapPreviewError with the
phrase and expect PREVIEW_WRITE_NOT_ALLOWED_MESSAGE) and reference the existing
symbols mapPreviewError and PREVIEW_WRITE_NOT_ALLOWED_MESSAGE so the test suite
covers these extra inputs.

In `@app/src/lib/query/preview-error.ts`:
- Around line 32-38: The READ_ONLY_PHRASES entry "cannot execute" is too broad
and causes false positives; narrow it to target read-only transaction messages
by replacing that entry with either the specific substring "in a read-only
transaction" or a regex pattern like "cannot execute .* in a read-only
transaction" and update the lookup logic that matches READ_ONLY_PHRASES
(wherever READ_ONLY_PHRASES is used) to support regex matching if you choose the
pattern approach so only messages explicitly about read-only transactions are
caught.
- Around line 19-30: The WRITE_KEYWORDS array contains entries "set " and
"remove " whose trailing spaces are discarded by the existing regex capture
([a-z]+) and the subsequent .trim(), so remove the trailing spaces and make the
match precise: update WRITE_KEYWORDS to use "set" and "remove" (no trailing
spaces) and tighten the keyword extraction regex to use word boundaries (e.g.,
\b([a-z]+)\b) so keywords are matched as whole words; leave the existing .trim()
in place or remove it if you rely on the word-boundary regex.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7db1ffb9-7fa1-4353-8d6f-add15005d6b2

📥 Commits

Reviewing files that changed from the base of the PR and between 8948b67 and 33b07bc.

📒 Files selected for processing (18)
  • app/e2e/connections.spec.ts
  • app/src/app/(dashboard)/connections/page.tsx
  • app/src/app/api/connections/[id]/test/__tests__/route.test.ts
  • app/src/app/api/connections/[id]/test/route.ts
  • app/src/app/api/connections/test-inline/__tests__/route.test.ts
  • app/src/app/api/connections/test-inline/route.ts
  • app/src/components/widget-editor/widget-preview-panel.tsx
  • app/src/lib/connector/__tests__/connection-form-validation.test.ts
  • app/src/lib/connector/__tests__/connection-test-result.test.ts
  • app/src/lib/connector/__tests__/validate-connection-uri.test.ts
  • app/src/lib/connector/connection-error-classifier.ts
  • app/src/lib/connector/connection-form-validation.ts
  • app/src/lib/connector/connection-test-result.ts
  • app/src/lib/connector/validate-connection-uri.ts
  • app/src/lib/query/__tests__/preview-error.test.ts
  • app/src/lib/query/preview-error.ts
  • component/src/components/composed/__tests__/connection-card.test.tsx
  • component/src/components/composed/connection-card.tsx

Comment thread app/src/app/(dashboard)/connections/page.tsx
Address CodeRabbit: with the form now noValidate, whitespace-only
uri/username/password were truthy and could overwrite stored credentials
with blanks. Gate buildEditConfig inclusion on the trimmed value so
'blank keeps existing' holds for whitespace-only input too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@alfredo1996
alfredo1996 merged commit 6da1f14 into release/1.1 Jun 13, 2026
15 checks passed
@alfredo1996
alfredo1996 deleted the fix/issue-1043-connectors-polish branch June 13, 2026 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants