Skip to content

FIX: Connection Name and Description Losing Last Character When Editing#57

Merged
wicky-zipstack merged 12 commits intomainfrom
fix/connection-name-description-edit-losing-last-character
Apr 15, 2026
Merged

FIX: Connection Name and Description Losing Last Character When Editing#57
wicky-zipstack merged 12 commits intomainfrom
fix/connection-name-description-edit-losing-last-character

Conversation

@tahierhussain
Copy link
Copy Markdown
Contributor

@tahierhussain tahierhussain commented Apr 13, 2026

What

  • Fixed a bug where editing the connection name or description would lose the last character
  • Example: Changing "test_pg" to "test_pg_edited" would save as "test_pg_edite"

Why

  • The issue was caused by:
    1. Using controlled inputs (value prop) that conflicted with Ant Design Form's internal state management
    2. The getValueFromEvent prop on Form.Item interfering with the onChange flow

How

  • CreateConnection.jsx:

    • Added Form.useForm() hook to create form instance and pass it to child
    • Read name/description directly from form using connectionDetailsForm.getFieldsValue() in submit handler
    • Used Form.useWatch to reactively track form values for hasDetailsChanged comparison
  • ConnectionDetailsSection.jsx:

    • Replaced controlled inputs with Ant Design's Form-managed inputs using name prop
    • Receive form instance from parent instead of creating own
    • Used form.setFieldsValue() to populate fields when editing existing connections
    • Removed problematic getValueFromEvent prop
    • Added normalize={collapseSpaces} on name field for space collapsing

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No, this PR should not break existing features
  • The form behavior remains the same from a user perspective
  • The changes only affect the internal state management pattern
  • Creating new connections still works as before
  • Editing existing connections now correctly preserves all characters

Database Migrations

  • None

Env Config

  • None

Relevant Docs

Related Issues or PRs

  • None

Dependencies Versions

  • No new dependencies

Notes on Testing

  1. Edit an existing connection
  2. Modify the name field (e.g., add "_edited" suffix)
  3. Click Update
  4. Verify the full name is saved correctly (no missing characters)
  5. Test the same for the description field
  6. Test creating a new connection to ensure it still works

Screenshots

The "name" field value modified but yet to click on the "Update" button
image

After clicking on the "Update" button
image

Checklist

I have read and understood the Contribution Guidelines.

tahierhussain and others added 2 commits April 13, 2026 21:01
- Replace controlled inputs (value prop) with Form-managed inputs (name prop)
- Use Form.useForm() hook and form.setFieldsValue() to set values when
  editing existing connections
- Remove getValueFromEvent which conflicted with controlled input pattern
- Move collapseSpaces transformation to onChange handler

This fixes the issue where the form fields wouldn't properly display
values when editing existing connections.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add debounced state update for name and description fields (300ms)
- Prevents the handleCreateOrUpdate callback from capturing stale
  dbSelectionInfo values during rapid typing
- Ensures the last character is not lost when updating a connection

This fixes the bug where editing connection name from "test_pg" to
"test_pg_edited" would save as "test_pg_edite" (missing last character).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@tahierhussain tahierhussain self-assigned this Apr 13, 2026
@tahierhussain tahierhussain requested a review from a team as a code owner April 13, 2026 15:38
@tahierhussain tahierhussain added the bug Something isn't working label Apr 13, 2026
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 13, 2026

Greptile Summary

This PR fixes the last-character-loss bug when editing connection name/description by replacing React-controlled inputs with Ant Design Form-managed fields (name prop + Form.useForm()), reading values via getFieldsValue() at submit time, and using Form.useWatch for reactive hasDetailsChanged comparison. The approach is correct and the root causes described in the PR are fully resolved.

Confidence Score: 5/5

Safe to merge; both findings are P2 quality-of-life improvements, not blockers.

