Skip to content

refactor(frontend): decompose DBProvidersPage into components hooks and helpers#14049

Open
tarciorodrigues wants to merge 8 commits into
release-1.11.0from
refactor/le-1735-wp2
Open

refactor(frontend): decompose DBProvidersPage into components hooks and helpers#14049
tarciorodrigues wants to merge 8 commits into
release-1.11.0from
refactor/le-1735-wp2

Conversation

@tarciorodrigues

@tarciorodrigues tarciorodrigues commented Jul 13, 2026

Copy link
Copy Markdown
Member

Why

LE-1735 Tier A componentization — work package 2. DBProvidersPage/index.tsx was an 866-line monolith mixing the provider list, the configuration panel, field rows, a pure payload builder, variable persistence, field-value resolution and the save/test/activate flows — with zero test coverage. This PR decomposes it into named files, behavior-preserving, with a characterization suite pinned before any move.

What

  • First commit adds a characterization suite (11 tests) written against the untouched file: provider list order and badges, active-provider resolution from LANGFLOW_KNOWLEDGE_BACKEND, chroma panel state, required-field gating of Save and Test connection, masked-secret hydration, POST vs PATCH persistence including Credential typing and provider activation, and the coming-soon stub.
  • Then seven verbatim extractions, one commit each, all validated against that suite: components/ProviderListItem.tsx, components/TextFieldRow.tsx + components/BooleanFieldRow.tsx (carrying MASKED_VALUE with its only consumer), components/ProviderConfigurationPanel.tsx, helpers/build-backend-config-payload.ts, hooks/useDBProviderVariables.ts, hooks/useDBProviderFields.ts and hooks/useDBProviderActions.ts.
  • index.tsx is now a 153-line composition of the extracted pieces. No exported symbol changed; everything new lives under the page's own directory.

Tests

  • Characterization suite green after every commit; full make test_frontend: 445 of 446 suites green — the one red suite (AuthModal) is a userEvent 5s timeout under a loaded parallel run, passes 8/8 in isolation and does not touch this diff.
  • make format_frontend no drift; biome check clean on the page directory.
  • Dead-export sweep: zero external references to any moved symbol (the ProviderListItem/MASKED_VALUE matches in modelProviderModal are same-named locals of that modal).
  • Manual smoke on the branch with disposable fixtures (created and removed via API, backend state restored): provider list and badges, panel switch, Save/Test gating from empty to hydrated, masked secret with the hydrated "Use Opensearch" label, invalid Test Connection surfacing the error toast, activation round-trip OpenSearch → Chroma. Console: only pre-existing messages.
  • Before/after screenshots light and dark below.

Note

The mask edit/cancel focus flow could not be driven by browser automation on this machine — the password-manager extension detaches the debugger when a password field gains focus; that flow is covered by the characterization suite. A valid Test Connection needs a real cluster and was not exercised.

Refs LE-1735

Screenshots

DB Providers page — OpenSearch panel

Light

Before

before-db-providers-opensearch-light

After

after-db-providers-opensearch-light

Dark

Before

before-db-providers-opensearch-dark

After

after-db-providers-opensearch-dark

Summary by CodeRabbit

  • New Features

    • Added database provider configuration panels with support for text, password, and boolean settings.
    • Added provider selection indicators, active-provider badges, and “Coming soon” notices.
    • Added Save, Test Connection, and provider activation actions.
    • Added masked handling for configured secrets and validation for required fields.
    • Added support for configuring OpenSearch and selecting Chroma providers.
  • Tests

    • Added coverage for provider rendering, activation, validation, secret handling, connection testing, and saving existing or new settings.

Golden-master coverage for the untouched 866-line page ahead of the
component extraction: provider list order and badges, active-provider
resolution from LANGFLOW_KNOWLEDGE_BACKEND, chroma panel action state,
required-field gating of Save and Test connection, masked secret
hydration, POST vs PATCH persistence incl. Credential typing and
provider activation, and the coming-soon stub panel. Behavior-only
assertions so each upcoming move can run against this suite unchanged.
Verbatim move of the inline list-item into components/ProviderListItem
with its explicit prop types. Characterization suite green.
Verbatim moves of TextFieldRow and BooleanFieldRow into components/,
carrying the MASKED_VALUE constant with its only consumer.
Characterization suite green.
Verbatim move of the configuration panel into components/, importing
the already-extracted field rows; orphan imports pruned from index.
Characterization suite green.
…lper

