From 0c74d77e75fac83e4ef50f25e2d1c914d6b0152a Mon Sep 17 00:00:00 2001 From: "Adrian Alfred C. Bonpin" Date: Thu, 6 Aug 2026 22:56:49 +0800 Subject: [PATCH] v0.7.6: PostgreSQL object management, keychain toggle, tabbed Objects workspace (#12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [P1-T1] Change::Ddl Rust variant + execute_change arm * [P1-T2] Frontend ddl change type + objectCrud capability * [P1-T3] use_keychain data model + migration v8 * [P2-T1] object_crud skeleton + validators + build_ddl dispatch * [P2-T2] Sequence builders * [P2-T3] Enum builders (no value removal) * [P2-T4] View / matview / extension builders * [P2-T5] Index + constraint builders * [P2-T6] Function / procedure + trigger builders * [P2-T7] build_object_ddl + get_available_extensions commands + wrappers * [P3-T1] conditional keychain + session passwords * [P3-T2] keychain-off password prompt on connect * [P3-T3] default-ON keychain opt-out + tooltip + modal conditional * [P3-T4] ddl queue card + after-commit refetch * [P4-T1] ObjectCrudDialog shell * [P4-T2] SequenceForm * [P4-T3] EnumForm with no-removal note * [P4-T4] ExtensionForm with available-extensions picker * [P4-T5] ViewForm (view + materialized view) * [P5-T1] IndexForm with column picker * [P5-T2] ConstraintForm (check/unique/pk/fk) + ColumnPicker * [P5-T3] FunctionForm (function + procedure) * [P5-T4] TriggerForm with trigger-function picker * [P5-T5] ObjectContextMenu + Explorer/TableOverflowMenu CRUD wiring * [P6-T1] object tab type + openObjectTab dedup * [P6-T2] extract ObjectDetail for object tabs * [P6-T3] Objects view two-pane sidebar + workspace * [P6-T4] object-tab content + per-type tab icons * [P7-T1] Version bump 0.7.5 -> 0.7.6 * [P7-T2] docs sync README/ROADMAP/AGENTS for v0.7.6 * [P7-T3] chore: Cargo.lock version sync 0.7.5 -> 0.7.6 * fix(ui): object tab icon stacks above name (preflight svg block) * fix(ui): optically center object tab icon with name * fix(ui): object tab icon matches query/table icon handling * [UI-POLISH-1] objectForm tab type + openFormTab store action * [UI-POLISH-2] ObjectFormTab + KindForm with Visual/SQL toggle * [UI-POLISH-3] route create/edit through form tabs; remove modal * docs: create/edit now open as form tabs (AGENTS sync) * [FB-1] follow app styling patterns + schema dropdown in forms * [FB-2] Monaco editor for function body + view definition * [FB-3] form tabs styled like viewers + in-cell editing * [FB-5] focus outline scoped to input area (label excluded) * [FB-6] no amber focus outline on Monaco body/definition rows * [FB-7] header dedupe + schema default + full edit prefill * [FB-8] SQL view in read-only Monaco editor * docs: roadmap — table create/edit + relationships (next) * docs: roadmap — Admin follow-up is 0.7.7 (next after 0.7.6) --- AGENTS.md | 5 +- README.md | 42 +- ROADMAP.md | 43 +- package.json | 2 +- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/src/commands/connections.rs | 5 + src-tauri/src/commands/db_viewer.rs | 37 + src-tauri/src/commands/demo.rs | 1 + src-tauri/src/commands/import_export.rs | 2 + src-tauri/src/commands/objects.rs | 44 +- src-tauri/src/commands/objects.test.rs | 47 + src-tauri/src/commands/query.rs | 1 + src-tauri/src/db/introspection.rs | 17 + src-tauri/src/db/mod.rs | 1 + src-tauri/src/db/object_crud.rs | 727 ++++++++++ src-tauri/src/lib.rs | 2 + src-tauri/src/models/connection.rs | 24 + src-tauri/src/models/db_viewer.rs | 7 +- src-tauri/src/store/migrations.rs | 72 +- src-tauri/src/store/mod.rs | 23 +- src-tauri/tauri.conf.json | 2 +- .../ConnectionMetadataRow.test.tsx | 2 +- .../DetailedConnectionForm.test.tsx | 2 +- .../connections/GeneralTab.test.tsx | 13 +- src/components/connections/GeneralTab.tsx | 3 + .../connections/NewConnectionScreen.tsx | 2 +- .../db-viewer/ChangesQueuePanel.test.tsx | 14 + .../db-viewer/ChangesQueuePanel.tsx | 9 +- .../db-viewer/DbViewerScreen.test.tsx | 64 +- src/components/db-viewer/DbViewerScreen.tsx | 44 +- .../db-viewer/EditConnectionModal.test.tsx | 69 +- .../db-viewer/EditConnectionModal.tsx | 9 +- .../db-viewer/ObjectExplorerPage.test.tsx | 118 +- .../db-viewer/ObjectExplorerPage.tsx | 1209 +++-------------- .../db-viewer/PasswordPromptDialog.test.tsx | 61 + .../db-viewer/PasswordPromptDialog.tsx | 58 + src/components/db-viewer/TabBar.test.tsx | 45 + src/components/db-viewer/TabBar.tsx | 38 +- .../db-viewer/TableOverflowMenu.test.tsx | 25 + .../db-viewer/TableOverflowMenu.tsx | 29 + .../db-viewer/objects/ColumnPicker.tsx | 26 + .../db-viewer/objects/ConstraintForm.test.tsx | 111 ++ .../db-viewer/objects/ConstraintForm.tsx | 178 +++ .../db-viewer/objects/EnumForm.test.tsx | 54 + src/components/db-viewer/objects/EnumForm.tsx | 226 +++ .../db-viewer/objects/ExtensionForm.test.tsx | 65 + .../db-viewer/objects/ExtensionForm.tsx | 146 ++ .../db-viewer/objects/FunctionForm.test.tsx | 143 ++ .../db-viewer/objects/FunctionForm.tsx | 275 ++++ .../db-viewer/objects/IndexForm.test.tsx | 89 ++ .../db-viewer/objects/IndexForm.tsx | 135 ++ src/components/db-viewer/objects/KindForm.tsx | 68 + .../objects/ObjectContextMenu.test.tsx | 90 ++ .../db-viewer/objects/ObjectContextMenu.tsx | 188 +++ .../db-viewer/objects/ObjectDetail.test.tsx | 39 + .../db-viewer/objects/ObjectDetail.tsx | 974 +++++++++++++ .../db-viewer/objects/ObjectFormTab.test.tsx | 159 +++ .../db-viewer/objects/ObjectFormTab.tsx | 155 +++ .../db-viewer/objects/SequenceForm.test.tsx | 113 ++ .../db-viewer/objects/SequenceForm.tsx | 166 +++ .../db-viewer/objects/TriggerForm.test.tsx | 93 ++ .../db-viewer/objects/TriggerForm.tsx | 234 ++++ .../db-viewer/objects/ViewForm.test.tsx | 35 + src/components/db-viewer/objects/ViewForm.tsx | 111 ++ src/components/db-viewer/objects/formRow.tsx | 62 + src/components/editor/SqlEditorField.tsx | 66 + src/components/grid/VirtualDataGrid.tsx | 4 +- src/components/grid/gridEditability.ts | 2 +- src/hooks/useDbConnection.test.tsx | 79 +- src/hooks/useDbConnection.ts | 20 +- src/lib/bundle-config.test.ts | 6 +- src/lib/changePayload.test.ts | 16 + src/lib/changePayload.ts | 4 + src/lib/dbCapabilities.test.ts | 16 +- src/lib/dbCapabilities.ts | 6 +- src/lib/docs-coverage.test.ts | 20 +- src/lib/keychain.ts | 17 + src/lib/objectCrud.test.ts | 463 +++++++ src/lib/objectCrud.ts | 261 ++++ src/lib/types.ts | 5 +- src/lib/version.test.ts | 4 +- src/stores/connectionStore.test.ts | 95 +- src/stores/connectionStore.ts | 34 +- src/stores/dbViewerStore.test.ts | 160 ++- src/stores/dbViewerStore.ts | 124 +- 86 files changed, 7094 insertions(+), 1165 deletions(-) create mode 100644 src-tauri/src/db/object_crud.rs create mode 100644 src/components/db-viewer/PasswordPromptDialog.test.tsx create mode 100644 src/components/db-viewer/PasswordPromptDialog.tsx create mode 100644 src/components/db-viewer/objects/ColumnPicker.tsx create mode 100644 src/components/db-viewer/objects/ConstraintForm.test.tsx create mode 100644 src/components/db-viewer/objects/ConstraintForm.tsx create mode 100644 src/components/db-viewer/objects/EnumForm.test.tsx create mode 100644 src/components/db-viewer/objects/EnumForm.tsx create mode 100644 src/components/db-viewer/objects/ExtensionForm.test.tsx create mode 100644 src/components/db-viewer/objects/ExtensionForm.tsx create mode 100644 src/components/db-viewer/objects/FunctionForm.test.tsx create mode 100644 src/components/db-viewer/objects/FunctionForm.tsx create mode 100644 src/components/db-viewer/objects/IndexForm.test.tsx create mode 100644 src/components/db-viewer/objects/IndexForm.tsx create mode 100644 src/components/db-viewer/objects/KindForm.tsx create mode 100644 src/components/db-viewer/objects/ObjectContextMenu.test.tsx create mode 100644 src/components/db-viewer/objects/ObjectContextMenu.tsx create mode 100644 src/components/db-viewer/objects/ObjectDetail.test.tsx create mode 100644 src/components/db-viewer/objects/ObjectDetail.tsx create mode 100644 src/components/db-viewer/objects/ObjectFormTab.test.tsx create mode 100644 src/components/db-viewer/objects/ObjectFormTab.tsx create mode 100644 src/components/db-viewer/objects/SequenceForm.test.tsx create mode 100644 src/components/db-viewer/objects/SequenceForm.tsx create mode 100644 src/components/db-viewer/objects/TriggerForm.test.tsx create mode 100644 src/components/db-viewer/objects/TriggerForm.tsx create mode 100644 src/components/db-viewer/objects/ViewForm.test.tsx create mode 100644 src/components/db-viewer/objects/ViewForm.tsx create mode 100644 src/components/db-viewer/objects/formRow.tsx create mode 100644 src/components/editor/SqlEditorField.tsx create mode 100644 src/lib/keychain.ts create mode 100644 src/lib/objectCrud.test.ts create mode 100644 src/lib/objectCrud.ts diff --git a/AGENTS.md b/AGENTS.md index 999e415..27315ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -156,7 +156,7 @@ Cut a release from the **`prod`** branch (never feature branches) by tagging it **Before tagging**, keep everything in sync: - Version number across `package.json`, `src-tauri/Cargo.toml`, and `src-tauri/tauri.conf.json` - `src/lib/version.test.ts` and `src/lib/docs-coverage.test.ts` if they assert the version -- **README download links are static (versioned)** — both download tables (top **Download** section + **Which file should I download?**) link directly to the release-tag assets (`releases/download/v0.7.5/`). tauri-action uses default versioned asset names (`Gridline__aarch64.dmg`, `Gridline--1.x86_64.rpm`, etc.) — update BOTH tables to the new names on every release (see the MAINTENANCE comment in README.md). +- **README download links are static (versioned)** — both download tables (top **Download** section + **Which file should I download?**) link directly to the release-tag assets (`releases/download/v0.7.6/`). tauri-action uses default versioned asset names (`Gridline__aarch64.dmg`, `Gridline--1.x86_64.rpm`, etc.) — update BOTH tables to the new names on every release (see the MAINTENANCE comment in README.md). - **Bundled pg tools:** `tauri.conf.json` `bundle.resources` lists `resources/pg_tools/*`; the `release.yml` matrix builds/downloads + checksum-verifies the static binaries before the Tauri build step. ### Adding a Tauri Command @@ -210,6 +210,7 @@ Planned work is prioritized in the [Project Roadmap](./ROADMAP.md) (source of tr | DB Viewer: MySQL browse + query + edit | ✅ | Full viewer: connect (SSL + SSH tunnel), databases/tables/columns/FKs, query + pagination, inline cell editing + changes queue, DDL copy (`SHOW CREATE TABLE`), CSV/JSON import — added in v0.7.0. PK-only editing (no ctid equivalent); VARBINARY `information_schema` columns decoded correctly | | DB Viewer: Redis browse | ❌ | Connection + test only; browsing gated off with a clean "not supported" state (v0.7.0) | | Password storage in OS keychain | ✅ | macOS Keychain, Linux Secret Service, Windows Credential Manager | +| Enable keychain toggle | ✅ | Default ON (opt-out); OFF = don't persist the DB password (session-only, re-prompt on connect) + purge existing keychain entry; SSH secrets stay keychain-only (v0.7.6) | | SSH tunnel config UI | ✅ | Host, port, user, auth method, key path, passphrase fields | | SSH tunnel runtime | ✅ | Real ssh2 tunnel (password + key auth), binds 127.0.0.1 only, secrets in OS keychain (`ssh_password:` / `ssh_passphrase:`), closed on pool eviction / app exit; TLS downgraded to `require` through the tunnel | | SSL/TLS config UI | ✅ | Mode (disable/require/verify-ca/verify-full), cert paths | @@ -290,6 +291,8 @@ Planned work is prioritized in the [Project Roadmap](./ROADMAP.md) (source of tr | Global object search | ✅ | Cmd+K palette in the DB viewer, current-schema scope, all object types; results open a table tab or jump to the Objects view (v0.7.5) | | Copy as DDL for any object | ✅ | `CREATE` DDL for every browsable type (tables via pg_dump; pg_get_*def passthrough; sequences/enums/extensions/views synthesized) (v0.7.5) | | Object dependencies | ✅ | `pg_depend` "what depends on this?" view, shown before destructive drops (table drop, schema drop) (v0.7.5) | +| Object management CRUD | ✅ | Right-click / ⋮ create/edit/drop for every PG object type; create/edit open as **workspace tabs** with a Visual ⇄ SQL toggle, staged through the changes queue with generated-SQL preview (v0.7.6). Enum value removal unsupported (PG has no DROP VALUE) | +| Objects view tabbed workspace | ✅ | Objects view uses the shared tabbed workspace: object details open as tabs (per-type icons), inline manual query tab, and the changes queue reachable from the tab bar (v0.7.6) | | Schema visualizer (ER diagram) | ✅ | Full React Flow ER diagram with dagre auto-layout, crow's foot notation, schema selector, legend with cardinality colors, collapsible columns (PK/FK/unique-only), cross-schema FK support. PostgreSQL (single round-trip LATERAL query) + SQLite (PRAGMA). Uses @xyflow/react + dagre. | ### Query Editor diff --git a/README.md b/README.md index b6e8664..77ef7bc 100644 --- a/README.md +++ b/README.md @@ -31,21 +31,21 @@ ## Download -Grab the installer for your OS from the [latest release](https://github.com/AdrianBonpin/gridline/releases/latest) — the links below point at the current release (**v0.7.5**): +Grab the installer for your OS from the [latest release](https://github.com/AdrianBonpin/gridline/releases/latest) — the links below point at the current release (**v0.7.6**): | OS | Architecture | Download | | :--- | :--- | :--- | -| **macOS** | Apple Silicon (M1/M2/M3/M4…) | [Gridline_0.7.5_aarch64.dmg](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.5/Gridline_0.7.5_aarch64.dmg) | -| **macOS** | Intel | [Gridline_0.7.5_x64.dmg](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.5/Gridline_0.7.5_x64.dmg) | -| **Windows** | x64 | [Gridline_0.7.5_x64-setup.exe](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.5/Gridline_0.7.5_x64-setup.exe) | -| **Debian / Ubuntu** | amd64 | [Gridline_0.7.5_amd64.deb](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.5/Gridline_0.7.5_amd64.deb) | -| **Fedora / RHEL / openSUSE** | x86_64 | [Gridline-0.7.5-1.x86_64.rpm](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.5/Gridline-0.7.5-1.x86_64.rpm) | -| **Other Linux** | amd64 | [Gridline_0.7.5_amd64.AppImage](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.5/Gridline_0.7.5_amd64.AppImage) | +| **macOS** | Apple Silicon (M1/M2/M3/M4…) | [Gridline_0.7.6_aarch64.dmg](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.6/Gridline_0.7.6_aarch64.dmg) | +| **macOS** | Intel | [Gridline_0.7.6_x64.dmg](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.6/Gridline_0.7.6_x64.dmg) | +| **Windows** | x64 | [Gridline_0.7.6_x64-setup.exe](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.6/Gridline_0.7.6_x64-setup.exe) | +| **Debian / Ubuntu** | amd64 | [Gridline_0.7.6_amd64.deb](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.6/Gridline_0.7.6_amd64.deb) | +| **Fedora / RHEL / openSUSE** | x86_64 | [Gridline-0.7.6-1.x86_64.rpm](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.6/Gridline-0.7.6-1.x86_64.rpm) | +| **Other Linux** | amd64 | [Gridline_0.7.6_amd64.AppImage](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.6/Gridline_0.7.6_amd64.AppImage) | > Not sure if your Mac is Intel or Apple Silicon? See [Which file should I download?](#which-file-should-i-download) below. All installers are **unsigned** — see the [notes](#which-file-should-i-download) on first-launch warnings.