feat(json): JSON/JSONB editor, viewer & in-table affordances#181
Merged
debba merged 15 commits intoMay 17, 2026
Conversation
Contributor
Author
Contributor
Author
|
for testing psql: https://gist.github.com/NewtTheWolf/757f1ec6efdf2ef65c3c77898fb15973 |
d0ace89 to
7792388
Compare
Move detection from a global toggle to a connection-level setting so users can enable JSON cell affordances only on connections where text columns actually contain JSON.
…ditor - JsonCell renders detected JSON with syntax highlighting and a Braces affordance for opening the viewer - JsonExpansionEditor provides an inline Monaco editor for cell-level edits without leaving the grid - isJsonContent heuristic + jsonHighlight tokenizer + formatCellValue updates round out the rendering path
- Refactor JsonInput to host three swappable editing modes: Monaco code editor, json-edit-react tree view, and raw text fallback - Add JsonCodeEditor + JsonTreeView wrappers, leaf-only tree editing, fillHeight layout mode - Pull in json-edit-react dependency
3e3f0fa to
593eb58
Compare
- Bind serde_json::Value directly for json/jsonb columns instead of text-with-cast, fixing object/array round-trips - JSON-encode scalar values for json/jsonb cell display so quoted strings, numbers and bools render correctly
…cell dedup - Add json_viewer Rust module: session store, ULID session IDs, WebviewWindowBuilder, cell-key dedup, last-bounds memory - Replace JsonViewerModal with a standalone Tauri window (JsonViewerPage + /json-viewer route) - Grant window close/focus/unminimize capabilities for the new window label pattern - Support opening the viewer for free-form SELECT results (no PK); falls back to read-only when no save-back path exists - DataGrid + JsonInput now invoke open_json_viewer_window with a derived cell key so reopens focus instead of duplicating - i18n: dataGrid.newRow added; jsonViewer keys updated across en/de/es/fr/it/zh
Satisfies react-hooks/set-state-in-effect — the empty sessionId case is a derived value from the URL, so resolve it inline instead of setState'ing inside useEffect.
editorTheme.styles?.container is typed as string | object | undefined by json-edit-react, so the spread tripped TS2698 even though buildTheme always assigns an object. Cast to Record<string, unknown> at the spread site.
- Add missing detect_json_in_text_columns field to SavedConnection literal in export_import_tests.rs (introduced by this branch, broke the test added on main) - Delete tests/components/modals/JsonViewerModal.test.tsx — the modal it tests was removed when the viewer became a native Tauri window
593eb58 to
01b5568
Compare
- README + 4 localized READMEs: mention syntax-highlighted JSON/JSONB cells, dedicated editor window, and the per-connection "Detect JSON in text columns" opt-in - PLUGIN_GUIDE: callout under get_columns explaining that data_type "JSON"/"JSONB" (case-insensitive) enables the viewer, and that execute_query row values may be native JSON or JSON-formatted strings
JSON cells now light up like other modified cells (object-aware equality check fixed the false-negative). Pending edits get a stronger blue background + left accent border so they're visible against the token colors. Expansion editor opens with a Monaco inline diff by default and a toggle to fall back to the plain code editor. JSON viewer window and JsonInput toolbar get the same Diff toggle (off by default in the window). Tooltip now serialises objects via formatCellValue so JSON cells stop showing "[object Object]". Backend session carries the original value through so the diff has a baseline to compare against.
Adds a dedicated json_demo table to both seeded databases with the common JSON shapes (flat object, nested, arrays, deeply nested, mixed types, empty values, unicode/emoji, plus a 40-item list on postgres). Includes a text column carrying JSON strings so the "detect JSON in text columns" opt-in can be exercised from the same table.
Collaborator
|
Tested it. |
Contributor
Author
|
done |
RowEditorSidebar now receives the original (un-merged) row data and the per-connection detect_json_in_text_columns flag from the grid, and forwards both through FieldEditor to JsonInput. With a baseline value in scope, the sidebar's JSON field shows the same Diff toggle as the expansion / viewer-window paths. Text columns with JSON content are recognised as JSON fields when the opt-in is on.
The non-fillHeight branch rendered the json-edit-react editor without a height or overflow constraint, so deeply nested objects with long URL strings expanded the tree past the sidebar's bounds and overlapped the toolbar / following fields. Wrapped it in a max-h scrollable container matching the fillHeight branch, with overflow-wrap:anywhere so long strings wrap instead of pushing horizontal scroll.
NewtTheWolf
added a commit
to NewtTheWolf/tabularis
that referenced
this pull request
May 17, 2026
Mirrors the JSON cell affordance from PR TabularisDB#181 for plain string columns whose value is long enough to be cumbersome in the inline grid cell. Closes TabularisDB#207. - isLongTextCellTarget — text-like column + value > 80 chars or contains a newline. JSON / BLOB / geometry / date paths stay untouched. - TextCell renders a single-line preview with a chevron (multi-line values get a ⏎ substitution). No separate viewer window — chevron is the only entry point per design discussion. - TextExpansionEditor opens inline below the row: Monaco in plaintext mode with a manual Diff toggle (default off) against the original. - FieldEditor swaps the plain textarea for Monaco-based TextInput when the sidebar value is long, so the diff toggle is available there too. - Width-aware Side-by-side toggle (Columns2) appears next to the Diff button whenever the editor's container is ≥ 480px. Below that the unified diff is the only mode, so the button doesn't promise a layout that won't fit. Same gating applied uniformly to JSON. - Json/Text Monaco wrappers are unified into a single CellCodeEditor / CellDiffEditor pair that takes a language prop, replacing the four per-language wrappers.
debba
added a commit
that referenced
this pull request
May 21, 2026
* Add password visibility toggles to inputs
* feat: Add connection export and import functionality
This commit introduces the ability to export and import connection
configurations.
The `export_connections_payload` command serializes all connection
groups, saved connections, and SSH connections into a JSON payload. It
also resolves and includes passwords from the keychain for both database
and SSH connections.
The `import_connections_payload` command takes an `ExportPayload`,
merges it with existing configurations, and securely stores any
passwords in the system's keychain. It then saves the updated
configurations to disk.
Additionally, this commit includes:
- A new `ExportPayload` model.
- A unit test for serialization and deserialization of the
`ExportPayload`.
- UI updates in `Connections.tsx` to add export and import buttons.
- Localization updates for export/import related strings.
- Styling adjustments for `ConfirmModal` to support different variants.
* fix(notebook): render db selector dropdown via portal to avoid clipping
The cell wrapper has overflow-hidden, which clipped the absolutely
positioned database selector dropdown when many databases existed.
Render the dropdown through a portal with fixed positioning computed
from the trigger button so the full list (with its 230px scroll area)
is reachable regardless of cell height.
* feat(sidebar): add Discord community callout and update links
* chore: switch Discord invite URLs to discord.com/invite/K2hmhfHRSt
* feat(connections): add import button to empty state
bump tabularis in src-tauri/Cargo.lock to 0.10.2
* feat(plugins): add firestore plugin to registry
* docs: fix Discord shields.io badge server id
* feat: database trigger management (PostgreSQL, MySQL, SQLite)
* chore(plugins): bump firestore plugin to v0.1.0 (stable, Codeberg-hosted)
- Version 0.1.0-beta.1 -> 0.1.0 (semver-strict; the registry schema
rejects pre-release suffixes). The plugin's manifest description
carries the "still effectively a beta" wording in the UI.
- Asset URLs moved from github.com to codeberg.org — Codeberg is the
release host now; GitHub Actions only runs the cross-platform build
and pushes the zips back to Codeberg via the Forgejo API.
- linux-arm64 added (openssl-sys cross-compile blocker fixed by
switching the firestore crate to tls-webpki-roots / rustls).
- Author URL switched to the Codeberg profile to match.
End-to-end install tested against a local custom_registry_url
serving this registry.json — Tabularis pulled the linux-x64 zip
from Codeberg and activated the plugin successfully.
* style(changelog): wrap long version links
* 0.10.3
* fix(export): expand SSH params and refactor into testable utilities
The export command resolved connection params without first expanding
the SSH connection record, so exports failed with "Missing SSH Host"
on SSH-tunneled MySQL/Postgres/SQLite connections. Mirror the pattern
used by every other Tauri command (expand_ssh_connection_params then
resolve_connection_params_with_id).
Also:
- emit a final export_progress event so the UI counter reflects exports
of fewer than 100 rows
- split the macro-based row writer into per-driver streamers
(drivers/{mysql,postgres,sqlite}/export.rs) and pure helpers
(export/{format,progress,sink}.rs)
- delegate JSON array framing to serde_json::ser::CompactFormatter
- add 26 unit tests covering format parsing, CSV/JSON sinks, and the
progress emitter
Closes #184
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* style(editor): polish Export dropdown trigger and menu
- add ChevronDown indicator with rotation when open
- highlight trigger on hover with the project's blue-500/15 convention
- keep highlighted state while the menu is open
- skip hover styles via enabled:hover: when the button is disabled
- give menu items file-format icons and accent hover
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(utils): add newConsole helper, tests, and wire to sidebar
* feat(tabularis-discord-release): add tabularis-discord-release skill and
template
* chore(discord-release): add link buttons and @everyone mention to template
Adds a top-level components row with four link buttons (Release post,
GitHub Release, Changelog, Website) so the Discord announcement no
longer relies on the embed's Links field, which has been removed.
Prefixes the content line with @everyone so the release announcement
pings the server. SKILL.md guard against components is narrowed to
only forbid reactions and polls; link buttons must be preserved
through substitution.
* fix(editor): restore correct SQL string color across all themes
* feat(editor): make Enter accept autocomplete suggestion configurable
Closes #186.
Adds an opt-in setting (Appearance → Editor → "Accept Suggestion with Enter")
that lets Enter accept the active autocomplete suggestion alongside Tab,
mapped to Monaco's "smart" mode so it only triggers when the suggestion
actually changes the text. Default stays off to preserve current behaviour.
* feat(editor)!: enable Enter-accepts-suggestion by default
BREAKING CHANGE: Pressing Enter while an autocomplete suggestion is
highlighted now accepts it instead of inserting a newline. Users who
preferred the previous behaviour can turn it off under
Appearance -> Editor -> "Accept Suggestion with Enter".
This matches what most code editors do out of the box and is the
behaviour users expect (issue #186).
* chore: update roadmap [skip ci]
* chore: update roadmap [skip ci]
* chore: update roadmap [skip ci]
* chore: update roadmap [skip ci]
* chore: update roadmap [skip ci]
* chore: update roadmap [skip ci]
* chore: update roadmap [skip ci]
* feat(editor): foreign key click-to-navigate in result grid
* fix(drivers): share a single connection across multi-statement scripts
Closes #199
The editor's "run all" path dispatched every statement through its own
parallel invoke("execute_query"), with each invoke acquiring a fresh
connection from the driver pool. Statements that depended on
connection-local session state — SET @var, LAST_INSERT_ID() / LASTVAL(),
BEGIN/COMMIT transactions, TEMPORARY TABLE, PREPARE/EXECUTE — silently
failed because the state lived on a connection nothing else in the batch
ever saw.
This change introduces an execute_batch method on DatabaseDriver, a
matching execute_query_batch Tauri command, and rewires the frontend
runMultipleQueries to make one round-trip per script. Built-in drivers
(MySQL/Postgres/SQLite) override execute_batch to acquire one pooled
connection and run every statement on it in order; plugin drivers fall
back to a default implementation that sequentially calls execute_query
(no session-state continuity but ordering is preserved).
MySQL additionally routes transaction-control statements
(BEGIN / COMMIT / ROLLBACK / SAVEPOINT / LOCK TABLES) through
sqlx::raw_sql() so they bypass the prepared-statement protocol that
rejects them (server error 1295).
Side fix included: the three built-in drivers were hardcoding
affected_rows: 0 for every statement, masking silent failures with a
plausible-looking "0 rows affected". Non-result-set statements
(INSERT/UPDATE/DELETE/DDL) now go through the execute() path and
return the real count.
Integration tests (#[ignore]'d, require local MySQL/Postgres):
- @var + LAST_INSERT_ID() chain (Issue's exact repro)
- BEGIN/COMMIT atomicity (text-protocol routing)
- TEMP TABLE visibility inside a Postgres transaction
- INSERT/UPDATE/DELETE affected_rows reporting (MySQL + Postgres)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(i18n): add export/import translations and export warning in locales
* docs(gitnexus-cli): add --drop-embeddings option and clarify post-hook
behavior
* fix(commands): preserve all in-flight abort handles per connection
`QueryCancellationState` used a `HashMap<String, AbortHandle>`, so the
second `execute_query`/`execute_query_batch`/`explain_query_plan` call on
the same `connection_id` orphaned the first task's abort handle. The
earlier Tokio task kept running and `cancel_query` could only abort the
most recently registered one.
Store handles per slot as `Vec<Arc<AbortHandle>>`:
- `register_abort_handle` pushes the new handle and prunes finished ones.
- `unregister_abort_handle` removes the specific handle by `Arc` identity
so a task's own cleanup never targets a sibling.
- `cancel_query` drains the slot and aborts every handle.
Adds unit tests for the helper invariants and an integration test that
runs two `SELECT SLEEP(5)` against the same connection and verifies a
single cancel aborts both.
Closes #201
* fix: incorrect get_app_config_dir when running in mpc mode in windows
* feat(i18n): add Japanese (ja) translation
* feat(json): per-connection "detect JSON in text columns" setting
Move detection from a global toggle to a connection-level setting so users can enable JSON cell affordances only on connections where text columns actually contain JSON.
* feat(json): in-cell JSON highlighting (JsonCell) + inline expansion editor
- JsonCell renders detected JSON with syntax highlighting and a Braces affordance for opening the viewer
- JsonExpansionEditor provides an inline Monaco editor for cell-level edits without leaving the grid
- isJsonContent heuristic + jsonHighlight tokenizer + formatCellValue updates round out the rendering path
* feat(json): multi-mode JsonInput (Code / Tree / Raw editors)
- Refactor JsonInput to host three swappable editing modes: Monaco code editor, json-edit-react tree view, and raw text fallback
- Add JsonCodeEditor + JsonTreeView wrappers, leaf-only tree editing, fillHeight layout mode
- Pull in json-edit-react dependency
* fix(postgres): bind JSON/JSONB columns natively + JSON-encode scalars
- Bind serde_json::Value directly for json/jsonb columns instead of text-with-cast, fixing object/array round-trips
- JSON-encode scalar values for json/jsonb cell display so quoted strings, numbers and bools render correctly
* feat(json): native Tauri JSON viewer window with bounds memory + per-cell dedup
- Add json_viewer Rust module: session store, ULID session IDs, WebviewWindowBuilder, cell-key dedup, last-bounds memory
- Replace JsonViewerModal with a standalone Tauri window (JsonViewerPage + /json-viewer route)
- Grant window close/focus/unminimize capabilities for the new window label pattern
- Support opening the viewer for free-form SELECT results (no PK); falls back to read-only when no save-back path exists
- DataGrid + JsonInput now invoke open_json_viewer_window with a derived cell key so reopens focus instead of duplicating
- i18n: dataGrid.newRow added; jsonViewer keys updated across en/de/es/fr/it/zh
* fix(json): compute missing-session-id error during render, not in effect
Satisfies react-hooks/set-state-in-effect — the empty sessionId case is a derived value from the URL, so resolve it inline instead of setState'ing inside useEffect.
* fix(json): cast JsonTreeView container style spread to satisfy tsc -b
editorTheme.styles?.container is typed as string | object | undefined by
json-edit-react, so the spread tripped TS2698 even though buildTheme always
assigns an object. Cast to Record<string, unknown> at the spread site.
* fix(test): repair test suite after main merge
- Add missing detect_json_in_text_columns field to SavedConnection literal in export_import_tests.rs (introduced by this branch, broke the test added on main)
- Delete tests/components/modals/JsonViewerModal.test.tsx — the modal it tests was removed when the viewer became a native Tauri window
* docs(json): note JSON/JSONB cell viewer + plugin contract
- README + 4 localized READMEs: mention syntax-highlighted JSON/JSONB cells, dedicated editor window, and the per-connection "Detect JSON in text columns" opt-in
- PLUGIN_GUIDE: callout under get_columns explaining that data_type "JSON"/"JSONB" (case-insensitive) enables the viewer, and that execute_query row values may be native JSON or JSON-formatted strings
* feat(demo): add Docker Compose demo with seeded databases
Includes MySQL, PostgreSQL, MSSQL init scripts, README
* feat(branding): add logo SVG files to public
* refactor(cancellation): unify query and explain slots by connection id
extract cancel_query_impl and add tests for multi-handle abort
* fix(export,dump): apply same per-slot abort-handle fix to export/dump/import
`ExportCancellationState` and `DumpCancellationState` had the same
overwrite bug as `QueryCancellationState`: a second concurrent
export/dump/import on the same connection_id orphaned the first abort
handle, so `cancel_*` could only stop the most recent task.
Switch both to `HashMap<String, Vec<Arc<AbortHandle>>>` and reuse the
`register_abort_handle` / `unregister_abort_handle` helpers from
`commands.rs` at all three register sites (`export_query_to_file`,
`dump_database`, `import_database`). `cancel_export`, `cancel_dump` and
`cancel_import` now drain the slot and abort every handle.
Refs #201
* refactor(cancellation): introduce AbortHandleMap alias and import_slot_key helper
Polish from a review pass:
- Add a `pub(crate) type AbortHandleMap = HashMap<String, Vec<Arc<AbortHandle>>>`
alias in `commands.rs` and use it in the three cancellation state structs and
the helper signatures. Removes repeated 5-level generic types from the
signatures and lets `export.rs` / `dump_commands.rs` drop their direct
`tokio::task::AbortHandle` and `std::collections::HashMap` imports.
- Extract `import_slot_key(&str) -> String` in `dump_commands.rs` so the
`"{}_import"` key composition lives in one place instead of being inlined
at both `cancel_import` and `import_database`.
No behavior change. All 8 cancellation_state unit tests still pass.
* feat(json): inline diff for pending changes + fix JSON cell highlight
JSON cells now light up like other modified cells (object-aware
equality check fixed the false-negative). Pending edits get a stronger
blue background + left accent border so they're visible against the
token colors.
Expansion editor opens with a Monaco inline diff by default and a
toggle to fall back to the plain code editor. JSON viewer window and
JsonInput toolbar get the same Diff toggle (off by default in the
window). Tooltip now serialises objects via formatCellValue so JSON
cells stop showing "[object Object]".
Backend session carries the original value through so the diff has a
baseline to compare against.
* feat(demo): seed json_demo table in postgres + mysql init
Adds a dedicated json_demo table to both seeded databases with the
common JSON shapes (flat object, nested, arrays, deeply nested, mixed
types, empty values, unicode/emoji, plus a 40-item list on postgres).
Includes a text column carrying JSON strings so the
"detect JSON in text columns" opt-in can be exercised from the same
table.
* feat(json): sidebar gets diff toggle + detect-JSON-in-text support
RowEditorSidebar now receives the original (un-merged) row data and
the per-connection detect_json_in_text_columns flag from the grid, and
forwards both through FieldEditor to JsonInput. With a baseline value
in scope, the sidebar's JSON field shows the same Diff toggle as the
expansion / viewer-window paths. Text columns with JSON content are
recognised as JSON fields when the opt-in is on.
* fix(json): bound the sidebar tree view so long strings stop overlapping
The non-fillHeight branch rendered the json-edit-react editor without a
height or overflow constraint, so deeply nested objects with long URL
strings expanded the tree past the sidebar's bounds and overlapped the
toolbar / following fields. Wrapped it in a max-h scrollable container
matching the fillHeight branch, with overflow-wrap:anywhere so long
strings wrap instead of pushing horizontal scroll.
* chore: update roadmap [skip ci]
* feat(text): chevron expand + Monaco diff for long text/longtext cells
Mirrors the JSON cell affordance from PR #181 for plain string columns
whose value is long enough to be cumbersome in the inline grid cell.
Closes #207.
- isLongTextCellTarget — text-like column + value > 80 chars or contains
a newline. JSON / BLOB / geometry / date paths stay untouched.
- TextCell renders a single-line preview with a chevron (multi-line
values get a ⏎ substitution). No separate viewer window — chevron
is the only entry point per design discussion.
- TextExpansionEditor opens inline below the row: Monaco in plaintext
mode with a manual Diff toggle (default off) against the original.
- FieldEditor swaps the plain textarea for Monaco-based TextInput when
the sidebar value is long, so the diff toggle is available there too.
- Width-aware Side-by-side toggle (Columns2) appears next to the Diff
button whenever the editor's container is ≥ 480px. Below that the
unified diff is the only mode, so the button doesn't promise a
layout that won't fit. Same gating applied uniformly to JSON.
- Json/Text Monaco wrappers are unified into a single CellCodeEditor /
CellDiffEditor pair that takes a language prop, replacing the four
per-language wrappers.
* fix(diff): word-wrap the original pane in side-by-side mode
Long-standing Monaco bug: the read-only original editor in a
side-by-side DiffEditor refuses to wrap long lines no matter how
wordWrap or diffWordWrap is set on the diff editor or via
updateOptions on the inner editors. Fixes here:
- useInlineViewWhenSpaceIsLimited: false — Monaco's inline-fallback
code path poisons the original pane's wrap state even when the
fallback isn't actually being used (Monaco discussions #4454, #4701).
- key={renderSideBySide ? "sbs" : "inline"} — toggling renderSideBySide
at runtime can leave the original pane's wrap unrecoverable (issue
#3346). React-key remounting sidesteps it by forcing a clean Monaco
instance per mode.
- diffWordWrap: "on" — explicitly inherit wrap into the diff layer.
- Drop originalEditable: false and apply readOnly per-editor via
updateOptions, which Monaco respects without breaking layout.
* feat(sidebar): drag-resizable row editor
The fixed 384px (w-96) width left no room for the new Monaco-based
text input, especially with the side-by-side diff toggle. Adds a
4px drag handle on the left edge of RowEditorSidebar driven by a
new useRowEditorResize hook: width is clamped to [320px, 90% of
viewport] and persisted to localStorage. Default stays 384px so
nothing changes for users who don't drag.
* feat(demo): seed text_demo table for issue #207 manual testing
Adds a focused seed alongside json_demo for the long-text chevron +
Monaco diff feature. Nine rows, each targeting a specific edge case:
short / long single-line / multi-line short / markdown article /
code snippet / multi-line SQL / long VARCHAR(500) / all-NULL / unicode.
MySQL relies on its default \\n-in-string handling; Postgres uses
E'...' escape-string syntax for the multi-line bodies.
* fix(demo): set utf8mb4 client charset on MySQL seeds
The mysql client used by docker-entrypoint-initdb.d does not default
to utf8mb4 in MySQL 8's official image; emoji and CJK literals in
the JSON / blog seeds were double-encoded on insert, so drivers that
honor utf8mb4 read back mojibake even though the columns themselves
are utf8mb4. Adding SET NAMES utf8mb4 at the top of each seed makes
the insert path round-trip cleanly. Requires a fresh volume
(docker compose down -v) to take effect.
* Add support for verify-ca and verify-full SSL modes in libpq
* restore some comments
* chore(demo-connections): split demo postgres into separate
tabularis_demo and analytics_demo
* 0.11.0
* docs(changelog): add 0.11.0 version link
* feat(demo): add MySQL triggers demo and bump version to 0.11.0
* docs(readme): add Japanese README and update language links
* fix(drivers): show pagination for SELECTs with leading SQL comments
`is_select_query` did not strip leading `--` / `/* */` comments before
checking for `SELECT`, while `returns_result_set` and
`is_explainable_query` did. A SELECT preceded by a comment header was
therefore routed to the fetch path but bypassed the pagination branch
in `exec_on_*_conn`, returning `pagination: None` so the UI hid the
controls entirely. Align it with the other helpers.
Fixing the classifier alone exposed a latent bug in `strip_limit_offset`:
it tokenised then rejoined with `" "`, collapsing newlines. For a query
like `-- header\nSELECT ... LIMIT 50` the rejoined output became
`-- header SELECT ... LIMIT 50 OFFSET 0`, which engines parse as one
`--` comment line — silently no-op. Switched the tokenizer to track
byte offsets and made `strip_limit_offset` slice the original input,
preserving comments and whitespace verbatim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* perf: eliminate per-query disk I/O and unblock result display from metadata fetch
* fix(settings): center SettingToggle knob
* fix(drivers): preserve i64/u64 precision past Number.MAX_SAFE_INTEGER
Snowflake-style ids and other BIGINT values above 2^53 - 1 lost their
last digits in the UI because the read path serialised them as JSON
numbers, which JSON.parse on the frontend rounds to the nearest IEEE 754
double.
Add a common helper that emits i64/u64 values as JSON strings only when
they fall outside JS's safe range, and wire it through every place a
driver hands a 64-bit integer to the renderer: MySQL's scalar fallback
(both signed and unsigned), Postgres' INT8 / XID8 / MONEY paths, and
SQLite's INTEGER path. Small values stay native numbers so sorting,
filtering and editing keep working untouched.
Mirror the change on the write-back side: a JSON string that parses as
an i64 outside the safe range is bound as a native integer, so editing
or deleting by a large bigint primary key still matches the row. The
Postgres PK predicate wraps the bind in CAST AS bigint to satisfy
tokio-postgres' strict type checking; MySQL and SQLite rely on their
implicit numeric coercion.
Closes #210
* feat(demo): seed bigint_demo table for issue #210 manual testing
Mirrors the text_demo / json_demo pattern with seven rows that exercise
the JS-safe-integer boundary from both sides: small values that stay
JSON numbers, the 2^53 / 2^53 - 1 boundary, the snowflake id from the
original report, i64::MAX, a u64 value above i64::MAX, and a negative
snowflake. Postgres also covers xid8 and money since both are backed by
64-bit integers.
* feat: Delete selected rows with keyboard shortcut
* chore(icons): redesign macOS dock icon
Replace icon.icns with a Tahoe-style squircle on a light glass background.
Windows .ico and Linux PNGs are left untouched.
* fix(pg): correct handling of TLS/SSL modes in PostgreSQL connection
* revert: remove unintended CHANGELOG changes
* Apply suggestion from @kilo-code-bot[bot]
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
* Apply suggestion from @kilo-code-bot[bot]
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
* test(connection_cache): cover Hit/Miss/Cold transitions and populate/invalidate cycle
* test(updater): gate Linux-only installation source tests
* test(updater): gate Linux-only installation source tests
* docs(sponsors): add DigitalOcean sponsor to README and SPONSORS
* feat(i18n): add Russian locale and count-based tab pluralization
---------
Co-authored-by: cole <imzhpe@qq.com>
Co-authored-by: ymadd <18324681+ymadd@users.noreply.github.com>
Co-authored-by: Andrea Debernardi <andrea@debbaweb.it>
Co-authored-by: NewtTheWolf <dominik@spitzli.dev>
Co-authored-by: Thomas Müller-Wasle <thomas.mueller1401@gmx.de>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: starasenko <starasenko-ext@goodgamestudios.com>
Co-authored-by: vlor <vlor@foxmail.com>
Co-authored-by: Nikolay Zhuravlev <s.verbaux@gmail.com>
Co-authored-by: vlor <614316365@qq.com>
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Closes #24.
Adds JSON/JSONB handling to the data grid: per-cell affordances, inline expansion editor, a native Tauri window for full-screen viewing/editing, and a per-connection toggle for detecting JSON inside plain text columns. PostgreSQL driver now binds structured JSON values directly on INSERT and UPDATE.
Notable bits
Mutex<HashMap>keyed by ULID; save flows back to the grid via thejson-viewer:savedTauri event.detect_json_in_text_columnsis per-connection, not global. Toggle in the connection edit modal. Same flag gates native array detection (text[],int[], Firestore arrays).serde_json::Valuedirectly forjson/jsonbcolumns via tokio-postgres'with-serde_json-1impl.insert_recordfetches column types once and threads them throughbind_pg_value.Files of interest for review
src-tauri/src/json_viewer.rs— new module, 3 commands, ULID sessionssrc/pages/JsonViewerPage.tsx— standalone window pagesrc/components/ui/DataGrid.tsx— Tauri event listener + window-open pathssrc-tauri/src/drivers/postgres/binding.rs+mod.rs— json/jsonb bindingTest plan
jsonbcolumn: chevron expansion, braces opens viewer, double-click opens viewer in edit modejson/jsonbsucceedpnpm tsc --noEmit,pnpm vitest run,cargo testgreenDesign refs: DBeaver Value Panel, DataGrip Value Editor.