The core bug is correctly fixed. Remaining findings are: a missing validateFields() call (pre-existing gap, doesn't regress behavior) and a one-render flash in hasDetailsChanged when loading (cosmetic, self-corrects). Neither blocks correctness of the primary fix.

CreateConnection.jsx — minor issues with submit validation and hasDetailsChanged initial state.

Important Files Changed

Filename Overview
frontend/src/base/components/environment/ConnectionDetailsSection.jsx Migrated from controlled inputs with manual onChange/value to AntD Form-managed fields using name prop and normalize; receives form instance from parent and uses setFieldsValue via useEffect to seed values on load.
frontend/src/base/components/environment/CreateConnection.jsx Creates shared form instance with Form.useForm(), reads name/description via getFieldsValue() on submit, and uses Form.useWatch for reactive hasDetailsChanged; two P2 issues: missing validateFields() before submit, and a one-render undefined flash in hasDetailsChanged when loading.

Sequence Diagram

sequenceDiagram
    participant U as User
    participant CC as CreateConnection
    participant CDS as ConnectionDetailsSection
    participant ADF as AntD Form (shared instance)
    participant API as Backend API

    Note over CC,ADF: Form.useForm() creates shared instance

    CC->>API: fetchSingleConnection(connectionId)
    API-->>CC: { name, description, ... }
    CC->>CC: setDbSelectionInfo / setOriginalDbSelectionInfo

    CC->>CDS: pass connectionDetailsForm instance
    CDS->>ADF: setFieldsValue({ name, description }) via useEffect
    ADF-->>CC: Form.useWatch → formName, formDescription updated

    U->>ADF: types in Name field
    ADF->>CC: Form.useWatch → formName updates → hasDetailsChanged recalculated

    U->>CC: clicks Update
    CC->>ADF: getFieldsValue() → { name, description }
    CC->>API: updateConnectionApi({ ...dbSelectionInfo, name, description, ... })
    API-->>CC: success
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: frontend/src/base/components/environment/CreateConnection.jsx
Line: 128-132

Comment:
**Validation rules bypassed on submit**

`getFieldsValue()` returns the current field values without triggering the form's validation rules. The `required` rule and `validateFormFieldName` validator on the `name` field will not block submission of an empty or invalid name — users can submit a blank connection name and the API call will proceed.

Since `Form.Item` now has a `name` prop and is wired to `connectionDetailsForm`, a simple `await connectionDetailsForm.validateFields()` call before reading values would enforce all declared rules and surface errors inline.

```suggestion
  const handleCreateOrUpdate = useCallback(async () => {
    setIsCreateOrUpdateLoading(true);
    try {
      // Validate fields first, then read values
      const { name, description } = await connectionDetailsForm.validateFields();
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: frontend/src/base/components/environment/CreateConnection.jsx
Line: 411-417

Comment:
**One-render flash where `hasDetailsChanged` is incorrectly `true`**

When `getSingleConnectionDetails` resolves, `setOriginalDbSelectionInfo` is called synchronously (in the same state batch). At that point `originalDbSelectionInfo` is no longer `null`, but `formName`/`formDescription` are still `undefined``setFieldsValue` hasn't run yet because it lives in `ConnectionDetailsSection`'s `useEffect`, which fires *after* the render caused by the state update. For that one render cycle, `formName !== originalDbSelectionInfo.name` evaluates to `undefined !== "test_pg"``true`, so any UI driven by `hasDetailsChanged` briefly shows the wrong state.

A guard for `undefined` removes the flicker:

```suggestion
  const hasDetailsChanged = useMemo(() => {
    if (!connectionId || !originalDbSelectionInfo) return false;
    if (formName === undefined && formDescription === undefined) return false;
    return (
      formName !== originalDbSelectionInfo.name ||
      formDescription !== originalDbSelectionInfo.description
    );
  }, [connectionId, formName, formDescription, originalDbSelectionInfo]);
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (10): Last reviewed commit: "fix: add hasDetailsChanged to deps and n..." | Re-trigger Greptile

tahierhussain and others added 7 commits April 13, 2026 21:30
The debounce was introduced to fix stale closure issues, but it
actually creates a worse bug - a 300ms window where clicking Update
could submit pre-edit values.

The root cause is already fixed in ConnectionDetailsSection.jsx by
using Ant Design's Form pattern (Form.useForm + form.setFieldsValue).
With uncontrolled inputs, the direct state update works correctly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Debounce the handleConnectionNameDesc callback (300ms) to ensure the
parent's handleCreateOrUpdate closure captures the latest state value.

The form input remains responsive since Ant Design manages the input
internally, while the parent state update is debounced.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Update form value synchronously with collapsed spaces so the validator
always sees the processed value, preventing spurious validation errors
when consecutive spaces are typed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Change useEffect dependency from dbSelectionInfo fields to connectionId
to prevent form values from being overwritten during typing due to
debounced state updates.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Restore debounce for parent state updates
- Add isUserEditingRef to track when user is actively editing
- Only populate form values when not in editing mode
- Reset editing flag when connectionId changes (new connection loaded)

This ensures:
1. Form populates correctly when async connection data arrives
2. User edits are not overwritten by the useEffect
3. Parent state updates are debounced to prevent stale closure issues

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Replace manual form.setFieldValue with normalize prop on Form.Item.
This ensures collapseSpaces is applied before storage and validation,
preventing false validation errors when consecutive spaces are typed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
setFieldsValue bypasses the normalize prop, so apply collapseSpaces
manually when loading connection data to ensure consistent formatting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@wicky-zipstack wicky-zipstack left a comment

Choose a reason for hiding this comment

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

Good fix for the root cause — switching to Ant Design's Form pattern (Form.useForm + name prop + normalize) is the right approach.

One concern — debounce race condition:

The 300ms debounce on debouncedHandleConnectionNameDesc means if a user types and clicks "Update" within 300ms, dbSelectionInfo in the parent still has the old value. Since handleCreateOrUpdate reads from dbSelectionInfo, the last few characters could still be lost — which is essentially the same bug with a different timing window.

Two options to fix:

  1. Flush on submit — call debouncedHandleConnectionNameDesc.flush() at the start of handleCreateOrUpdate in CreateConnection.jsx
  2. Read from form directly — use form.getFieldsValue() in the submit handler instead of relying on dbSelectionInfo for name/description

Option 2 would be cleaner since the form already has the correct value at all times.

tahierhussain and others added 3 commits April 15, 2026 10:45
- Move Form.useForm() to CreateConnection.jsx and pass form as prop
- Remove debounce logic from ConnectionDetailsSection (no longer needed)
- Read name/description directly from form in handleCreateOrUpdate
- Use Form.useWatch to reactively track form values for hasDetailsChanged
- This eliminates the race condition and fixes Update button not enabling

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add hasDetailsChanged to handleCreateOrUpdate dependency array to fix
  stale closure issue
- Apply collapseSpaces when storing originalDbSelectionInfo.name to
  ensure consistent comparison with form values

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@tahierhussain
Copy link
Copy Markdown
Contributor Author

Good fix for the root cause — switching to Ant Design's Form pattern (Form.useForm + name prop + normalize) is the right approach.

One concern — debounce race condition:

The 300ms debounce on debouncedHandleConnectionNameDesc means if a user types and clicks "Update" within 300ms, dbSelectionInfo in the parent still has the old value. Since handleCreateOrUpdate reads from dbSelectionInfo, the last few characters could still be lost — which is essentially the same bug with a different timing window.

Two options to fix:

  1. Flush on submit — call debouncedHandleConnectionNameDesc.flush() at the start of handleCreateOrUpdate in CreateConnection.jsx
  2. Read from form directly — use form.getFieldsValue() in the submit handler instead of relying on dbSelectionInfo for name/description

Option 2 would be cleaner since the form already has the correct value at all times.

@wicky-zipstack Done. I went with Option 2.

The submit handler now reads directly from the form using connectionDetailsForm.getFieldsValue(), so the race condition is no longer an issue. I also removed the debounce entirely, since the form is now the source of truth.

For hasDetailsChanged, we now use Form.useWatch to reactively track form values for the comparison.

Thanks for the suggestion!

Copy link
Copy Markdown
Contributor

@wicky-zipstack wicky-zipstack left a comment

Choose a reason for hiding this comment

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

LGTM

@wicky-zipstack wicky-zipstack merged commit de058f9 into main Apr 15, 2026
8 checks passed
@wicky-zipstack wicky-zipstack deleted the fix/connection-name-description-edit-losing-last-character branch April 15, 2026 06:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants