Skip to content

fix(instance): connect on deep-link to refresh modules - #6230

Open
trippyogi wants to merge 4 commits into
redis:mainfrom
trippyogi:fix/6080-deep-link-modules
Open

fix(instance): connect on deep-link to refresh modules#6230
trippyogi wants to merge 4 commits into
redis:mainfrom
trippyogi:fix/6080-deep-link-modules

Conversation

@trippyogi

@trippyogi trippyogi commented Jul 17, 2026

Copy link
Copy Markdown

Summary

  • Call checkConnectToInstanceAction when mounting InstancePage, matching the DB picker / Redis Stack entry path.
  • Refresh modules via GET /databases/:id/connect before fetching instance data used by Vector Search guards.
  • Fixes Docker preconfigured databases (modules: []) opened via /0/vector-search incorrectly showing Redis Search as unavailable.

Fixes #6080

Test plan

  • InstancePage.spec.tsx — 9/9 passed
  • Fresh preconfigured DB with modules: []; deep-link /0/vector-search triggers connect and populates search module
  • UI: deep-link Search shows indexes (e.g. idx:trie), not the RQE unavailable empty state
  • /0/browser still loads after deep-link / picker entry
  • Regression: open DB from picker, then Search — still works

Note

Medium Risk
Changes core instance mount and connect sequencing used by every database route; behavior differs for deep links, picker entry, and DB switches, though covered by expanded tests.

Overview
InstancePage now mirrors the DB picker / Redis Stack flow: when the route’s database id does not match connectedInstance.id, it runs checkConnectToInstanceAction (including GET /databases/:id/connect) before loading config, info, and recommendations; when ids already match, it skips connect and only loads that data. Connect callbacks run on both success and failure so connectedInstance.loading clears (e.g. Vector Search no longer spins on deep links with stale empty modules). resetConnectedInstance is only requested when switching from another connected id, not on fresh deep links or same-id entry.

fetchConnectedInstanceAction now dispatches setConnectedInstanceFailure when the instance fetch fails.

Tests add connectDatabaseApiSpy, MSW overrides for failed connect, and cases for same-id skip, successful/failed connect, DB switch reset, and single connect on deep link; slice tests cover the new failure dispatch.

Reviewed by Cursor Bugbot for commit 2f3b6bf. Bugbot is set up for automated code reviews on this repo. Configure here.

InstancePage now calls checkConnectToInstanceAction before fetching
instance data so Redis modules are refreshed via GET /connect. This
fixes Vector Search showing unavailable when deep-linking to
/0/vector-search on preconfigured Docker databases.

Fixes redis#6080
@CLAassistant

CLAassistant commented Jul 17, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@trippyogi
trippyogi marked this pull request as ready for review July 17, 2026 18:55
@trippyogi
trippyogi requested a review from a team as a code owner July 17, 2026 18:55

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81976eb9fb

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

dispatch(fetchRecommendationsAction(connectionInstanceId))
},
undefined,
contextInstanceId !== connectionInstanceId,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid clearing RedisStack's connected id

In the RedisStack build, RedisStackRoutes first connects, calls setConnectedInstanceId, and pushes /:id/browser; those routes are wrapped by ProtectedRoute, which redirects to Pages.home whenever connectedInstance.id is empty. On this first InstancePage mount the app context is still empty, so this reset flag is true and checkConnectToInstanceAction synchronously dispatches resetConnectedInstance before the async connect completes. That clears the id after the route was admitted, causing ProtectedRoute to immediately redirect back home and preventing /0/browser from staying open in the RedisStack path.

Useful? React with 👍 / 👎.

Only reset connectedInstance when switching away from a different DB.
Redis Stack sets the connected id before routing into InstancePage;
resetting it cleared ProtectedRoute and bounced back to home.
@trippyogi

Copy link
Copy Markdown
Author

Addressed Codex feedback: resetConnectedInstance now only runs when switching away from a different already-connected DB (connectedInstanceId !== connectionInstanceId).

Redis Stack sets connectedInstance.id before mounting InstancePage, so we no longer clear it mid-route (which was bouncing ProtectedRoute back to home).

