All notable changes to DBFlux will be documented in this file.
-
Amazon S3 driver (DBF-26) — A first-party object-storage driver for AWS S3 and S3-compatible endpoints. The connection root shows a buckets table (name, region, object count, size, versioning, created); the sidebar lists buckets flat, one level deep. The object browser follows AWS-console-style per-level pagination by default, with an optional lazy tree mode for full expansion. The preview pane renders images and SVGs natively, opens text-like objects (txt, md, json, csv, log, ...) in an inline editor with dirty tracking and Ctrl+S save-back, and falls back to metadata plus download/open-externally for PDF and other binary objects; preview size is capped at a configurable 10 MiB, and archived storage classes (GLACIER, DEEP_ARCHIVE) never fetch a body. Full object CRUD covers upload, delete, type-to-confirm recursive prefix/bucket delete batched in groups of 1000, folder and bucket creation with per-endpoint option degradation, rename via copy-then-delete, and presigned URLs. A full editor tab with an in-editor find panel, a resizable object-details pane, and a row context menu round out the browsing experience. Authentication supports AWS profiles/SSO or static credentials, with custom endpoints for Cloudflare R2, MinIO, and path-style addressing. Every mutation is audited under a new object-storage event category, and a MinIO-backed live integration suite runs in CI. Deferred: multipart upload with a transfers panel, and an embedded PDF viewer.
-
Amazon Redshift driver (read-only) (DBF-23) — A first-party Redshift connection for browsing and querying analytical warehouses. Connect over the PostgreSQL wire protocol (host, port
5439, database, user, password; TLS with optional custom root CA and client-certificate mTLS; optional SSH tunnel), browse schemas, tables, views, and columns, and run read-onlySELECTqueries. Table details surface Redshift-specific distribution and sort keys plus advisory (non-enforced) primary/foreign/unique constraints as storage hints, shown through a generic sidebar seam that any driver can populate.NUMERIC/DECIMALvalues are decoded from the binary wire format. This first release is read-only:INSERT/UPDATE/DELETE, inline editing, and multi-statement input are rejected with a clear error; IAM/SSO auth,COPY/UNLOAD, and query-plan visualization are not yet supported. -
Context-aware SQL autocomplete in the query editor — Completion in the SQL editor now follows where the cursor sits instead of listing every identifier the connection knows: tables and views after
FROM/JOIN, columns scoped to the tables actually referenced in the statement, relation aliases, CTE names, andSELECToutput aliases inGROUP BY/ORDER BY/HAVING. It parses with tree-sitter so it holds up on half-typed queries, prefetches column metadata in the background so a table no longer needs a sidebar expand first, and hydrates from the latest deep schema snapshot on connect so it starts warm after a restart. Every relational driver benefits; non-SQL dialects keep their existing keyword completion. -
Data transfer — Export, Import, and same-engine Migration for SQL databases — A new transfer engine moves SQL data without leaving DBFlux. Multi-select tables in the sidebar and Export them to a folder (one CSV or JSON file per table plus a
manifest.jsonthat makes the bundle re-importable), Import a previously exported bundle into a connected database, or Migrate tables directly from one connection to another through a guided, multi-phase wizard — pick the source tables and the target database from a connection → database → schema → table tree, review the mapping in a Source / Target / Mapping / Transform grid, and move through Options, Confirm, and Run steps tracked in a phase sidebar, in a larger centered modal. Migration orders tables by foreign-key dependencies (parents before children), with a manual reorder step when the graph has cycles and an optional disable-referential-integrity toggle during transfer. Target tables can be auto-created from the source schema (Create / Use existing / Recreate / Skip), columns auto-map by name with adjustable overrides, and destructive modes (Recreate, Truncate) require explicit confirmation. This first release covers same-engine SQL transfers (PostgreSQL, MySQL/MariaDB, SQLite, SQL Server); cross-engine and NoSQL migration are not yet supported. -
Export / import standalone profiles from Settings (#214) — SSH tunnels, proxies, and auth profiles can now be exported and imported directly from their Settings sections, building on the connection portability pipeline (#213). Each profile editor gains an Export action in its footer (keyboard-navigable alongside Save / Delete) that opens the same passphrase-encrypted TOML bundle modal, scoped to that single profile; each section's list header gains an Import… action (also reachable with
iwhen the profile list is focused) that opens the import wizard with its conflict / required-reference resolution. The import wizard now presents as a modal dialog with the same chrome as the export modal — in Settings and in the Connection Manager alike — so export and import look and behave consistently. AWS reflected auth profiles stay reference-only and cannot be exported. Secret material travels only inside the encrypted secrets section, passphrase encryption is on by default, and the bundle format is unchanged. -
Export / import connection profiles as a portable bundle (#212) — Connection profiles can be exported to a single passphrase-encrypted TOML bundle and imported on another machine, with a wizard that resolves name conflicts and required references. A driver seam (
ExportFieldHint) decides per field what travels: regular values are included, passwords and write-only fields go into the encrypted secrets section, local file paths are flagged as machine-local, and environment-local references (AWS named profiles, auth-profile references) are marked required-on-import so the user supplies them on the target machine. -
Schema diff & apply (DBF-24) — A schema-drift comparison now works at the table-set level, not just per table: added, removed, and modified tables are detected by
(schema, name)identity, and each individual change (column added/removed/renamed, type or default changed, index added/removed, constraint added/removed, primary-key changed) is annotated with its governance risk through the same classifier the MCP layer uses, so risky operations are labelled consistently everywhere. The drift modal renders the new change kinds and the resulting migration can be applied from the UI. -
Cross-driver query tooling — PartiQL editor and Document-driver builder — The query editor and visual builder are no longer SQL-only. A new
EditorLanguageProfileseam onDriverMetadatadrives highlighting, placeholder, comment prefix, connection-context controls, and live diagnostics from driver metadata instead of the query language enum, and the builder now opens for any driver whose capabilities support it, sourcing its sections and operators fromQueryCapabilities. In practice this gives DynamoDB a full PartiQL surface — SQL-style highlighting, context-aware autocomplete over the table and its sampled attributes,SELECTreads and governed writes throughExecuteStatement, and sort-key-only ordering — and gives MongoDB read generation from the visual builder. No-WHEREPartiQLDELETE/UPDATEis flagged as dangerous through the shared classifier. Relational drivers are unchanged. -
Per-channel app icon and identity (#183) — Nightly builds now ship their own brand mark, application id (
dbflux-nightly), window title, desktop and MIME entries, and database file, so a nightly install coexists with a stable one instead of sharing its taskbar entry and data. The channel is derived once from the compiled version, and nightly can opt into sharing the stable database from Settings. macOS and Windows move onto the same design-system mark as Linux; stable packaging output is byte-identical to before.
-
Standalone MCP server failed to start and listed no tools — The governance binding role/policy repositories queried table names that did not match the migrated schema, so
dbflux mcpaborted with "no such table" for any profile with a governance binding (the same mismatch also broke saving these bindings in the main app). Startup then panicked on a blocking lock read inside the async runtime, andtools/listreturned an empty catalog because the tool handler served an empty router instead of the combined one. -
SSH tunnel / proxy list icon vanishing on long hosts — The globe icon in the Settings SSH tunnels and proxies lists could be squeezed to zero width by long, unbreakable hostnames (e.g. EC2
ec2-…compute.amazonaws.comaddresses), so some rows appeared to have no icon. The icon container is nowflex_shrink_0and the text columnmin_w_0, so the icon always renders and the subtitle truncates instead. -
Shutdown left connections and background work dangling —
SIGINTandSIGTERMnow run the same graceful shutdown path as closing the window, so connections, hooks, and background tasks are torn down instead of being killed mid-flight. -
Connection hooks were dropped when a profile was saved — Editing a profile could discard its hook bindings, and the hook "test" run did not execute the configured phases. Both are fixed, and hook phases run as configured.
-
Duplicate Settings windows — Closing and reopening Settings could leave a second window behind; only one Settings window can now exist at a time.
-
Sidebar context menus escaped the window and drifted — Context menus and their submenus are now anchored to the owning row instead of trailing the cursor, and are repositioned to stay on-screen near window edges.
-
Single-database connections lost their lazy nodes — Sidebar refresh could collapse a lazily loaded single-database node and drop its children.
-
MySQL / MariaDB panicked when connecting over TLS (#291) — SSL connections aborted the process instead of returning an error.
-
Main window did not come to the front on a second launch — An IPC focus request now activates and raises the existing window.
-
Inline table editing discarded typed text — Text typed into an inline cell editor could be reset before commit.
-
Audit CSV export was not RFC 4180-safe — Text columns are now escaped correctly, so exports containing quotes, commas, or newlines round-trip losslessly.
-
Settings number inputs collapsed on first layout — General settings number fields are laid out in a flex row with a definite width, so they no longer render zero-width until the first resize.
-
MCP governance, audit, and DDL integrity hardening (MCP-1..6) — Fixes across policy evaluation, audit persistence, and DDL classification in the MCP governance stack.
-
Security and reliability hardening (SEC2-3..5, MISC-1..15) — MySQL hex literal handling, storage file permissions,
process.runPATH visibility, atomic migration bootstrap, non-panickingSystemTimeuse, and bounded IPC reads, plus assorted reliability fixes. -
Packaging and CI — The nightly binary build resolves brand-mark locations correctly,
dbflux-nightlyis exposed through the Nix overlay with a stamped build version, nightly release notes are scoped to commits since the previous nightly, and stale nightly assets are pruned.
-
Visual UPDATE / DELETE query builder (#163) — The
QueryBuilderPanelgains a mode selector that extends the visual SELECT builder with UPDATE and DELETE modes, reusing the relational filter bar forWHEREcomposition. The SQL preview is always visible and regenerates synchronously on every builder change. New core types (VisualMutationSpec,MutationKind,ColumnAssignment,AssignmentValue) feedQueryGenerator::generate_update_from_spec/generate_delete_from_spec, which emit keyset-paginated chunked DML for all four SQL dialects; a raw-expression assignment is tracked via aused_raw_expressionflag rather than a textual marker. Execution runs through aMutationExecutorstate machine with three modes —SingleTransaction,ChunkedTransaction,DirectAutocommit— auto-suggested from the count estimate, theTRANSACTIONScapability, and primary-key availability, with a tradeoff modal on user override. Chunked runs use keyset pagination over the table PK (chunk size clamped to[1000, 10000], default 5000), surface per-chunk entries in the Tasks panel with cancellation between chunks, andROLLBACKon chunk failure. No-WHEREUPDATE/DELETE is gated by a doubled spec-level + text-levelDangerousQueryKindcheck, and a newMutationPolicyseam (Allowed/ReadOnly/ApprovalRequired) composes MCP-actor, per-profile read-only, and default resolution. Driver-agnostic by construction: gated onQueryLanguage::Sqlwith no per-driver branching. -
Inline edit on builder-generated SELECT results (#170) — Inline cell edit and row delete now work on results produced by the visual query builder, not just plain table browses, when the result is provably editable-safe: it maps 1:1 to a single underlying table and every primary-key column of that table is projected under its original name. The builder computes an
EditableBindingfrom the committedVisualQuerySpecand threads it into the DataView, so edits and deletes reuse the existing single-table mutation path with aWHEREbuilt from the projected PK values — no parsing of the generated SQL. JOINs are allowed: columns originating from the source table are editable while joined columns are marked read-only. The result falls back to read-only — with a toolbar hint explaining why — when any rule fails: aggregates /GROUP BY/HAVING, a wildcard projection across a JOIN, a primary key that is missing or projected under an alias, or a schema cache that has not yet loaded the table's keys (the grid upgrades to editable on its own once the keys arrive). Free-form editor SQL stays read-only; this is scoped to builder- generated queries. Driver-agnostic by construction: the editable-safe proof lives indbflux_coreover generic spec and metadata types with no per-driver branching, so every relational driver picks it up. -
GROUP BY and aggregates in the visual query builder (#161) — The visual SELECT builder gains a
Group By / Aggregatessection between Joins and Sort, with a separateHavingsection that reuses the same predicate editor asFilters(WHERE). Supported aggregate functions:COUNT,COUNT(*),COUNT(DISTINCT),SUM,AVG,MIN,MAX, each with an editable alias that auto-generates from the function and column. When the spec becomes grouped, the projection section is replaced by a read-only effectiveSELECTpreview composed of group columns followed by aggregate aliases; sort entries are restricted to group columns and aggregate aliases, with invalid entries rejected with a visible error. The DataView reshapes in place: rows reflect the aggregated result, pagination switches to aCOUNT(*)subquery over the grouped SELECT so the total page count is accurate, and aggregate result columns receive the correctColumnKindso chart auto-detection keeps working (COUNT*→ Integer,AVG→ Float,SUMpreserves Integer/Float,MIN/MAXpreserve input). Editing is gated when the result is aggregated: add-row, delete-row, edit-cell, and inspect-row become unavailable with explanatory tooltips, and the footer surfaces a count of incomplete aggregate rows so silently-dropped rows are visible to the user. Driver- agnostic by construction: gated onQueryLanguage::Sqlwith no per-driver branching, and the existingSqlSelectBuilderis extended withbuild_group_by,build_having, andbuild_count_of_groupedshared across SQLite, PostgreSQL, MySQL/MariaDB, and SQL Server. -
Schema-aware autocomplete for the visual query builder and DataView filter (#165) — Inline suggestion popovers now appear on the builder rail's single-line inputs (filter / sort / projected columns, join target table, join
ONleft and right sides) and on the DataView toolbar's WHERE filter input. Suggestions are sourced from the live schema and the builder's own spec — source-table columns, declared join aliases (alias.column), and joined-table columns fetched lazily through the existing background metadata pattern. After typing<alias>., results are scoped to that alias's columns only. Arrow keys navigate,Tab/Entercommits,Escand focus loss dismiss. Prefix-only filtering for now (substring and SQL keyword completion are deliberately deferred). Driver-agnostic by construction: suggestions consumedbflux_coremetadata types without branching on driver id, so every relational driver picks the feature up automatically. -
Relational filters in the DataView filter bar (#162) — The filter bar now accepts ORM-style dotted paths like
created_by.email LIKE '%@acme.com'orcreated_by.organization.name = 'Acme'. Paths are resolved against foreign-key metadata cached on the data grid; the resolver lowers the expression into aVisualQuerySpecwithJoinOn::FkPathjoins and routes it through the same builder pipeline that ships with the visual SELECT builder (#146), so there is no second SQL generation path. Ambiguous segments surface an inline chip with an "Open in builder" action seeded with the joins resolved so far. The feature is driver-agnostic and gated onQueryLanguage::Sql; non-dotted input keeps today's raw-WHERE behavior. -
Visual SELECT query builder (#146) — A right-rail query builder composes SELECT statements without writing SQL: projection, FROM with alias, JOINs, a recursive
WHEREpredicate tree,ORDER BY, andLIMIT/OFFSET, with a live parameterized SQL preview. The foundation is the newVisualQuerySpec(and supportingFilterNode,Predicate,JoinStep,JoinOn,Projection,SortEntrytypes) indbflux_core, rendered bySqlSelectBuilderbehind the defaultedQueryGenerator::generate_selecttrait method with dialect-specific placeholders for SQLite, PostgreSQL, MySQL/MariaDB, and SQL Server. Builders can be saved and reopened: migration 017 addsqry_saved_queriesand its child tables (columns, sorts, joins) with cascading FKs and aUNIQUE (profile_id, name)constraint, fronted bySavedQueryRepoand an in-memorySavedQueryManager. ATableProbeseam verifies table existence when importing a saved query onto another connection without reaching into driver code. Acolumn_kindinference fallback mapstype_nametoColumnKindso charts keep working on builder results. Driver-agnostic by construction: gated onQueryLanguage::Sql. -
Instance metrics charts and inspectors across drivers (#93) — PostgreSQL, MySQL/MariaDB, MongoDB, Redis, and SQL Server now expose live server metrics (time series) and tabular inspectors (sessions, processlist, currentOp, CLIENT LIST) through a new
InstanceCatalogdriver seam and two capability flags:INSTANCE_METRICSandINSTANCE_INSPECTOR. Each catalog publishes a driver-defined Instance Overview dashboard that opens read-only and can be cloned via "Save as editable" into a persisted, user-owned dashboard. Dashboards gain a newInspectorpanel kind alongsideChartandDivider, persisted viaviz_dashboard_panels.panel_kind(migration 014). Inspector rows expose driver-supplied row actions (e.g. Terminate connection / Kill session) gated by per-driver privilege probes (pg_monitor,PROCESS/CONNECTION_ADMIN, MongoDBkillOp, RedisCLIENT KILL). Destructive actions route throughreport_error_asyncso failures land in the audit log with a correlation id, and every refresh timer (dashboard, chart, inspector) skips its tick when the underlying connection is gone so closing a connection no longer floods the toast layer. -
External RPC drivers and auth providers can emit audit events (#157) RPC-backed drivers (driver protocol v1.2, capability
AuditEmit) and auth providers (auth-provider protocol v1.3, hello flagaudit_emit_opt_in) can now write to the audit log over IPC by sendingEmitAuditEventframes as intermediatedone=falseresponses. The host sanitizes every event: forcesactor_type/source_idto newExternalDriver/ExternalAuthProvidervariants, fillsactor_idwith the registered RPC service ID, overrides connection context fromAppState, enforces a per-source category whitelist (drivers:Connection/Query/System; auth providers:Connectiononly), and truncatesdetails_jsonto the configuredmax_detail_bytes. A per-socket_idtoken-bucket rate limiter (100 events/minute, configurable) caps emission; overflow events are dropped silently — the IPC session is never blocked or errored — and counted onAuditService::external_audit_dropped. Older RPC peers that don't advertise the capability/flag remain silent.
- Centralized user-facing error reporting (
report_error/report_error_asyncindbflux_ui_base). Failures across mutations, file save, settings, and workspace actions now surface as a styled toast with a "View in Audit" action, increment a status-bar error badge, and emit a tracing event correlated with the audit row (#156). EventRecord.correlation_idis now populated from thecorrelation_idtracing field across alldbfluxtargets, regardless of whether the field is recorded via%(Display) or?(Debug) sigil (#156).- Tracing-to-audit bridge for centralized log capture (#154) — A new
tracing-bridgefeature installs anAuditLayersubscriber in thedbflux,dbflux_mcp_server, anddbflux_driver_hostbinaries that funnelstracingevents into the audit log through a bounded background queue with an atomic drop counter and in-flight gauge. A configurablelog_capture_min_levelaudit setting (defaultinfo, persisted via migration 014) gates capture and updates the shared level atomic immediately. The layer applies a recursion guard, level gate, and summary truncation, andAuditService::dropped_log_event_count()exposes overflow drops.
- Toast host applies a severity-aware throttle (capacity 5, refill 1 token / 2 s) to Warning and Info toasts so connection-storm noise does not bury the UI; Error and Fatal toasts bypass the throttle (#156).
- Provider-neutral auth-profile edit seam (#155) — The auth-profile edit path no longer carries AWS-specific types in the public core API.
dbflux_core::auth::editnow exposes a provider-neutralAuthEditSnapshot(opaqueArc<dyn Any>),AuthEditTarget, andAuthSaveOutcome; the formerAwsEditFile/AwsEditSnapshot/AwsSectionHashtypes moved to a privatedbflux_aws::editmodule, andAuthProviderCapabilitiesgained an optionaleditfield (serde-defaulted for backward compatibility). All three AWS providers were rewired to the neutral types with no behavior change.
- Scripts-tab folders can be collapsed again — Chevron clicks were routed through the connections tree only, so script-folder expansion lookups always returned
falseand every click tried to expand. Toggling now routes through the active tab's tree, propagates the override into the scripts tree state, and applies expansion overrides when building script items so collapses survive a refresh. - Syntax highlighting preserved across
AppStateChanged—CodeDocumentre-applied the highlighter mode on everyAppStateChanged, andInputState::set_highlighterclears the cached highlighter until the next render — wiping SQL coloring after running a query until the next keystroke. The document now tracks the last appliededitor_modeand only re-applies the highlighter when it actually changes. - NULL rendered as an empty field in CSV export — CSV export emitted the PostgreSQL
\COPYsentinel\Nfor NULL, which most CSV consumers (Excel, Sheets, generic parsers) read as the literal string. NULL now exports as an empty field, the de facto CSV convention. - Inactive tab background no longer mismatches the tab bar.
- Multiline UPDATE/DELETE no longer falsely flagged as missing a
WHERE— The dangerous-query check matched only the literal substring" where ", so aWHEREplaced on its own line (preceded by a newline rather than a space) was never found and the statement was wrongly reported as affecting all rows. Detection now strips single-quoted string literals (honoring''escapes) and matcheswhereas a whitespace/paren-delimited token, fixing the false positive for both UPDATE and DELETE while still catchingwheretext that only appears inside a value. - Chart auto-detection across four drivers (#204) — Drivers now assign
ColumnKindhonestly so the chart engine includes genuine numeric columns and excludes non-plottable ones. CloudWatch CWL Insights@timestamp/@ingestionTimevalues are normalised from CWLI format to RFC3339, and the kind scanner skipsTextsamples so mixed-type columns resolve correctly. DynamoDB infers kind fromAttributeValue, MongoDB from BSON value types (BSONTimestampstaysUnknown— it carries no wall-clock meaning), and InfluxDB Flux/InfluxQL classifybooleanasInteger.Value::Boolplots as 0/1 across all drivers, andValue::DateTime/Value::Dateare extracted as epoch-milliseconds on a time axis.Value::Timehas no absolute epoch, so SQL ServerTIMEcolumns are classifiedUnknowninstead of being offered as an empty time axis.
- Saved charts, dashboards, and CloudWatch dashboard browsing (#152) —
Charts created from query results can now be saved, organized into
dashboards, and reopened from the sidebar. CloudWatch connections gain a
browse view that lists the account's dashboards as a read-only catalog so
they can be inspected without round-tripping through the AWS console.
The change also lands the workspace's PaneHandle/ResultPanel refactor:
document tabs share a single closure-erased shell and a universal chrome
row built from
ToolbarSegments, so the mode bar, filter bar, and refresh dropdown wrap responsively on narrow windows instead of pushing controls off-screen. - AWS profiles reflected live from
~/.awsas source of truth (#149) — AWS SSO, SSO-session, and shared-credentials profiles are now enumerated on demand from~/.aws/configand~/.aws/credentialsvia mtime-guarded caches, with a deterministic UUIDv5 identity per(provider_id, name)so reflected profiles are stable across launches without ever being stored. DBFlux holds zero AWS key material on disk (ADR-7): the static-credentials provider and its write-back paths are gone, and all~/.aws/configwriters now go through the atomic locked primitive so concurrent edits can no longer truncate the file. Reflected entries surface in the auth picker as read-only and are distinguished from stored profiles by a newAuthProfile.read_onlyflag. - AWS SSO sessions as first-class auth profiles — A new
aws-sso-sessionauth provider models the[sso-session NAME]block of~/.aws/configas its own profile, andaws-ssoprofiles reference it via a genericFormFieldKind::AuthProfileRefdropdown instead of duplicatingsso_start_url/sso_regioninline. A newexpand_auth_profile_refspass merges the referenced session's fields into consumers at pipeline-input and MCP-resolution time (consumer overrides win). Settings now renders the selected session as inert text viadisabled_when_field_set, and the AWS-profile importer routes[sso-session …]blocks into the session provider so re-importing matches sessions by name. Account/role dropdowns always probe with a session marker, so they populate as soon as a valid SSO session exists without forcing a new login. - Copy-to-clipboard export from the data grid (#153) — The data-grid export menu now offers Copy to clipboard alongside Save as file for every text-friendly format. Binary export is deliberately disabled with guidance to use Hex or Base64 instead.
- Single Settings window across all entry points — The four entry points
that opened Settings (workspace action, auth-profiles deep link, Connection
Manager section jump, sidebar footer) now all funnel through a shared
open_or_focus_settingshelper. Previously only the workspace path usedAppState::settings_windowfor dedup, so the other three could stack duplicate Settings windows on top of each other.
- Native file dialog now has a fallback path with user feedback (#153) —
rfd::AsyncFileDialog::save_file()returnsNoneon both user-cancel and backend-failure, so on Linux systems withoutxdg-desktop-portal/zenity/kdialogthe data-grid export and script Save As silently dropped the action. DBFlux now pre-flights the backend via a PATH probe; when none is available it writes to~/.local/share/dbflux/exports/with a non-clobbering filename, raises a warning toast, and emits aresult_export_fallbackaudit event. When a backend exists,Noneis treated as a genuine cancel. Script Save As mirrors the same pattern and now surfaces write failures via toast instead of a silent log line. - Schema drift modal no longer fires on every SELECT for multi-FK tables
(#151) — The MySQL/MariaDB and MSSQL drivers built their foreign-key
list from a
HashMap's values, whose iteration order is nondeterministic. Drift compares cached vs fresh foreign keys positionally and hashes the fingerprint in order, so two identical fetches in a different order looked like a change. Both drivers now useForeignKeyBuilder::build_sorted(), matching the order the SQLORDER BYalready specifies and the Postgres driver's behavior. - MariaDB and InfluxDB profiles default to the correct config variants
—
default_db_config_for_kindfell through todefault_postgres()for MariaDB and InfluxDB, so a profile loaded via this fallback got a Postgres config while keeping its real kind; saving then persisted the mismatch, and connecting failed with "Expected MySQL configuration" for MariaDB. MariaDB now maps todefault_mysql()and InfluxDB todefault_influxdb(); the catch-all arm is removed so newDbKindvariants fail to compile instead of silently degrading to Postgres. - AWS SSO login no longer hangs after a successful browser flow — The
cache lookup that polled for the new SSO token relied on
sha1(start_url)as the filename. AWS CLI v2 actually names the filesha1(session_name)whenever the profile uses ansso_sessionblock, so the fast path silently returned an unrelated, expired file and the polling loop spun forever even afteraws sso loginprinted "Successfully logged into Start URL".find_sso_cache_contentsnow always scans the cache directory and picks the newest entry whosestartUrlfield matches, covering both the legacy URL-keyed and modern session-keyed schemes. - Inline SSO login panel replaces the cross-window modal — The login
panel, verification URL, Open Browser / Copy URL / Cancel buttons,
and the new
abort_sso_loginplumbing now live inside the Auth Profiles settings section. Cancel actually kills the runningaws sso loginchild process via a shared abort flag and a per-profile abort registry. The stdout scanner was also rewritten with a boundedrecv_timeoutloop so PKCE-flow URLs (which never printuser_code=) are surfaced immediately instead of blocking indefinitely.
- Metric picker rail tab for chart documents — CloudWatch metric charts now
open with an interactive picker rail (320 px overlay) that lets users browse
namespaces, metrics, and dimension combinations fetched live via
ListMetricspagination. Selecting a metric and pressing Apply swaps the chart's data source and auto-runs the query. Results are cached for the session byMetricCatalogCache. No driver names or categories are hardcoded in the UI layer; the Metric tab is gated solely on the genericMETRIC_CATALOGcapability bit (#96). - Time-range macros for InfluxQL and Flux — user-written InfluxDB queries
can opt into UI-driven time-range substitution via Grafana-style tokens
(
$timeFilter,$__from,$__tofor InfluxQL;v.timeRangeStart,v.timeRangeStopfor Flux). Substitution happens at the execution chokepoint in bothCodeDocumentandChartDocument; the InfluxDB driver's inject-when-absent path is skipped when macros are present so they take precedence without double-injection. Queries without macros keep today's byte-for-byte behavior. Documented in the driver README (#119).
- Driver-owned connection form definitions — Built-in connection form
schemas moved out of
dbflux_coreand into their owning driver crates. Core now keeps only the genericDriverFormDefprimitives and helper builders, while the connection manager reads forms through the existingDbDriver::form_definition()seam. This removes driver-specific defaults, URI placeholders, tab layouts, and conditional field rules from core with no connection-manager behavior change (#140). - Dialect-specific language services leave core — SQL Server's
TSqlLanguageServicenow lives indbflux_driver_mssql, matching the MongoDB and MySQL driver-owned language-service pattern. Core retains the genericLanguageServiceseam and shared SQL helpers, but no longer exports the T-SQL-specific implementation (#129). - MongoDB and Redis dangerous-query detection moved to drivers — MongoDB
and Redis dangerous-operation classifiers now live in their driver language
services, and code execution asks the active connection's language service
to classify dangerous queries. Core still owns the shared
DangerousQueryKindtype and SQL classifier, but no longer exports Mongo/Redis-specific detection helpers (#139). - Sidebar collapses single-database wrapper — Connections whose driver
exposes exactly one database (CloudWatch's
logs, DynamoDB's default region, single-file SQLite, etc.) no longer render the redundant database level. Child nodes (Collections, Metrics, Tables) attach directly under the connection node. Multi-database drivers (Postgres, MySQL, MongoDB) are unaffected — the wrapper still discriminates between databases (#131). - CloudWatch metric catalog hardening — The
RealCloudWatchClientadapter now reuses a single long-lived Tokio runtime acrosslist_metricscalls (previously a new runtime was constructed per call, wasting file descriptors during full-namespace sweeps). The namespace sweep is also bounded at 50 pages (~25,000 metrics) to cap the worst case on very large AWS accounts; the cap is documented in the driver README. A future change will replace the cap with full timeout + cancellation infrastructure (#96). - Sidebar metric leaves dedupe by metric name — On accounts with
per-instance metric explosion (e.g. AWS/EC2 with 1000 instances) the
CloudWatch driver returns one
MetricDescriptorper(metric_name, dimension_combo)pair. The sidebar now collapses these into one leaf per distinctmetric_name; dimension refinement still happens inside the chart document's picker rail (#96). - Metric chart entry point moved to the sidebar — Clicking a metric leaf in the connection sidebar (Metrics > Namespace > Metric) opens a chart pre-populated with defaults (Average statistic / 5 min period / aggregate across all dimensions) and immediately executes it. The picker rail opens alongside for refinement of dimensions, period, and statistic. Duplicate clicks on the same metric leaf focus the existing tab (#96).
- Centralized
TimeRangePanelcustom-picker rendering — A newrender_custom_picker_rowhelper (andCustomPickerSlotsfor hosts that need per-slot decoration) is shared acrossChartDocument,CodeDocument, the data-grid chart toolbar, and the audit document. The data-grid chart toolbar gains the custom date/hour/minute picker that previously was missing under "Custom…", and audit migrates off the last hand-rolled row. Behavior-preserving — public accessors and emitted events are unchanged (#121). - Chart toolbar wraps on narrow viewports — The shared chart toolbar
used by
ChartDocumentandDataGridPanelswitched from a single non-wrapping flex row to the codebase's responsive pattern (flex_wrap+gap_x/gap_y,min_h(34px)). Trailing controls (TYPE chips, Stats / PNG / Save) no longer push off-screen when the document is narrow; rows grow downward instead of clipping (#136). - Stats rail gains an in-rail close affordance —
ChartDocument's Stats rail now renders a header with a STATS title and an×close button so users can dismiss it without hunting for the toolbar toggle (#136).
open_metrics_chartworkspace action and command-palette entry — the sidebar tree is now the single entry point for metric charts.ChartDocument::new_empty_metric_chartconstructor — replaced bynew_with_sourcewith a pre-builtMetricSourceandsetup_metric_picker.
- Command palette keyboard navigation follows visual sections — Filtered command-palette items now sort by rendered section order before match score, so Up/Down navigation moves through Connections, Commands, Charts, Tables, and Scripts exactly as displayed. Pressing Up from the first item in a section now lands on the previous visible section instead of jumping within the score-sorted backing list (#143).
- Modal sizing & button overflow — three confirm dialogs (Run entire
script, Dangerous query, sidebar Delete/Drop) now use the shared
ModalShellprimitive with consistent widths and a dedicated footer button row. Buttons no longer overflow into the body, and the Drop Database / Delete confirms no longer render at half the size of the other confirm modals (#130). - Chart axis tick density on wide/tall plots — Three targeted
adjustments to the chart engine raise tick density without over-ticking
small charts:
NICE_TIME_STEPS_MSgains 2h / 3h / 12h / 2d / 3d entries (a 3-week range with 12 target ticks no longer collapses to 3 weekly ticks), the X-tick clamp floor drops from 4 to 3 so ~400px charts can render 3 ticks, and the Y-axis target switches from a build-time constant of 5 to a render-time(plot_h / 60).clamp(3, 12)that mirrors the existing X dynamic path (covers line / area / StackedBar / log). PR #123's dynamic edge-label padding is preserved (#132). ChartDocumentStats rail toggle now actually renders — The toggle state machine was complete butrender_chart_contenthad noChartRailTab::Statsbranch, so clicking Stats appeared to do nothing. The rail now renders for query-result, saved-chart, and CloudWatch metric hosts with SERIES / STATS / WINDOW / SOURCE sections matchingDataGridPanel. Closes #133 (#136).- MySQL editor diagnostics no longer flag DCL statements — the MySQL
driver was using the generic
SqlLanguageService(tree-sitter-sequel / ANSI SQL), which chokes onCREATE USER 'u'@'h' IDENTIFIED BY '…',GRANT … TO 'u'@'h',FLUSH PRIVILEGES, etc., surfacing spurious "Unexpected …" errors. A newMySqlLanguageService(mirrors the MongoDB pattern) overridesConnection::language_service()to return empty editor diagnostics — the server stays the source of truth. MariaDB shares the impl and is covered automatically. Closes #126 (#128). TimeRangePanelwindow preserved against stale source-input clobber — The result-panel chart toolbar's panel emittedTimeRangeChangedon every preset click, butrun_query_textthen unconditionally rebuiltexec_ctx.sourcefrom the once-populatedsource_*_inputtext fields, silently overwriting the panel's selection. A newpending_window_overrideonCodeDocumentcarries the authoritative panel bounds through a pureresolve_source_contexthelper that gives the override precedence over the input-driven fallback (and suppresses input validation errors when an override is present).ChartDocumentwas unaffected (no dual source of truth) (#124).- X-axis edge labels no longer clipped on charts — the label paint
loop centered labels on tick screen-X with no right-bound clamping,
and the fixed
MARGIN_RIGHT = 16did not reserve space for label overhang. A pre-shape pass in the paint closure now measures label widths and derives effective horizontal padding asmax(MARGIN_*, max_label_w / 2.0)(base margins as a floor), with a symmetric left-edge guard. The Y-tick column tracks the effective left pad so it stays flush with the plot. Extracted aseffective_x_label_paddingwith 6 unit tests (#120). ChartDocumentcustom-range apply race —apply_custom_rangenow setspending_time_windowandpending_chart_reexecutesynchronously from the validated(start_ms, end_ms)returned by the panel, instead of waiting for the deferredTimeRangeChangedsubscription. The subscription still fires forselected_time_rangemirroring, but re-execution is no longer gated on its delivery timing (#121).- Connection + sidebar UX batch — cancelling a connect task now also clears the profile-level pending-operation entry so the sidebar exits the "(connecting...)" state immediately. Editing a currently-connected profile surfaces a "Reconnect now / Later" toast; the edit always persists and the live session refreshes only on opt-in. Reopening Settings after closing it no longer wastes the first click (stale window handle cleared on close and on focus failure). Ctrl+click in the sidebar now seeds the keyboard-focused item into the multi-selection before toggling, matching the visual cursor (#145).
- Row inspector follows the active tab and selection — the
workspace inspector rail used to be a singleton with no per-tab
state, so switching tabs left a previous table's inspector
rendered against the new tab's chrome.
DataGridPanelnow remembers(row, col)when the inspector opens and re-snapshots the row on tab activation, result refresh, and selection changes (click / arrow keys). Rows that fall out of bounds after a refresh close the rail cleanly. Explicit dismissal (× / ESC) drops the cached coords so the rail stays closed on return. Inspector column-name and value cells now share a flex layout (140px / 220px basis) with ellipsis truncation, so long names no longer wrap and resizing the rail redistributes width across both columns.Ctrl+A/Cmd+Ainside an inline cell editor now selects the input text instead of all table rows (#145).
- Audit event charts — the Audit document now has a Table/Chart view toggle that visualizes the currently filtered audit events as counts over time, with one series per group value (grouped by category, outcome, or level). The chart honors the document's active time range and auto-refresh. Charts are ephemeral (a view mode, not a saved artifact).
- Logarithmic Y axis for charts — charts can switch the Y axis between linear and logarithmic (log1p) scale, so large spikes no longer flatten the rest of the data. Exposed in the audit chart toolbar.
- CloudWatch metric charts — CloudWatch connections can graph real
metrics (via
GetMetricData) as a time-series chart. An "Open Metrics Chart" command is available whenever the active driver advertises the generic metric-series capability; the chart refreshes over the active time window. The metric is currently fixed (AWS/Lambda Invocations, average over 5-minute periods); an in-app metric picker is a follow-up. - Generic
ChartDataSourceseam (W0) — a driver-agnostic chart data trait that the audit and CloudWatch chart features both consume. The UI never branches on driver identity; charts are wired through metadata and capabilities.
- Charts respond to the active theme — chart canvas chrome (gridlines,
tick labels, crosshair, hover dot, readout overlays) and chart overlays
(legend, axis bar, point inspector, picker) now route through a new
semantic::ChartColorspalette resolved per active theme. The Light theme no longer renders the dark series palette over a light canvas; Mirage and Dark use theme-driven series colors via the engine'stheme.chart_1..chart_5. Dark series colors remain byte-identical to prior releases. Three deliberate Dark chrome divergences (gridlines viatheme.border, tick labels viatheme.muted_foreground, hover-dot background viatheme.background) carry through and were validated by visual QA. - Document toolbar styling unified — every document type's toolbar now uses the same shared primitives (icons, separators, spacing) so the look is consistent across SQL editors, chart documents, audit views, and the data grid.
- UI split into six layered crates — the monolithic
dbflux_uicrate was split intodbflux_components(domain-free leaf),dbflux_ui_base(events/keymap/AppState seam),dbflux_ui_document(tabs, panes, all document types),dbflux_ui_windows(settings + connection manager),dbflux_ui_sidebar, and a thindbflux_uiintegrator. Per-driver feature flags no longer live on UI crates (they belong todbflux_app, which registers drivers). Incremental rebuilds are noticeably faster. - Design tokens consolidated across every UI crate — every UI crate
now consumes the centralized
dbflux_components::tokensscale (Spacing,Borders,Widths,ChartGeometry) and routes banner colors through a singlesemantic::BannerColors. Each crate is locked by a source-scanning guardrail test that prevents regressions. Chart factory files (axis_bar,point_inspector,legend) sit under the guardrail; onlychart/engine.rsstays exempt for canvas geometry math. Behavior-preserving. dbfluxbinary dependency cleanup — the binary'sCargo.tomlno longer declares the driver/runtime crates as direct optional deps; they are activated throughdbflux_app/<feature>. Feature relays unchanged from a user perspective;--features sqlite,…,lua,aws,mcpcontinues to work identically.
- Audit row detail expanded full-width with custom range inputs visible — the Audit document's row detail panel now spans the full width of the document and the custom date-range inputs are no longer clipped behind toolbar chrome.
- Audit SQLite "database is locked" errors under contention — the
audit store now sets a 5s
busy_timeoutwhen opening its connection. Since the audit database shares a WAL file withStorageRuntime(and tests may race on a shared temp path), concurrent openers previously failed immediately withSQLITE_BUSYinstead of waiting; they now serialize. Fixes intermittent test failures in the MCP governance suite.
- Focus shortcuts on macOS/Windows —
Ctrl+Shift+1..4(Focus Sidebar / Editor / Results / Tasks) now fire on every platform. GPUI normalizesShift+digit chords at the platform layer (e.g. macOS deliversCtrl+Shift+2as@withshift=false), so the literalKeymapStackmatchers never matched the runtime keystroke. The four shortcuts are now registered as native GPUI key bindings, which GPUI normalizes per platform/layout at registration time. TheKeymapStackentries are retained solely as the command-palette shortcut-label source. - DriverCapabilities bit collision —
MULTI_STATEMENTandROUTINESwere both defined as1 << 47in the same bitflags, so a driver advertising one silently advertised the other.MULTI_STATEMENTnow occupies bit 48, with a regression test asserting the bits are distinct. - DynamoDB upsert capability —
MutationCapabilities.supports_upsertwasfalseeven though the driver implements single-item upsert (PutItem) and only rejectsmany + upsert. The flag is nowtrue, so the MCP write tool no longer rejects a supported operation.
- Multi-statement script execution — running a buffer with no active
selection now offers to execute the whole script (multiple
;-separated statements) behind a "Run entire script (N statements)?" confirmation, on drivers that advertise the newDriverCapabilities::MULTI_STATEMENTflag.QueryLanguagesplits SQL-family buffers while skipping separators inside strings, identifiers, line/block comments, and PostgreSQL dollar-quoted bodies; non-SQL languages stay single-statement. PostgreSQL routes batches through the simple query protocol (batched columns are untyped text); MySQL/MariaDB and SQLite split client-side and run each statement through the typed prepared path (also fixing SQLite silently executing only the first statement); MSSQL already executed batches natively. Each result set renders in its own result tab. The seam is driver-agnostic — the UI gates on the capability flag, never on driver identity. - Stored Procedures / Routines folder — a capability-gated Routines
folder now appears under schema nodes in the sidebar, gated on the new
DriverCapabilities::ROUTINESflag (never on driver id). Core exposesRoutineInfo/RoutineKindkeyed on the engine-providedspecific_namefor overload-safe node identity, plusConnection::schema_routines/routine_definitionwith default empty implementations so non-supporting drivers fall back gracefully. PostgreSQL (viapg_proc/pg_get_functiondefwith an aggregate/window fallback), MySQL/MariaDB (viainformation_schema.ROUTINES+SHOW CREATE), and SQL Server (viasys.objects+OBJECT_DEFINITION) implement listing. Clicking a routine opens a read-onlyCodeDocument(editor disabled, completion off, mutating and execution toolbar buttons hidden) that round-trips across session restore.
- Workspace document architecture refactor — the closed
DocumentHandleenum that previously gated every document type was replaced with aPaneHandleclosure-erasing shell. Adding a new document type now requires only a new<name>/pane.rsand oneopen_<name>function inworkspace/actions.rs; no changes toworkspace/mod.rs,tab_manager.rs,tab_bar.rs, orhandle.rs. IntroducesDocumentKeyfor tab deduplication (replaces the sixis_*methods), a unifiedDocumentEvent(replaces four per-document event enums), and a universalResultPanel+ViewHandlechrome host with aToolbarSegmentslot system (Left | Center | Right+index,flex_wraprow) for filter bars, axis bars, range chips, and similar view-provided controls.handle.rsreduced from 486 to 29 LOC;audit/mod.rsreduced from 3454 to 1628 LOC. No new dependencies, no functional regressions, 2169 tests pass. - Chart-specific icons across chart surfaces and the result mode bar
— added
ChartSpline/ChartArea/ChartColumnBig/ChartBar/ChartPie/ChartNetworkicons (with afor_chart_kindhelper) and replaced generic placeholders: the chart tab and the "Chart this query" menu/editor button now useChartSpline, the chart toolbar Stats button usesChartBar, and the Data | Chart | JSON result-view mode bar gains per-mode icons.
- Result mode bar appears in CodeDocument query results —
DataGridPanel::available_result_view_modesno longer gates on the currently active mode, so the Data | Chart | JSON bar now renders the moment aQueryResultarrives (instead of only after the user manually switched away from Table). Regression introduced earlier in the workspace-view refactor.
- Microsoft SQL Server driver — first-class SQL Server support
built on
tiberius, with TLS modes (off,on,required+trust_server_certificate), SSH tunnel and SQL Browser named- instance routing, full multi-schema introspection (hr,sales,dbo, …), CRUD viaOUTPUT INSERTED.*/OUTPUT DELETED.*,OFFSET ... FETCH NEXTpaging, and cooperative query cancellation via side-channelKILL <spid>with automatic session restore and active-database recovery.ColumnKindis wired across everytiberius::ColumnTypeso MSSQL results integrate with chart auto-detection.
- Long text wraps in toasts, banners, and the delete-confirmation
modal — long error strings and titles previously overflowed past
the card edge instead of wrapping. The flex chain inside the card
is now configured so titles and subtitles wrap within the
container's
max_w. - Delete-confirmation popup no longer duplicates the dedicated
delete modals — when
ModalDeleteConnectionorModalDropTableis open, the generic confirmation popup is now suppressed so users don't see two overlapping delete dialogs. - Connection profile add / remove / update now persist on disk —
removing a profile failed to delete its row because
save_profileswas upsert-only, and add / update relied on an MCP-side persist hook so changes were lost on builds without MCP.app_statenow calls the storage repository directly on every mutation.
- Data grid column header prioritizes the column name — the name,
PK/FK badges, and type chip were equal-weight siblings, so long type
labels (e.g. MySQL's raw
MYSQL_TYPE_VAR_STRING) pushed the column name out of view. The name is now the primary affordance rendered with the standard foreground and never ellipsized, while the type label and PK/FK badges share a single muted styling and shrink first. MySQL now maps protocol types to canonical SQL labels (VARCHAR,BIGINT UNSIGNED,DECIMAL(p,s), …) and DynamoDB infers a label from the first sampled item instead of showing the literal"DynamoDB". - Pending inserts are committed on save —
request_save_allemitted virtual row indices for pending inserts while the commit path looked them up by array index, so on any table with existing rows the save aborted silently with no error. Inserts now persist regardless of the base row count. - Chart engine plots Decimal and Bool columns —
extract_f64only handledValue::Int,Value::Float, and timestamp-typedValue::Text, silently droppingValue::DecimalandValue::Bool. Columns whoseColumnKindis numeric (e.g. PostgreSQLNUMERIC, MSSQLDECIMAL, MSSQLBIT) now render correctly instead of producing an empty series with no error. - PostgreSQL array columns accept inserts and updates — saving a row
into a
text[]/int4[]/ etc. column failed withexpression is of type jsonbbecause the dialect emitted'<json>'::jsonbregardless of the destination type. Per-column type metadata now flows from the UI data grid and MCP write tools throughRowInsert/RowPatch/SqlUpdateRequest/SqlUpsertRequestto the dialect, which emitsARRAY[...]::elem[]for array columns and keeps::jsonbfor JSON columns. The IPC wire format stays backward compatible via serde shims, so older driver peers keep working.
- Chart engine — first-class time-series charts across the workspace. Results in the data grid gain a Chart mode with an axis bindings bar (X / Y / Group By / Aggregate), a shared toolbar (range, refresh, window, points, stats, PNG, save), LTTB decimation, axis tick labels, a user-toggleable legend, and a crosshair readout with nearest-sample lookup. Charts can be saved and reopened from the command palette.
ChartDocument— standalone chart document opened via "Chart this query" from a data grid context menu. Owns its own time-range panel, refresh dropdown and execution loop; the query is fixed for the document's lifetime.ColumnKindmetadata — every driver now reports per-column semantic kind (Timestamp, Numeric, Tag, etc.) used by chart detection. Wired across Postgres, MySQL, SQLite, MongoDB, Redis, DynamoDB, CloudWatch, OpenSearch, Cypher, and InfluxDB.- InfluxDB driver — InfluxDB v1 (InfluxQL) and v2 (Flux) support with full query, chart, and metadata integration.
- Branding — adopted the new DBFlux mark from the design system across the application chrome.
- SQL editor diagnostics no longer flag PostgreSQL dollar-quoted
blocks — valid
DO $$ ... $$;anonymous code blocks and other$tag$-quoted bodies were marked with spurious syntax errors because the bundled tree-sitter SQL grammar does not understand dollar quoting or PL/pgSQL. Parse diagnostics are now skipped when the query contains a closed dollar-quoted block.
- Platform-aware keybindings — application-level shortcuts now use
Cmd on macOS and Ctrl on Linux/Windows: command palette
(
Cmd/Ctrl+Shift+P), new/close/switch tab, run query, save, open script/history, export results, toggle sidebar, audit viewer, and Results cell copy. vim-style navigation (Ctrl+h/j/k/l,Ctrl+u/d) andCtrl+Tab/Ctrl+Shift+Tabstay literal Ctrl on every platform, along with focus shortcuts (Ctrl+Shift+1..4) that would clash with macOS screenshot bindings andCtrl+Mwhich would clash with window-minimize on macOS. Inline data-table commands (Copy, Save row, Select all, Undo/Redo) use GPUI'ssecondary-modifier so they pick the right key per platform. Command-palette shortcut labels and the SQL editor / save-row hints now reflect the platform modifier. Closes #63.
- Workspace-level inspector rail — row inspector promoted to a workspace-wide rail and migrated off the per-document overlay (#52).
- Nix prebuilt-binary package —
pkgs.dbfluxis now a prebuilt binary fetched from the matching GitHub Release (pinned bynix/release-info.nixand built vianix/binary.nix), with a fallbackpkgs.dbflux-sourcefor compiling locally. The flake also exposesoverlays.defaultso downstream flakes can consume the package directly.
- Adopt trunk + short-lived release-branch model: add
CONTRIBUTING.md, label-aware PR/issue templates, anddocs/RELEASE.mddocumenting the cut and tag procedures. - Release workflow publishes stable tags (
vX.Y.Z) directly and marks-dev.N/-rc.Ntags as prereleases. - Cherry-pick discipline now requires removing the corresponding entry
from main's
[Unreleased]block after the picked commit lands on the release branch, and the cut procedure verifies the release workflow has theClassify releasestep before tagging.
- Toast bubble no longer overflows the screen when the subtitle is long.
The title and subtitle now stack vertically inside a
flex_1 min_w_0column so the subtitle wraps within the card'smax_w(raised from 26rem to 28rem) instead of pushing the whole toast past the workspace edge. The card also calls.occlude()so clicks on its empty area no longer fall through to the sidebar or document underneath.
- Schema-drift preflight no longer reports phantom "all columns removed"
for queries whose table lives outside
public. The fresh fetch is now steered to the right schema via a layered precedence (query qualifier → cachedTableInfo.schema→ editor toolbar's schema →publicfallback), and the checker defensively skips any entry whose driver lookup returns zero columns — preventing the emptyTableInfofrom poisoning the autocomplete and table-detail caches via the "Refresh & re-run" path.
- Pin EOL to LF via
.gitattributes(* text=auto eol=lf) socargo fmtno longer desyncs Windows working trees that default tocore.autocrlf=true.
- Results table horizontal trackpad / wheel scroll now respects the platform sign convention (macOS "natural scrolling" preference, Linux / Windows scroll direction) and the body shifts on the same frame as the scrollbar, removing the one-frame lag that read as jitter during trackpad momentum. Follow-up to #60.
- Ctrl+C / Cmd+C now copies the selected cell (or range) from the Results grid to the clipboard, matching the right-click → Copy behavior.
- Results table now scrolls horizontally with trackpad / Magic Mouse
gestures and
Shift+Wheel. The horizontal scroll handle is owned by a 1px phantom scroller so the scrollbar widget can drive it, which meant horizontal wheel deltas landing on the header or body were dropped; the table now forwards those deltas to the handle, and the vertical-only uniform list is restricted to its axis so GPUI's built-in delta.x → delta.y fallback no longer double-scrolls on shift+wheel (#58).
- Results data grid shows the horizontal scrollbar immediately when
the columns are wider than the viewport. gpui-component scrollbars
render fully transparent at idle and only fade in after a scroll
event; the horizontal axis is driven by a 1px phantom scroller that
never receives the wheel, so previously the bar stayed invisible
until the user arrowed past the right edge. The horizontal scrollbar
is now configured with
ScrollbarShow::Always.
- Logger now initialises at the very start of
run_gui()so startup diagnostics (IPC socket binding, auth token init) reach the log sink. SettingDBFLUX_LOG_FILEredirects alllog::*!output to the given file in append mode — useful on Windows where the GUI subsystem hides stderr.
- SQL editor keeps focus after dismissing the completion popup with Esc.
gpui-component's
CompletionMenu::hideclears the menu but the follow-up re-render dropswindow.focuseven though the input still owned it synchronously; the editor pane now re-focuses its input on the next tick so typing keeps working.
- Design system foundation — new
dbflux_componentscrate with a complete design-system token scale (AppStyleCompact / Default density tiers, semantic color tokens, density accessors threaded throughButton,Dropdown,PanelHeader,Surface,Badge,FocusFrame,Textand the whole typography stack). The Style is persisted ingeneral_settingsand selectable from a new Style dropdown in General settings. Ayu Mirage joined Ayu Dark as a first-class theme. - Hi-Fi design bundle applied across the app — workspace chrome refresh
(Linux CSD titlebar with breadcrumb, doc-tab dirty dot, pulsing status bar),
sidebar (compact tab strip, magnifier-prefix search, no double border,
StatusDotper row, single compact footer with connected/idle count), data grid with column PK/FK badges and row-state colors, paginator‹ N / Total ›, schema-drift detection with modal, command palette redesign (grouped sections,Chordshortcuts, deep-Ayu-Dark background), settings navigation (uppercase XS group headers,warning_bg-tinted active item, keybinding rows withChord+ conflict banner), audit document 6-column grid withBannerColorsLVL chips, empty workspace state with shortcut chords. - New shared primitives —
StatusDot,BannerBlock,TypeToConfirm,Chord,KbdBadge,SegmentedControl,FilePicker,Logsicon,RowColors/BannerColors/StatusDotPalettetoken families,AnimandWidths/Shadowsconstants. - Rich Toast system — explicit
Toast::xxx(title).subtitle(...).body(...).details(...).code_block(...).progress(...).action(...).collapsible().push(cx)builder with auto-dismiss policy per variant, action buttons, collapsible details, and a 4 px left accent stripe. All ~100 call sites migrated to the explicit builder; the oldcx.toast_xxx(msg, window)trait removed. SQL execution errors render rich withFormattedError(subtitle = SQLSTATE, body = message, code_block = HINT, "Copy" action). - Row Inspector overlay — 320 px floating panel with PK/FK indicators,
FK forward-resolution (issued against the per-database connection so it
works on Postgres' connection-per-database model), inline wrapping for
long FK headers and resolution errors, drag-mask resize (240 – 1280 px),
scroll containment, and a working
×close button. - Connection manager rebuild — driver picker as a grouped, alphabetical
4-col card grid with
/-focusable filter input and 2D keyboard navigation; per-driver SSL modes viaSegmentedControldeclared by each driver's metadata; cert paths chosen viaFilePicker; SSH passphrase prompt with 60 min in-memory remember; enriched test-connectionBannerBlock(engine version, RTT, server time, SSL ciphersuite). - Driver metadata expansion — new
DatabaseCategory::LogStream(with CloudWatch reclassified to it and using the newLogsicon),DeploymentClassenum (Self-hosted / Embedded / Cloud-managed) surfaced in Settings → Drivers, per-driverSslModeOptionlists andSslCertFieldscapability. MongoDB and Redis gained TLS support (CombinedPemFilehelper concatenates cert+key for MongoDB). - Schema-aware features —
SchemaCache::dependentscache, per-driverfetch_dependents,referenced_tables,fetch_row_by_pk,test_connection_richonConnection;SchemaFingerprintfor drift detection. - Built-in CloudWatch Logs integration (#43).
- External RPC auth providers reach AWS parity — runtime registration
over RPC, login-capable providers with device-URL flow surfaced in the
shared login modal, opaque
AuthSessionDto.session_dataround-trip, and genericDynamicSelectform fields whose options are fetched through the newFetchFieldOptionsIPC method. Auth-provider IPC reaches v1.2 with asecret_dependency_opt_inmanifest flag;Password-typed values are stripped from option requests by default. AWS SSO Account ID / Role Name dropdowns now travel through the generic path — no provider id is hard-coded in the Settings panel anymore. The Provider selector is a single dropdown over the full registry (built-in + RPC-discovered). - Sidebar batch delete — multi-select rows and delete them in one action.
- RPC services foundation — formalised driver and auth-provider service kinds, shared bootstrap, and negotiated API-version contracts at startup.
FetchOptionsError::SessionExpiredandNeedsLoginnow surface a visible per-field re-login hint and provider-level banner instead of being silently logged.RefreshTrigger::Manualonly fetches on cache miss — no more refetch on every render.- MySQL connection configs are preserved across reloads.
- The data grid keeps CRUD actions available on empty tables.
nix developis back to a working state.- Sidebar tree survives degraded storage loads and no longer overwrites a broken connection tree.
- PostgreSQL
GRANTstatements no longer surface false-positive diagnostics in the editor. - Editor focus is preserved after running a query.
- CI now runs DynamoDB live integration tests.
- Workspace-wide rustc/clippy lints (warn level) opted into by all driver
crates;
rustfmt.tomlbaseline added. - Repo-specific workflow skills added for contributor automation.
- Add sidebar refresh and drop actions for schema nodes (#29)
- Add a new app icon and fix the About section display
- Improve small app icon rendering in packaging assets
- Persist all pending row changes on save, not just the first (#28)
- Keep column resize drag active until mouse release
- Restore plural-aware delete confirmation copy for multi-row deletes after the main/dev merge
- Register value providers for AWS static credentials auth (#22)
- Sign .deb/.rpm packages natively and make GPG signing always-on (#6, #23)
- Use UUID for temp SQLite path to avoid parallel test lock contention
- Align audit filter controls and multi-select behavior (#21)
- Unify MCP audit with app-wide audit system (#20)
- Add MCP
create_typesupport (#15)
- Add Linux client-side window decorations in the UI (#14)
- Expand command palette global search behavior (#17)
- Preserve MongoDB SRV URIs in URI mode (#19)
- Add a pull request template to standardize change summaries and validation details
- Implement cooperative query cancellation for MongoDB driver (#11)
- Wire proxy tunnels into the connect pipeline (#12)
- Update README with screenshot and installation options
- Add deb and rpm package generation to Linux release workflow
- PKGBUILD now downloads pre-built Linux binaries from GitHub Releases instead of compiling from source
- Release artifacts (tar.gz, AppImage) now include LICENSE files
- Codebase split into
dbflux_app(pure domain, no GPUI) anddbflux_ui(all GPUI/UI code);dbfluxbinary is now a thin shell AppStateextracted as a plain struct indbflux_app;AppStateEntitywrapper with GPUI event emission lives indbflux_uidbflux_corereorganized from 50 flat files into 10 thematic subdirectories (core/,driver/,schema/,sql/,query/,connection/,storage/,data/,config/,facade/)
- DynamoDB: built-in driver with full CRUD, SSM tunnel integration, and AWS SSO auth
- PostgreSQL, MySQL, SQLite, MongoDB, Redis: driver stability fixes, schema introspection, filter translation, pagination, and aggregate handling
- Driver crates now include README files documenting features and limitations
- Policy engine with roles, trusted clients, and tool policies
- Approval service for deferred destructive/write operations
- SQLite-backed audit logging with CloudWatch-like viewer
- Standalone MCP server (
dbflux mcp) integrated as optional CLI subcommand - Granular MCP tools for query, schema, DDL preview, and more
- Proxy tunnel support: SOCKS5 and HTTP CONNECT with per-connection selection
- SSH tunnel with adaptive sleep and host key verification
- Connection hooks: reusable Bash/Python/Lua scripts bound to PreConnect, PostConnect, PreDisconnect, PostDisconnect phases
- Unified SQLite storage in
~/.local/share/dbflux/dbflux.db
- Tab context menu (Close, Close Others, Close All, Duplicate)
- Settings sidebar with collapsible categories (TreeNav component)
- Audit viewer with full keyboard navigation (
j/k,g/G,]/[,mfor context menu) - Language-specific script icons in sidebar
- X11 window rendering fixes and platform-aware floating windows
- Live output streaming for script execution
SecretStringend-to-end across core, drivers, and IPC handoff- Per-process authentication tokens for local IPC and driver RPC
- URI passwords sanitized before persistence
- Lua VM memory capped at 16 MiB
- In-app AWS SSO login flow with account/role discovery wizard
- Provider-agnostic auth with runtime-registered
AuthProviderRegistry(AWS SSO, Static, Shared credentials) - Managed access via AWS SSM port-forward tunnels (no SSH key needed for RDS/EC2)
- Value sources for managed access fields: SSM Parameter Store, Secrets Manager, environment variables
- SSO auth profiles write back to
~/.aws/configfor compatibility with other AWS tools - DynamoDB driver uses same managed access pipeline for seamless AWS integration
- Dedicated style CI workflow that runs
cargo fmt --checkandcargo clippy --workspace -- -D warnings
- New connections and SSH tunnels now save credentials to the system keyring by default unless the checkbox is explicitly disabled
- Release workflow now blocks artifact builds until both tests and style checks pass
- SQL query context selectors now refresh when connections and databases change, so tabs opened before connecting can pick their execution target correctly
- Per-database query task cancellation now cleans up the exact connection target, allowing the sidebar to reopen those databases after cancellation
- PostgreSQL connection retry setup and live integration tests now compile cleanly under current type inference requirements
- Restored the full
LICENSE-MITtext in release artifacts
- Comprehensive live integration tests for all five database drivers (43 tests covering schema introspection, CRUD, browse/count, explain, describe, cancellation, code generators, document CRUD, and KeyValueApi)
- Docker-based test infrastructure for PostgreSQL, MySQL, MongoDB, and Redis with automatic container lifecycle management
- Driver contract validation tests for metadata, form definitions, and capability declarations
- AppState now accepts an external driver registry, making driver wiring controllable across different runtime contexts
- Document open and query connection selection extracted into explicit decision paths for consistent handling of missing connections and per-database routing
- MySQL
information_schemaqueries migrated fromformat!()string interpolation to parameterized queries (conn.execwith?placeholders) - MySQL nullable column reads (
Option<String>) now userow.get_opt()to correctly distinguish SQL NULL from missing columns
- MySQL schema introspection panic on MySQL 8.4 where
column_keyininformation_schema.columnscan be NULL - MySQL constraint introspection panic where
GROUP_CONCATover aLEFT JOINreturns NULL for CHECK constraints without key columns - Windows portable builds no longer open a CMD console window when launched outside a terminal
- CI integration test job now installs required system dependencies (
libdbus-1-dev,libxkbcommon-dev)
- Explicit unsupported-value representation in query results (
UNSUPPORTED<type>) to distinguish decode gaps from realNULLvalues
- Unsupported values are now treated as read-only in the data grid and are excluded from save/copy mutation flows
- Added complete PostgreSQL
tsvector/tsqueryhandling across table browse, query results, and grid filtering - PostgreSQL fallback decode paths no longer misrepresent unknown types as
NULL, reducing confusion and avoiding incorrect edits
- Inline enum/set dropdown editing in the data grid with keyboard navigation (
j/k, arrows,Enter,Esc) - Nullable enum editing support with explicit
NULLoption in dropdowns - Driver-level enum value metadata (
enum_values) inColumnInfofor PostgreSQL and MySQL - Info-level logging for unsupported value decoding paths in PostgreSQL, MySQL, and SQLite drivers
- PostgreSQL column introspection now uses
pg_catalog+format_type(...)to preserve real type names (including user-defined types) - PostgreSQL generated SQL literals now use escaped single-quoted string literals for readability
- MySQL
ENUM(...)andSET(...)column definitions are parsed and exposed as selectable values in the UI
- PostgreSQL custom types (enum/domain/composite/range) no longer appear as
NULLdue to restrictive string decoding - Table mode command routing now handles
Execute/Cancelcorrectly, restoring keyboard-driven inline editing flow LIKEfilter generation now only addsESCAPE '\\'when required by the search value- PostgreSQL
uuidcolumns now cast to::textforLIKEfilters
- File-backed "New Tab" flow and keyboard navigation in the context bar
- Settings toggle to mask and reveal SSH password fields
- MongoDB sidebar metadata with collection-level indexes and a database-level indexes folder
- MongoDB field schema sampling in the sidebar (field type, optionality, nested fields)
- Sidebar schema folders now stay visible with zero counts while lazy details load
- SQL and MongoDB schema folders are collapsed by default to avoid layout jumps during refresh
- Sidebar expansion no longer gets stuck in a loading state when opening schema nodes
- Closing a database connection no longer blocks the UI thread and freezes the app
- Filter submenu in data grid context menu for SQL databases (=, <>, >, <, IS NULL, IS NOT NULL, Remove filter)
- Order submenu in data grid context menu for SQL databases (ASC, DESC, Remove order)
- MongoDB filter submenu in document tree context menu with Extended JSON values,
$andcomposition, and NULL semantics ($existsguard) - ListFilter and ArrowUpDown icons
- Empty state for the sidebar connections tab ("No connections yet" hint)
- CI release workflow extracts changelog section from CHANGELOG.md instead of using hardcoded text
- GPUI newline panic: escape control characters in
Value::Jsonpreview in document tree - GPUI newline panic: escape control characters in
Value::Textand catch-all rendering in document card view - GPUI newline panic: use compact JSON (no newlines) when composing MongoDB filters for the single-line filter input
- Toolbar clear-filter button now re-runs the query after clearing (was only calling
cx.notify()withoutrefresh()) - Refactored icon asset loading to use
ALL_ICONSlookup table instead of match arms
- Table expansion in sidebar now loads and displays columns, indexes, and foreign keys instead of showing a stuck "Loading..." placeholder
- Concurrent table expansions no longer overwrite each other (replaced single pending action slot with per-item map)
- Failed schema fetches now collapse the table node instead of leaving it stuck in loading state
- Cache key mismatch between tree builder and fetch path that prevented details from ever appearing for per-database connections
- Collapsed sidebar now shows separate buttons for Connections and Scripts tabs
- FileCode icon registered in asset source
- MongoDB driver with collection browsing, CRUD operations, and schema introspection
- Document tree view with keyboard navigation, search, and value expansion
- MongoDB query parsing and validation with positional diagnostics
- MongoDB shell query generator for "Copy as Query" support
- Document view context menu with language-aware editor
- Redis driver with key-value API integration
- Key-value document browser with keyboard-navigable new-key modal
- Support for all Redis data types: String, Hash, Set, Sorted Set, List, Stream
- Context menu and real pagination for the key browser
- Live TTL countdown display
- Add Member modal for collection types
- Redis key completions and command arity validation in the editor
- File-backed query documents with Open (
Ctrl+O), Save (Ctrl+S), and Save As (Ctrl+Shift+S) - Execution context bar with connection, database, and schema dropdowns per tab
- Scripts folder in the sidebar with file and folder management
- Auto-save on a 2-second debounce after each keystroke
- Scratch files for untitled tabs, shadow files for file-backed tabs (explicit
Ctrl+Sstill writes the original) - Full session restore on startup from
~/.local/share/dbflux/sessions/ - Conflict detection: warns when original file was modified externally while a shadow existed
- Tabs close without unsaved-changes warnings
- PostgreSQL supports multiple databases open simultaneously in the sidebar
- Query tabs target a specific database connection instead of sharing a single switchable one
- Tab-based document architecture with
DocumentHandleandTabManager - SQL query documents with multiple result tabs (MRU ordering)
- Collapsible, resizable sidebar dock and bottom dock panels
- History modal integrated with document-based focus system
- Language-aware autocompletion (SQL tables/columns, MongoDB collections, Redis keys)
- Live query diagnostics with positional error markers
- Redis command arity validation in the editor
- Inline cell editing with focus handling
- Modal editor for JSON and long text values (
CellEditorModal) - Context menu with CRUD operations and SQL generation
- Keyboard navigation in context menus
- Column resizing via drag
- Support for empty tables in the data grid
- Row insert and duplicate without requiring a primary key
- Unified query generation with "Copy as Query" and preview modal
QueryGeneratortrait implemented by PostgreSQL, MySQL, SQLite, MongoDB, and Redis driversSqlDialecttrait for SQL flavor differences across drivers
- Multi-format export: CSV, JSON, Text, and Binary
- Export generalized by result shape instead of hardcoded CSV
- Interval-based auto-refresh with unified refresh split button
DocumentTaskRunnerfor unified async task tracking
- URI connection mode for PostgreSQL and MySQL
- Bidirectional sync between connection URI and individual form fields
- Dangerous query detection for SQL, MongoDB, and Redis commands
- Confirmation dialog with query preview before destructive operations
- Schema-level indexes, foreign keys, and data types in the tree
- Schema-level metadata support for MySQL and SQLite
- Context menus for indexes, foreign keys, and custom types
q/ekeys to switch between Connections and Scripts tabs- Inline rename in the tree (both tabs)
- Default focus to sidebar on startup when no tabs are open
- macOS release builds with
.appbundle (Info.plist) - Windows release builds with Inno Setup installer
- MongoDB and Redis feature flags enabled in default builds
CellValuepre-computes display text at construction time (avoids allocation during render)- Lazy loading for PostgreSQL and SQLite drivers (shallow metadata first, details on demand)
- Sidebar uses
SchemaNodeIdparsing instead of stale underscore prefixes - Custom toast implementation replaces
gpui-componenttoast - AppState decomposed into focused sub-managers in
dbflux_core - Architecture decoupled: core traits, driver capabilities, and error formatting extracted
- Oversized UI modules split into focused submodules (sidebar, SQL query, modals, SSH form)
- Active context detection improved in data grids
- Document focus restored correctly across menus and modals
- Scripts tab styling matches connections tab (icon and label colors)
- Removed force-close flow (double
Ctrl+Wwarning, pending force close state)
- Fixed catastrophic 1 FPS rendering issue in the data table
- Row-level event handlers replace per-cell closures in tables
- Background executor used consistently for all database operations
- Document focus restored across menus and modals
- Redis database state handling and UI interaction bugs
- SSH tunnel form mouse focus syncs with keyboard state
- Settings sync between SSH form fields
- Panics and unwraps eliminated across UI and driver code
- Empty query results now return column metadata correctly
- DDL queries show preview modal and editor height is correct
- Sidebar "New File"/"New Folder" creates inside the selected folder instead of at root
- Reveal in File Manager works on macOS and Windows (not just Linux)
- Opening an already-open script activates its tab instead of closing it
- MySQL/MariaDB driver with full query execution and schema introspection
- Dual connection architecture (sync for schema, async for queries)
- Dynamic connection forms that adapt to driver-specific requirements
- Folder-based organization for connection profiles
- Drag and drop support for connections and folders
- Multi-selection (Shift+click, Ctrl+click)
- Keyboard shortcuts for rename, delete, and new folder actions
- Confirmation dialogs for dangerous SQL queries (DELETE, DROP, TRUNCATE without WHERE)
- Driver-delegated SQL generation from context menu (SELECT, INSERT, UPDATE, DELETE)
- Column sorting via header clicks (ASC/DESC)
- Custom DataTable component with virtualized rendering
- Centralized SVG icon system with
AppIconenum and compile-time embedding - Icons across the editor toolbar (History, Save), Run/Cancel buttons, and tabs
- Sidebar tree icons (database brands, folders, tables, views, columns, indexes)
- Icons in context menus, results footer, pagination, and export actions
- Icons in connection manager (tabs, form headers, buttons)
- Icons in settings sidebar and About section
- Icons in toast notifications (success, info, warning, error)
- Icons in confirmation dialogs (delete, dangerous query)
- Database brand icons for PostgreSQL, MySQL, MariaDB, and SQLite
- Third-party licenses listed in About (Lucide ISC, Simple Icons CC0)
- Nix flake with development shell
- Arch Linux PKGBUILD
- Linux installer script (
curl | bash) - GPG-signed release artifacts
- GitHub Actions–based release workflow
- Lazy loading of table details in the sidebar (improves performance on large schemas)
- Schema loading deferred until node expansion
- Active databases are now visually highlighted in the sidebar
- Eliminated hover-induced re-renders in the data table
- Fixed subscription leaks in the table component
- Horizontal auto-scroll when navigating the data table with the keyboard
- Connection Manager: SQLite form navigation now works correctly (
j/knavigates between Name, File Path, and action buttons instead of jumping to non-existent PostgreSQL fields) - Connection Manager: Pressing Enter while editing an input now exits edit mode and moves to the next field
- Connection Manager: Input blur events now properly restore keyboard navigation focus
- About section in Settings with version info, GitHub links, and license (Apache 2.0 / MIT)
- SSH tunnel form keyboard navigation (row-based:
j/kbetween rows,h/lwithin fields,Tabsequential,g/Gfirst/last) - Database switch now appears as cancellable background task
- Settings window now opens as singleton (reuses existing window instead of opening duplicates)
- Stale settings window handle is now cleared when the window is closed
- SSH form field selection resets to valid field when switching auth method (PrivateKey ↔ Password)
- SSH selected index adjusts correctly when tunnels are deleted
zkeybinding for panel collapse now works in Editor and Background Tasks (previously only Results)
Initial release of DBFlux.
- PostgreSQL driver with full query execution and schema introspection
- SQLite driver for local database files
- SSL/TLS support for PostgreSQL (Disable, Prefer, Require modes)
- SSH tunnel support with multiple authentication methods (key, password, agent)
- Reusable SSH tunnel profiles
- Three-panel workspace layout (Sidebar, Editor, Results)
- Resizable and collapsible panels
- Schema tree browser with hierarchical navigation (databases, schemas, tables, views, columns, indexes)
- Visual indicators for column properties (primary key, nullable, type)
- Multi-tab SQL editor with syntax highlighting
- Virtualized results table with column resizing
- Table browser mode with WHERE filters, custom LIMIT, and pagination
- Command palette with fuzzy search and scroll support
- Toast notifications for user feedback
- Background tasks panel with progress and cancellation
- Status bar showing connection and task status
- Keyboard-navigable context menus with nested submenu support
- Query execution with result display
- Query cancellation support (PostgreSQL uses
pg_cancel_backend, SQLite usessqlite3_interrupt) - Execution time and row count display
- Multiple result tabs
- Query history with timestamps and execution metadata
- Saved queries with favorites support
- Search and filter across history and saved queries
- Unified history/saved queries modal with keyboard navigation
- Persistent storage in
~/.config/dbflux/
- Connection profiles with secure password storage (system keyring)
- Connection manager with full form validation
- Test connection before saving
- Quick connect/disconnect from sidebar
- Vim-style navigation (j/k/h/l) throughout the application
- Context-aware keybindings (Sidebar, Editor, Results, History, Settings)
- Global shortcuts for common actions
- Tab cycling between panels
- Full keyboard support in connection manager form
- Results toolbar navigation:
fto focus toolbar,h/lto navigate elements,Enterto edit/execute,Escto exit - Panel collapse toggle with
zkey - Context menu navigation:
j/kto move,Enterto select,lto open submenu,h/Escto close
- CSV export for query results
- SSH tunnel profile management
- Keybindings reference section with collapsible context groups and search filter
- No dark/light theme toggle (uses system default)