Skip to content

Feat/unified data explorer - #268

Merged
itsmeakhil merged 26 commits into
mainfrom
feat/unified-data-explorer
Aug 4, 2026
Merged

Feat/unified data explorer#268
itsmeakhil merged 26 commits into
mainfrom
feat/unified-data-explorer

Conversation

@itsmeakhil

Copy link
Copy Markdown
Collaborator

No description provided.

itsmeakhil and others added 26 commits August 4, 2026 20:47
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… toast

Review findings on Task 5: the tab-persistence comment claimed adapter
`state` was excluded from localStorage when it never was (state IS
persisted on purpose — it restores page/query/sort across sessions,
since fetched rows live in the adapter's actions hook, not on the tab).
Replaced the comment to describe the actual contract instead of
stripping the field. Also routed the "Could not load connections"
toast fallback through DataExplorer.toast.loadFailed instead of a
hardcoded string.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ned tabs

- useCallback the four sidebar handlers in the shell so React.memo on
  ConnectionRow survives page-level renders (openTab et al).
- aria-label on the row action menu trigger, aria-expanded on the group
  header and the connection toggle, focus-within reveal for keyboard users.
- Drop tabs whose connection was deleted, gated on an explicit
  connectionsLoaded flag plus isInitialized so a cold start never wipes
  tabs restored from localStorage and a failed fetch never prunes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…gh i18n

validate() now returns DataExplorer-relative i18n keys instead of hardcoded
English; the connection dialog resolves them via t(). testConnection's
"Connection failed" fallback is gone — it throws empty when there's no
sanitised server message, and the dialog supplies connectionDialog.testFailed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… cross-server sync

Adds copy-db-name, collection multi-select + bulk delete, in-tree search
filtering, and cross-server sync targets. SidebarTreeProps gains
searchQuery and siblings (source-agnostic: the shell buckets by sourceId
equality). Also: per-mode name-validation messages, sorted collections,
no No-databases flash, sanitizeError on every error path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The MongoDB pane wired onDelete straight to actions.remove, so a row's trash
icon deleted a document irreversibly with no prompt — the legacy page's
handleDelete only opens an AlertDialog and confirmDelete does the work, and
DocumentView confirms bulk delete but not single delete. Restore the dialog in
the pane, since document-view.tsx cannot be modified.

The shell rendered <Pane> with no key. Panes are stable component references,
so a same-source tab switch reconciled the same instance and carried the
previous collection's documents, view mode, selection and index data across.
Key it per tab, which also resets the actions hook's document state and covers
every other adapter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sanitizeRedisError returned the raw message when new URL(redisUrl) threw,
even though validate() only checks the scheme and lets malformed URLs
through (e.g. a non-numeric port). Rebuild it on the existing
nosql-error-sanitizer.ts pattern: scrub any redis(s):// URL wholesale by
regex, run the result through the shared sanitizeError for generic
user:password@ and email patterns, then apply the URL-parse-based
credential strip only as a best-effort extra layer that strips both the
raw and percent-encoded form of the username/password. A parse failure
in that last layer no longer changes whether the message was sanitized.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The pane's db selector wrote state.db while the tab's shell-owned id and
title stayed frozen at open time, so a switched tab mislabelled its database
and a second tab could open on the same one. Database switching is now a
sidebar-tree-only action, which always opens or focuses the correctly
identified tab.

The connection form no longer offers a read-only switch: ValueEditor and
CommandPanel take no readOnly prop, so the flag could only ever hide Flush
and BulkActions, not "block every write operation" as the hint promises. The
field stays in the data model and keeps gating those two controls.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tate

Review findings: dedupe key was (sourceId, name) only, silently dropping
distinct connections sharing a name (legacy Mongo defaults unnamed rows to
"My Connection"); fold in a config discriminator (connectionString/redisUrl)
so same-named-different-config rows both import while true duplicates still
dedupe to zero, including across a name-only case/whitespace difference.
Gate the import on the shell's connectionsLoaded flag so a failed or
in-flight unified-list fetch can't make every legacy connection look new.
Drop the raw error message from the fetch-failure toast (untranslated,
unnecessary risk in a credential-handling flow) and report total failure
(imported === 0, failed > 0) as toast.error instead of toast.success.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Translates the 127-key DataExplorer namespace, Navigation.dataExplorer and
Dashboard.tools.dataExplorer into the 26 non-English locales. Plural
categories follow CLDR per locale: full zero/one/two/few/many/other for ar,
one/few/many/other for pl/ru/uk/cs, other-only for ja/ko/ms/vi/zh.

Also hardens legacy-import's normalizeName against a stored row with a
missing name, which previously threw out of dedupeAgainstExisting and
blocked the entire legacy import.

Verified: 27/27 locales valid JSON with exactly one DataExplorer block,
complete key parity and placeholder parity against en.json; 4536 ICU
renders compiled and formatted across all locales with zero failures;
tsc clean; jest 118/119 suites, 1040 tests (sole failure is the
pre-existing react-window suite); cargo test 38 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… readOnly, safe restore

- page: render an IconMenu2 sidebar trigger whenever the viewport is narrow.
  `setMobileSidebarOpen(true)` had no caller, so under 768px the sidebar lived
  in a Sheet nothing could open and the tool was an unrecoverable dead end.
- connection-dialog: `testConnection` is now an explicit optional button, not a
  precondition for saving. Only `adapter.validate` gates the save, matching the
  legacy Mongo form, so a rename/recolour saves off-VPN and a connection to a
  server that is not up yet can be pre-created. Success and failure both render
  inline. Source-agnostic: the flow changes for every adapter.
- types/tab-bar: drop `UnifiedTab.readOnly`. It was captured at open time and
  persisted, so it went stale the moment the connection was edited. The tab bar
  now resolves the lock glyph from the live connection.
- redis adapter: seed the builder fields from the stored URL via a new
  defensive `parseRedisUrl` (returns null instead of throwing). Editing a saved
  connection and touching Builder used to submit redis://localhost:6379 and
  destroy the stored credentials. The password is never rendered — it is
  re-attached on submit unless the user types a replacement.
- tab restore: validate shape before use (new lib/data-explorer/tab-storage.ts).
  A parsed-but-wrong value crashed the tool on mount and was never cleared,
  because the parse had succeeded.

New i18n key `DataExplorer.openSidebar` in all 27 locales; `connectionDialog.test`
and `testOk` were already translated everywhere and are now wired.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replaces the two-step grid-of-buttons picker with an always-visible Select
at the top of the connection dialog. Creating defaults to the first
registered source so the dialog opens ready to type; editing pins the
source, since changing what kind of database an existing connection points
at was never coherent.

Switching source clears any error and test result from the previous one,
and the adapter form is keyed by adapter id so no field carries over.

Reuses the existing connectionDialog.pickSource label, so no new keys and
no change to the 27-locale parity.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The source dropdown already says "MongoDB", so the form's second
mongodb/documentdb/cosmosdb/ferretdb picker read as a duplicate question.
Removed it and derived dbType from the connection string.

dbType stays load-bearing: normalizeConnectionString appends
retryWrites=false for DocumentDB and Cosmos, which reject the driver's
default and would otherwise fail writes silently. Both are identifiable by
their managed hostnames, which is what detectDbType matches (already
covered by lib/__tests__/nosql-dialects.test.ts). When detection cannot
tell, the connection's saved dbType is kept, so an explicit FerretDB
choice from an older build survives an edit.

The connection-string placeholder still follows the inferred dialect.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Unable to deploy a commit from a private repository on your GitHub organization to the itsmeakhil's projects team on Vercel, which is currently on the Hobby plan. In order to deploy, you can:

  • Make your repository public or
  • Upgrade to Pro. A Pro subscription is required to deploy from a private organization repository.

To read more about collaboration on Vercel, click here.

@itsmeakhil
itsmeakhil merged commit b475084 into main Aug 4, 2026
1 check failed
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.

1 participant