Added a unit test covering the same-id / no-reset case. InstancePage.spec: 10/10 passed.

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 2ac110e. Configure here.

Comment thread redisinsight/ui/src/pages/instance/InstancePage.tsx Outdated
Comment thread redisinsight/ui/src/pages/instance/InstancePage.spec.tsx

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2ac110e7c7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +87 to +92
() => {
dispatch(fetchConnectedInstanceAction(connectionInstanceId))
dispatch(getDatabaseConfigInfoAction(connectionInstanceId))
dispatch(fetchConnectedInstanceInfoAction(connectionInstanceId))
dispatch(fetchRecommendationsAction(connectionInstanceId))
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle failed deep-link connects

When a user opens a bookmarked/direct instance route and GET /databases/:id/connect fails (for example a temporarily unavailable DB returning 424), this success callback never runs and no failure callback is provided. Since the old unconditional fetchConnectedInstanceAction is now only dispatched here, a fresh / :id /vector-search load leaves connectedInstance.loading as undefined, which VectorSearchPageRouter treats as loading forever; Browser children also keep connectedInstance.id empty. Please update the failure path to either redirect/show a terminal state or still fetch/reset the connected instance state.

Useful? React with 👍 / 👎.

Always fetch connected instance/config/info after connect succeeds or
fails so connectedInstance.loading settles and Vector Search does not
spin forever. Drop unused getRecommendations import in the spec.
@trippyogi

Copy link
Copy Markdown
Author

Addressed Bugbot findings on 2ac110e:

  1. Connect failure / loadingloadInstanceData now runs on both connect success and failure so connectedInstance.loading settles (Vector Search no longer spins forever).
  2. Unused import — removed getRecommendations from InstancePage.spec.tsx.

InstancePage.spec: 10/10 passed.

@VaskoAtanasovRedis VaskoAtanasovRedis self-assigned this Jul 23, 2026
Comment on lines +88 to +101
// Only reset when switching away from a different connected DB.
// Redis Stack already set connectedInstance.id before routing here;
// resetting would clear it and ProtectedRoute would bounce to home.
// Always load instance data after connect attempt (success or fail) so
// connectedInstance.loading settles and Vector Search does not spin forever.
dispatch(
checkConnectToInstanceAction(
connectionInstanceId,
loadInstanceData,
loadInstanceData,
Boolean(connectedInstanceId) &&
connectedInstanceId !== connectionInstanceId,
),
)

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.

Making this unconditional regresses the existing entry paths though. The DB picker (databases-list/methods/handlers.ts), Redis Stack router (RedisStackRoutes.tsx), and the navigation popover (InstancesList.tsx) all dispatch checkConnectToInstanceAction before navigating and set connectedInstance.id in their success callbacks - so with this change every normal DB open issues a second /connect. That endpoint is not cheap on the backend (DatabaseConnectionService.connect): it re-probes modules and server version, rewrites the DB record, runs INFO + CLIENT LIST, re-runs recommendation checks, and emits a connection analytics event - all doubled per open, and the analytics get double-counted. It also serializes the four data fetches behind the extra round-trip on every navigation, not just deep links.

Since those paths all arrive with connectedInstance.id already equal to the route id, you can keep the fix and skip the redundant call:

Suggested change
// Only reset when switching away from a different connected DB.
// Redis Stack already set connectedInstance.id before routing here;
// resetting would clear it and ProtectedRoute would bounce to home.
// Always load instance data after connect attempt (success or fail) so
// connectedInstance.loading settles and Vector Search does not spin forever.
dispatch(
checkConnectToInstanceAction(
connectionInstanceId,
loadInstanceData,
loadInstanceData,
Boolean(connectedInstanceId) &&
connectedInstanceId !== connectionInstanceId,
),
)
if (connectedInstanceId === connectionInstanceId) {
loadInstanceData()
} else {
dispatch(
checkConnectToInstanceAction(
connectionInstanceId,
loadInstanceData,
loadInstanceData,
Boolean(connectedInstanceId),
),
)
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch on the double /connect - adopted the same-id gate so picker / Redis Stack / nav keep a single connect, and deep links still refresh modules. Included in 2f3b6bf.

]

expect(store.getActions().slice(0, expectedActions.length)).toEqual(
expect(testStore.getActions().slice(0, expectedActions.length)).toEqual(

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.

The reset / no-reset branches are well pinned (nice negative test for the Redis Stack case), but the behavior this PR exists to create ended up unasserted: the old expected-actions list contained setConnectedInstance, getDatabaseConfigInfo, setConnectedInfoInstance, and getRecommendations, and after this rework those only fire inside the connect success callback - which lands after the slice(0, expectedActions.length) window, so nothing checks them anymore. Deleting loadInstanceData (or passing undefined for both callbacks) keeps the whole suite green.

Could you add three tests to lock the new flow in:

  1. Success path - render with the default store and await waitFor(() => expect(store.getActions()).toEqual(expect.arrayContaining([setConnectedInstance(), getDatabaseConfigInfo(), setConnectedInfoInstance(), getRecommendations()]))). The MSW handler for /databases/:id/connect already returns 200, so the callback runs in tests.
  2. Fail path - override the connect handler with a 503 via mswServer.use(...) (same pattern as instanceConnectionLost.spec.tsx) and assert setDefaultInstanceFailure is dispatched and the four fetches still fire - this is the guarantee of commit 0ce6401, currently uncovered.
  3. Fresh deep link (the literal [Bug]: Docker Redis Insight does not detect Redis Search when opening a preconfigured database through a direct route #6080 state) - seed connectedInstance.id = '', spy on the connect endpoint (same jest.fn() MSW-spy pattern as getDatabasesApiSpy) and assert it's called once and resetConnectedInstance is not dispatched.

Two smaller things while you're in here: the positive assertion in the same-id test (toContainEqual(setDefaultInstance())) doesn't actually prove the connect flow ran - fetchConnectedInstanceAction dispatches setDefaultInstance() too, so a full revert to the old direct-fetch code still passes it; asserting setDefaultInstanceSuccess() or the connect spy pins it properly. And 'prevId' could come from faker per our testing conventions.

(If you adopt the same-id gate suggested on InstancePage.tsx, test 1 doubles as its coverage - same-id renders should then assert the fetches fire without a connect call.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Added the three coverage cases (success / fail / fresh deep link), tightened the same-id path to assert no connect call + the four fetches, and switched prevId to faker. Also in 2f3b6bf.

checkConnectToInstanceAction(
connectionInstanceId,
loadInstanceData,
loadInstanceData,

@VaskoAtanasovRedis VaskoAtanasovRedis Jul 27, 2026

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.

Running loadInstanceData on the fail path is a good catch, but the VS page can still load forever: if the GET /databases/:id inside fetchConnectedInstanceAction itself fails (e.g. a stale or invalid id in the url), its catch never sets connectedInstance.loading back to false.

I think we can add a one line guard against this inside that catch (slices/instances/instances.ts, ~line 759):

dispatch(setConnectedInstanceFailure())

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed - i added setConnectedInstanceFailure() in the fetchConnectedInstanceAction catch so connectedInstance.loading settles on a bad/stale id. Also in 2f3b6bf.

Skip GET /connect when already on the same instance id (picker/Redis Stack), clear connectedInstance.loading on fetch failure, and lock the deep-link success/fail flows with tests.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f3b6bf77f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

} catch (_err) {
const error = _err as AxiosError
const errorMessage = getApiErrorMessage(error)
dispatch(setConnectedInstanceFailure())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve an error state when instance fetch fails

When a direct/bookmarked instance route reaches this catch path because the follow-up GET /databases/:id fails (for example the DB was deleted or the API returns 404/5xx after the connect attempt), this now marks connectedInstance.loading as false while leaving the reset/default instance data (modules: []) in place. VectorSearchPageRouter treats loading === false plus no RediSearch module as a normal “RQE not available” result, so users get a misleading unsupported page instead of an error or redirect. Fresh evidence beyond the earlier connect-failure comment is that this newly added failure action now explicitly settles the compatibility guard after the failed instance fetch.

Useful? React with 👍 / 👎.

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.

[Bug]: Docker Redis Insight does not detect Redis Search when opening a preconfigured database through a direct route

3 participants