Verbatim move of the pure buildBackendConfigPayload function into
helpers/build-backend-config-payload.ts. Characterization suite green.
Verbatim move of the global-variable query, the create-or-update
setVariable primitive and activateProvider into
hooks/useDBProviderVariables. Characterization suite green.
Verbatim move of getFieldValue, hasConfiguredValue, isHydrated and
canSave into hooks/useDBProviderFields, parameterized on the selected
provider, stored globals and session edits. Characterization suite
green.
Verbatim move of handleSave, handleTestConnection and handleUseChroma
into hooks/useDBProviderActions together with the ApiError helper; the
hook owns the test-connection mutation and alert wiring. index.tsx is
now a 153-line composition of the extracted hooks and components.
Characterization suite green.
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

Database provider configuration

Layer / File(s) Summary
Provider configuration UI
src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/components/*
Extracts provider list and configuration rendering, including field controls, secret masking, badges, provider-specific branches, and action buttons.
Field and variable state
src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderFields.ts, src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderVariables.ts
Resolves edited, stored, and default values; computes hydration/save readiness; and creates or patches global variables.
Save, test, and activation actions
src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderActions.ts, src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/helpers/build-backend-config-payload.ts
Implements provider saving, connection testing, Chroma activation, alert handling, and backend test payload construction.
Page orchestration and validation
src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/index.tsx, src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/__tests__/DBProvidersPage.test.tsx
Wires the extracted hooks and components into the page and adds coverage for provider selection, field behavior, secret hydration, and POST/PATCH persistence flows.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested reviewers: erichare, ramgopalsrikar, olayinkaadelakun

🚥 Pre-merge checks | ✅ 8 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Test Quality And Coverage ⚠️ Warning Strong happy-path RTL coverage exists, but no test covers rejected save/test/use-chroma flows or asserts setErrorData; mockTestMutateAsync only resolves. Add error-path tests for save/test/use-chroma and missing-config validation, asserting setErrorData and behavior after rejection.
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: refactoring DBProvidersPage into components, hooks, and helpers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Test Coverage For New Implementations ✅ Passed A new frontend characterization suite (DBProvidersPage.test.tsx) adds 11 real tests covering provider order, badges, save/test gating, masking, POST/PATCH, and coming-soon UI.
Test File Naming And Structure ✅ Passed DBProvidersPage.test.tsx matches repo Jest/RTL conventions, uses descriptive grouped tests, and includes setup/teardown plus positive/negative coverage.
Excessive Mock Usage Warning ✅ Passed Mocks isolate API hooks, alert store, i18n, and an icon; the tests still exercise the real page and user flows, so mocking isn't excessive.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/le-1735-wp2

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 added the refactor Maintenance tasks and housekeeping label Jul 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Test Coverage Advisor

No source changes detected without accompanying tests. Thanks for keeping coverage up! 🎉

Advisory check only — never blocks merge.

@github-actions github-actions Bot added refactor Maintenance tasks and housekeeping and removed refactor Maintenance tasks and housekeeping labels Jul 13, 2026

@Cristhianzl Cristhianzl left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

@github-actions github-actions Bot added the lgtm This PR has been approved by a maintainer label Jul 13, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (2)
src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderActions.ts (1)

241-245: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Chroma lookup relies on array position.

DB_PROVIDER_OPTIONS[0] assumes Chroma is always first; reordering the list would silently activate the wrong provider with no compiler warning.

♻️ Proposed fix
-    const chromaProvider = DB_PROVIDER_OPTIONS[0];
+    const chromaProvider = DB_PROVIDER_OPTIONS.find((p) => p.id === "chroma");
+    if (!chromaProvider) return;
🤖 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
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderActions.ts`
around lines 241 - 245, Update handleUseChroma to retrieve the Chroma option by
its stable provider identifier or explicit property instead of relying on
DB_PROVIDER_OPTIONS[0]. Preserve the existing activateProvider and
setSelectedProviderId flow once the Chroma option is found.
src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/helpers/build-backend-config-payload.ts (1)

24-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Hardcoded fallback defaults duplicate field-definition defaults.

These literal fallbacks ("us-east-1", "vector_field", "text", true) mirror values that likely already live as defaultValue on the corresponding fields in dbProviderConstants. Two sources of truth for the same default risks silent drift between what the UI shows/pre-fills and what's actually sent to the backend if one is updated without the other.

Also applies to: 34-39

🤖 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
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/helpers/build-backend-config-payload.ts`
at line 24, Update buildBackendConfigPayload to use the corresponding field
definitions’ defaultValue from dbProviderConstants for cloud_region and the
other affected payload fields, instead of duplicating "us-east-1",
"vector_field", "text", and true. Preserve explicitly provided literalFields
values while falling back to the centralized field defaults.
🤖 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
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/__tests__/DBProvidersPage.test.tsx`:
- Around line 25-30: Add error-path coverage to the DBProvidersPage test suite:
configure mockTestMutateAsync and the save mutation to reject, and cover missing
configuration causing setErrorData to be used. Assert mockSetErrorData is called
with the surfaced error and preserve existing success and disabled-button tests.

In
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/components/BooleanFieldRow.tsx`:
- Around line 20-24: Update BooleanFieldRow’s switch aria-label to reuse the
same translated label value produced by the visible field label’s t(...) call,
including its defaultValue fallback, instead of using raw field.label. Keep the
visible label rendering unchanged and ensure both accessible and visual labels
stay consistent across locales.

In
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/components/ProviderConfigurationPanel.tsx`:
- Around line 155-160: Update the focus handling around isConfigured in
ProviderConfigurationPanel so it only calls onSecretEditingChange for a
configured secret and does not initialize variableValues through
onVariableChange with an empty string. Leave draft creation to the existing
onChange path, preserving masking and unedited state after blur.
- Line 50: Update hasUnsavedChanges in ProviderConfigurationPanel to evaluate
only draft values belonging to the currently selected provider, rather than any
entries persisted in variableValues. Reuse the selected-provider identity and
existing variableValues structure from the panel/index flow, preserving “Use”
when the selected provider has no draft and “Save and use” only when it does.

In
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderActions.ts`:
- Around line 24-26: Update getErrorDetail to accept or access the existing
translation function t and translate the fallback message when
ApiError.response.data.detail is absent, while preserving API-provided detail
values unchanged.
- Around line 79-95: Add a shared secret-aware getMissingRequiredFields helper
in useDBProviderFields, reusing the same variableValues, hasConfiguredValue, and
getFieldValue rules as canSave. Update both handleSave and handleTestConnection
in useDBProviderActions to use this helper, and localize the missing-fields
sentence through t() with interpolated field labels instead of raw string
concatenation.

In
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderVariables.ts`:
- Around line 38-40: Update the existing-variable branch in the variable
persistence logic around findVariable and updateGlobalVariable so secret values
preserve credential classification. When isSecret is true, include type:
"Credential" in the PATCH payload, or reject and recreate a conflicting Generic
variable; retain existing behavior for non-secret updates.

---

Nitpick comments:
In
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/helpers/build-backend-config-payload.ts`:
- Line 24: Update buildBackendConfigPayload to use the corresponding field
definitions’ defaultValue from dbProviderConstants for cloud_region and the
other affected payload fields, instead of duplicating "us-east-1",
"vector_field", "text", and true. Preserve explicitly provided literalFields
values while falling back to the centralized field defaults.

In
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderActions.ts`:
- Around line 241-245: Update handleUseChroma to retrieve the Chroma option by
its stable provider identifier or explicit property instead of relying on
DB_PROVIDER_OPTIONS[0]. Preserve the existing activateProvider and
setSelectedProviderId flow once the Chroma option is found.
🪄 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: a68a7855-6620-4590-b916-8491297e392a

📥 Commits

Reviewing files that changed from the base of the PR and between 80758f2 and 5ff7802.

📒 Files selected for processing (10)
  • src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/__tests__/DBProvidersPage.test.tsx
  • src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/components/BooleanFieldRow.tsx
  • src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/components/ProviderConfigurationPanel.tsx
  • src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/components/ProviderListItem.tsx
  • src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/components/TextFieldRow.tsx
  • src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/helpers/build-backend-config-payload.ts
  • src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderActions.ts
  • src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderFields.ts
  • src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderVariables.ts
  • src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/index.tsx

Comment on lines +25 to +30
const mockTestMutateAsync = jest.fn(() =>
Promise.resolve({ ok: true, message: "cluster green" }),
);

const mockSetSuccessData = jest.fn();
const mockSetErrorData = jest.fn();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

No test exercises the error path despite the scaffolding being present.

mockTestMutateAsync always resolves successfully and mockSetErrorData is never asserted as called anywhere in the suite. The coding guideline requires coverage for "positive, negative, edge, and error cases," but this suite only covers happy-path save/activation and disabled-button gating — there's no test for a rejected useTestDBProviderConnection call, a rejected save, or missing-config error surfacing via setErrorData.

🧪 Example error-path test
+    it("surfaces a connection-test failure via setErrorData", async () => {
+      mockTestMutateAsync.mockRejectedValueOnce(new Error("cluster red"));
+      const user = userEvent.setup();
+      render(<DBProvidersPage />);
+      await user.click(screen.getByTestId("db-provider-item-opensearch"));
+      // ...fill required fields...
+      await user.click(screen.getByTestId("db-provider-test-connection"));
+      await waitFor(() => expect(mockSetErrorData).toHaveBeenCalled());
+    });

As per coding guidelines, "follow frontend test naming conventions... and coverage for positive, negative, edge, and error cases" for frontend test files.

🤖 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
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/__tests__/DBProvidersPage.test.tsx`
around lines 25 - 30, Add error-path coverage to the DBProvidersPage test suite:
configure mockTestMutateAsync and the save mutation to reject, and cover missing
configuration causing setErrorData to be used. Assert mockSetErrorData is called
with the surfaced error and preserve existing success and disabled-button tests.

Source: Coding guidelines

Comment on lines +20 to +24
<span className="text-[12px] font-medium">
{t(`settings.dbProviders.fields.${field.variableKey}.label`, {
defaultValue: field.label,
})}
</span>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

aria-label bypasses i18n while the visible label is translated.

Line 41 uses the raw field.label for the switch's accessible name, while the visible label (Lines 20-24) goes through t(). Screen-reader users on non-English locales will hear the English label while sighted users see the translated one.

🌐 Proposed fix
       <Switch
         checked={value}
         onCheckedChange={onChange}
         disabled={disabled}
-        aria-label={field.label}
+        aria-label={t(`settings.dbProviders.fields.${field.variableKey}.label`, {
+          defaultValue: field.label,
+        })}
         data-testid={`db-provider-toggle-${field.variableKey}`}
       />

Also applies to: 41-41

🤖 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
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/components/BooleanFieldRow.tsx`
around lines 20 - 24, Update BooleanFieldRow’s switch aria-label to reuse the
same translated label value produced by the visible field label’s t(...) call,
including its defaultValue fallback, instead of using raw field.label. Keep the
visible label rendering unchanged and ensure both accessible and visual labels
stay consistent across locales.

const isComingSoon = provider.status === "coming_soon";
const isActive = activeProviderId === provider.id;
// True when the user has interacted with any field this session.
const hasUnsavedChanges = Object.keys(variableValues).length > 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Scope unsaved changes to the selected provider.

variableValues persists across provider selection in index.tsx Lines 108-111, so drafts for another provider can incorrectly change this panel’s action from “Use” to “Save and use.”

Proposed fix
-  const hasUnsavedChanges = Object.keys(variableValues).length > 0;
+  const hasUnsavedChanges = provider.configFields.some(
+    (field) => field.variableKey in variableValues,
+  );
📝 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 hasUnsavedChanges = Object.keys(variableValues).length > 0;
const hasUnsavedChanges = provider.configFields.some(
(field) => field.variableKey in variableValues,
);
🤖 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
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/components/ProviderConfigurationPanel.tsx`
at line 50, Update hasUnsavedChanges in ProviderConfigurationPanel to evaluate
only draft values belonging to the currently selected provider, rather than any
entries persisted in variableValues. Reuse the selected-provider identity and
existing variableValues structure from the panel/index flow, preserving “Use”
when the selected provider has no draft and “Save and use” only when it does.

Comment on lines +155 to +160
const isConfigured =
field.isSecret &&
globalVariables.some((v) => v.name === field.variableKey);
if (isConfigured && !(field.variableKey in variableValues)) {
onSecretEditingChange(field.variableKey, true);
onVariableChange(field.variableKey, "");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not create an empty secret draft on focus.

Adding the empty key makes TextFieldRow.tsx Lines 36-40 treat the field as having a new value. After blur, the configured secret remains blank instead of becoming masked again and is falsely counted as edited.

Typing already creates the draft through onChange, so only toggle editing here.

Proposed fix
   if (isConfigured && !(field.variableKey in variableValues)) {
     onSecretEditingChange(field.variableKey, true);
-    onVariableChange(field.variableKey, "");
   }
📝 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 isConfigured =
field.isSecret &&
globalVariables.some((v) => v.name === field.variableKey);
if (isConfigured && !(field.variableKey in variableValues)) {
onSecretEditingChange(field.variableKey, true);
onVariableChange(field.variableKey, "");
const isConfigured =
field.isSecret &&
globalVariables.some((v) => v.name === field.variableKey);
if (isConfigured && !(field.variableKey in variableValues)) {
onSecretEditingChange(field.variableKey, true);
}
🤖 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
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/components/ProviderConfigurationPanel.tsx`
around lines 155 - 160, Update the focus handling around isConfigured in
ProviderConfigurationPanel so it only calls onSecretEditingChange for a
configured secret and does not initialize variableValues through
onVariableChange with an empty string. Leave draft creation to the existing
onChange path, preserving masking and unedited state after blur.

Comment on lines +24 to +26
const getErrorDetail = (error: unknown) =>
(error as ApiError)?.response?.data?.detail ||
"An unexpected error occurred. Please try again.";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fallback error text isn't localized.

Every other user-facing string in this file goes through t(); this fallback message is the one exception, so an API error without a detail field always renders in English.

🤖 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
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderActions.ts`
around lines 24 - 26, Update getErrorDetail to accept or access the existing
translation function t and translate the fallback message when
ApiError.response.data.detail is absent, while preserving API-provided detail
values unchanged.

Comment on lines +79 to +95
if (!canSave) {
setErrorData({
title: t("settings.dbProviders.errorMissingConfig"),
list: [
`${selectedProvider.label} requires ${selectedProvider.configFields
.filter(
(field): field is DBProviderTextField =>
field.kind !== "boolean" &&
field.required &&
!getFieldValue(field).trim(),
)
.map((field) => field.label)
.join(", ")}.`,
],
});
return false;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Missing-field error list mismatches canSave's own secret-handling rule, and bypasses i18n entirely.

Two issues in this duplicated block:

  • The filter !getFieldValue(field).trim() doesn't match the secret-aware rule useDBProviderFields uses for canSave (variableValues[...]?.trim() || hasConfiguredValue(...)). A required secret field that's already saved (masked, so getFieldValue returns "") will still be listed as "required" here even though it isn't the reason canSave is false — confusing users into re-entering credentials that are already configured.
  • The list sentence is built via raw string concatenation and never passed through t() (unlike title on the same call), so this user-facing message is never localized.

Both instances (handleSave and handleTestConnection) duplicate the same logic, so fixing once via a shared helper resolves both.

🔧 Suggested direction

Expose a secret-aware helper from useDBProviderFields (mirroring canSave's per-field predicate) and consume it here instead of re-deriving from getFieldValue:

// in useDBProviderFields.ts
const getMissingRequiredFields = () =>
  selectedProvider.configFields.filter(
    (field): field is DBProviderTextField =>
      field.kind !== "boolean" &&
      field.required &&
      !(field.isSecret
        ? Boolean(variableValues[field.variableKey]?.trim()) || hasConfiguredValue(field.variableKey)
        : Boolean(getFieldValue(field).trim())),
  );

Then in useDBProviderActions.ts, build the list from getMissingRequiredFields().map(f => f.label) and wrap the sentence in t(...) with interpolated values instead of a raw template literal.

Also applies to: 158-174

🤖 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
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderActions.ts`
around lines 79 - 95, Add a shared secret-aware getMissingRequiredFields helper
in useDBProviderFields, reusing the same variableValues, hasConfiguredValue, and
getFieldValue rules as canSave. Update both handleSave and handleTestConnection
in useDBProviderActions to use this helper, and localize the missing-fields
sentence through t() with interpolated field labels instead of raw string
concatenation.

Comment on lines +38 to +40
const existingVariable = findVariable(name);
if (existingVariable) {
await updateGlobalVariable({ id: existingVariable.id, value });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether the PATCH payload supports changing variable type.
rg -n -C5 '\bPatchGlobalVariablesParams\b' src/frontend/src
rg -n -C5 '"Credential"|"Generic"' src/frontend/src/controllers src/frontend/src/types

Repository: langflow-ai/langflow

Length of output: 4875


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the hook and related API/model definitions around variable updates.
FILE1='src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderVariables.ts'
FILE2='src/frontend/src/controllers/API/queries/variables/use-patch-global-variables.ts'
FILE3='src/frontend/src/types/global_variables/index.ts'

for f in "$FILE1" "$FILE2" "$FILE3"; do
  echo "===== $f ====="
  nl -ba "$f" | sed -n '1,220p'
  echo
done

# Search for other update paths that might include `type`.
rg -n -C3 '\btype\b|isSecret|Credential|Generic|usePatchGlobalVariables|updateGlobalVariable' src/frontend/src/pages src/frontend/src/controllers src/frontend/src/types

Repository: langflow-ai/langflow

Length of output: 301


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE1='src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderVariables.ts'
FILE2='src/frontend/src/controllers/API/queries/variables/use-patch-global-variables.ts'
FILE3='src/frontend/src/types/global_variables/index.ts'

for f in "$FILE1" "$FILE2" "$FILE3"; do
  echo "===== $f ====="
  sed -n '1,220p' "$f" | cat -n
  echo
done

echo "===== search ====="
rg -n -C4 'updateGlobalVariable|usePatchGlobalVariables|PatchGlobalVariablesParams|type:\s*["'\'']Credential["'\'']|type:\s*["'\'']Generic["'\'']|isSecret' src/frontend/src

Repository: langflow-ai/langflow

Length of output: 50376


Preserve credential classification on update. This path updates only value, so a secret written over an existing Generic variable keeps the wrong type and can bypass the masking contract. Add type: "Credential" to the PATCH contract or reject/recreate the conflicting variable when isSecret is true.

🤖 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
`@src/frontend/src/pages/SettingsPage/pages/DBProvidersPage/hooks/useDBProviderVariables.ts`
around lines 38 - 40, Update the existing-variable branch in the variable
persistence logic around findVariable and updateGlobalVariable so secret values
preserve credential classification. When isSecret is true, include type:
"Credential" in the PATCH payload, or reject and recreate a conflicting Generic
variable; retain existing behavior for non-secret updates.

@github-actions

Copy link
Copy Markdown
Contributor

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 46%
46.51% (64571/138819) 70.14% (8847/12612) 44.36% (1457/3284)

Unit Test Results

Tests Skipped Failures Errors Time
5292 0 💤 0 ❌ 0 🔥 18m 28s ⏱️

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.67898% with 150 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.73%. Comparing base (6450159) to head (5ff7802).
⚠️ Report is 4 commits behind head on release-1.11.0.

Files with missing lines Patch % Lines
...ages/DBProvidersPage/hooks/useDBProviderActions.ts 56.42% 112 Missing ⚠️
...vidersPage/helpers/build-backend-config-payload.ts 29.26% 29 Missing ⚠️
...dersPage/components/ProviderConfigurationPanel.tsx 97.46% 5 Missing ⚠️
...es/DBProvidersPage/hooks/useDBProviderVariables.ts 94.93% 4 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##           release-1.11.0   #14049      +/-   ##
==================================================
+ Coverage           60.16%   60.73%   +0.56%     
==================================================
  Files                2333     2397      +64     
  Lines              228353   231475    +3122     
  Branches            32038    33901    +1863     
==================================================
+ Hits               137386   140579    +3193     
+ Misses              89351    89280      -71     
  Partials             1616     1616              
Flag Coverage Δ
frontend 59.94% <82.67%> (+0.90%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...ges/DBProvidersPage/components/BooleanFieldRow.tsx 91.93% <100.00%> (ø)
...es/DBProvidersPage/components/ProviderListItem.tsx 95.60% <100.00%> (ø)
.../pages/DBProvidersPage/components/TextFieldRow.tsx 93.90% <100.00%> (ø)
...pages/DBProvidersPage/hooks/useDBProviderFields.ts 100.00% <100.00%> (ø)
...pages/SettingsPage/pages/DBProvidersPage/index.tsx 97.63% <100.00%> (+80.25%) ⬆️
...es/DBProvidersPage/hooks/useDBProviderVariables.ts 94.93% <94.93%> (ø)
...dersPage/components/ProviderConfigurationPanel.tsx 94.88% <97.46%> (ø)
...vidersPage/helpers/build-backend-config-payload.ts 29.26% <29.26%> (ø)
...ages/DBProvidersPage/hooks/useDBProviderActions.ts 56.42% <56.42%> (ø)

... and 342 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm This PR has been approved by a maintainer refactor Maintenance tasks and housekeeping

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants