From 7401e91a12f598d8dd8500ba3df08fca829ed73c Mon Sep 17 00:00:00 2001
From: "Adrian Alfred C. Bonpin"
Date: Fri, 7 Aug 2026 05:51:23 +0800
Subject: [PATCH] v0.7.7: PG roles/grants, table maintenance, Create/Edit Table
+ atomic column-reorder rebuild, FK management, table options (#13)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat(models): Change::RebuildTable + role/privilege/readiness/maintenance structs (Task 1.1)
* feat(introspection): role/privilege/tablespace/rebuild-readiness query builders (Task 1.2)
* feat(lib): rebuild_table payload, table/role object kinds, v0.7.7 capabilities + types (Task 1.3)
* feat(object_crud): table_ddl builder (create/edit-diff/options/drop) + build_ddl table arm (Task 2.1)
* feat(object_crud): role_ddl builder (create/edit/drop/grant/revoke) + build_ddl role arm (Task 2.2)
* feat(object_crud): rebuild_script assembler + fk/grant/sequence introspection queries (Task 2.3)
* feat(commands): transactional RebuildTable arm + build_rebuild_script + get_table_columns commands (Task 2.4)
* feat(commands): get_roles/privileges/readiness/tablespaces + run_maintenance (Task 2.5)
* feat(commands): role/privilege/rebuild/maintenance typed wrappers (Task 3.1)
* feat(store): roles slice + openFormTab table/role dedup (Task 3.2)
* feat(ui): TableForm (create/edit-diff/rebuild) + cross-schema FK with ON DELETE/UPDATE (Task 4.1)
* feat(ui): RoleForm + RoleDetail + RoleGrantsEditor (Task 4.2)
* feat(ui): wire roles into object registry + explorer (Task 4.3)
* feat(ui): Edit Table + maintenance menu + Create Table toolbar + rebuild badge (Task 4.4)
* chore: bump version to 0.7.7 (Task 5.1)
* docs: sync README/ROADMAP/AGENTS to v0.7.7 (Task 5.2)
* test: v0.7.7 manual smoke checklist (Task 5.3)
* chore: sync Cargo.lock to v0.7.7
* style(ui): match TableForm visual layout to shared object-form rows (remove stray padding)
* feat(ui): table creator grid redesign + per-column FK slide-in panel with relationship controls
* style(ui): table-creator columns grid — bordered cells like the data table view
* feat(ui): table creator — type dropdown, PK/Nullable rules, drag-to-reorder columns (vertical), tidy add-column row
* feat(ui): table creator — single-PK exclusivity, name on top, fixed column widths + contained h-scroll, no-wrap constraints
* style(ui): table creator — constraints column sized to content (no clip), overscroll containment
* style(ui): table creator — overscrollBehavior none on both scroll containers, add-column row py-2
* feat(ui): table creator — centered add-column button, schema dropdown auto-selected to current schema
* style(ui): table creator — columns grid fills container width, scrolls only when too narrow
* feat(ui): table creator — shorthand PG types in dropdown, Auto-Increment only for int-family
* feat(ui): FK panel — animate in/out from the right, flush create-table-style rows
* fix(ui): FK panel — smooth slide (willChange + eased), local column options from the form grid
* feat(ui): FK composer (multi-column, type preview, gated sections) + composite PK + constraints cog in actions col + auto-named FKs
* fix(ui): FK panel blocks unnamed table with hint; Foreign keys section lists staged + DB FKs
* style(ui): FK panel — transparent full-width selects, title↔select borders, 2-col column picker
* style(ui): FK panel — vertical divider between local/ref columns
* style(ui): FK panel — section title padding py-2
* style(ui): FK panel — remove row margins + select/text padding in column picker
* style(ui): FK panel — flush column picker (no section padding), border-r + py-1 cells
* style(ui): FK panel — cell padding + row borders on column picker (user polish)
* feat: FK inline into CREATE TABLE (single staged change in create mode); touch up class
* style(ui): hide FK icon on PK columns; fix grid header/row column alignment
* feat(ui): SQL preview in table creator uses read-only Monaco editor
* feat(ui): Foreign keys section — relation rows with icon + Edit/Remove actions
* style(ui): FK relation row — label, icon, table on one line
* style(ui): FormRow selects transparent like FK panel; test matches FK relation label
* style(ui): form-row focus outline amber-400/20 (subtle)
* style(ui): SQL view — remove px-4 py-3 wrapper padding
* feat(ui): Create Table button label; auto tree refresh after schema-modifying commits; table name on staged ddl card
* fix(roles): cast rolconnlimit::int8 to fix panic deserializing int4 into i64
* fix(privileges): cast privilege_type::text to avoid domain-array panic; aclexplode for sequences/schemas (role_sequence_grants removed in PG15, schema_privileges never existed)
* feat(ui): role privileges sections collapsible (collapsed by default) with 5-entry preview + fade + Show more
* feat(ui): role privileges — collapsed state shows first 5 with fade; expand reveals all
* chore(test): drop unused fireEvent import in RoleDetail test
* style(ui): hide chevron when section has 5 or fewer entries
* docs: README/ROADMAP/AGENTS — v0.7.7 shipped details (roles/grants, table editor, FK composer, privilege explorer); ROADMAP adds v0.7.8 Next up (quick wins)
* docs(readme): collapse Recent changes and Key features into details blocks
* docs(readme): move hero caption under image; align download + comparison table columns
* docs(readme): collapse only body content — keep Recent Changes / Key Features headings visible
* docs(readme): per-subsection collapsibles with meaningful summary labels
---
AGENTS.md | 19 +-
README.md | 142 +-
ROADMAP.md | 33 +-
.../2026-08-06-v0.7.7-smoke-checklist.md | 28 +
package.json | 2 +-
src-tauri/Cargo.lock | 2 +-
src-tauri/Cargo.toml | 2 +-
src-tauri/src/commands/db_viewer.rs | 99 +-
src-tauri/src/commands/maintenance.rs | 39 +
src-tauri/src/commands/maintenance.test.rs | 28 +
src-tauri/src/commands/mod.rs | 1 +
src-tauri/src/commands/objects.rs | 270 +++-
src-tauri/src/commands/objects.test.rs | 54 +-
src-tauri/src/db/introspection.rs | 245 +++
src-tauri/src/db/object_crud.rs | 726 ++++++++-
src-tauri/src/lib.rs | 6 +-
src-tauri/src/models/db_viewer.rs | 113 +-
src-tauri/src/models/mod.rs | 2 +-
src-tauri/tauri.conf.json | 2 +-
.../db-viewer/ChangesQueuePanel.test.tsx | 31 +
.../db-viewer/ChangesQueuePanel.tsx | 62 +-
src/components/db-viewer/DbViewerScreen.tsx | 3 +-
.../db-viewer/DbViewerToolbar.test.tsx | 13 +-
src/components/db-viewer/DbViewerToolbar.tsx | 38 +-
.../db-viewer/ObjectExplorerPage.test.tsx | 33 +
.../db-viewer/ObjectExplorerPage.tsx | 26 +-
.../db-viewer/TableOverflowMenu.test.tsx | 18 +
.../db-viewer/TableOverflowMenu.tsx | 170 +-
src/components/db-viewer/TableTree.tsx | 3 +-
.../db-viewer/objects/ConstraintForm.test.tsx | 79 +-
.../db-viewer/objects/ConstraintForm.tsx | 115 +-
.../db-viewer/objects/FkPanel.test.tsx | 223 +++
src/components/db-viewer/objects/FkPanel.tsx | 566 +++++++
src/components/db-viewer/objects/KindForm.tsx | 7 +
.../objects/ObjectContextMenu.test.tsx | 18 +-
.../db-viewer/objects/ObjectContextMenu.tsx | 4 +-
.../db-viewer/objects/ObjectDetail.test.tsx | 40 +-
.../db-viewer/objects/ObjectDetail.tsx | 17 +-
.../db-viewer/objects/ObjectFormTab.tsx | 5 +
.../db-viewer/objects/RoleDetail.test.tsx | 49 +
.../db-viewer/objects/RoleDetail.tsx | 75 +
.../db-viewer/objects/RoleForm.test.tsx | 98 ++
src/components/db-viewer/objects/RoleForm.tsx | 300 ++++
.../objects/RoleGrantsEditor.test.tsx | 62 +
.../db-viewer/objects/RoleGrantsEditor.tsx | 270 ++++
.../db-viewer/objects/SequenceForm.test.tsx | 2 +-
.../db-viewer/objects/TableForm.test.tsx | 516 ++++++
.../db-viewer/objects/TableForm.tsx | 1398 +++++++++++++++++
src/components/db-viewer/objects/formRow.tsx | 2 +-
src/lib/bundle-config.test.ts | 6 +-
src/lib/changePayload.test.ts | 17 +
src/lib/changePayload.ts | 4 +
src/lib/commands.test.ts | 91 ++
src/lib/commands.ts | 34 +-
src/lib/dbCapabilities.test.ts | 20 +
src/lib/dbCapabilities.ts | 9 +-
src/lib/docs-coverage.test.ts | 14 +-
src/lib/objectCrud.test.ts | 28 +
src/lib/objectCrud.ts | 53 +-
src/lib/types.test.ts | 32 +
src/lib/types.ts | 49 +-
src/lib/version.test.ts | 4 +-
src/stores/dbViewerStore.test.ts | 32 +-
src/stores/dbViewerStore.ts | 6 +-
64 files changed, 6255 insertions(+), 200 deletions(-)
create mode 100644 docs/superpowers/specs/2026-08-06-v0.7.7-smoke-checklist.md
create mode 100644 src-tauri/src/commands/maintenance.rs
create mode 100644 src-tauri/src/commands/maintenance.test.rs
create mode 100644 src/components/db-viewer/objects/FkPanel.test.tsx
create mode 100644 src/components/db-viewer/objects/FkPanel.tsx
create mode 100644 src/components/db-viewer/objects/RoleDetail.test.tsx
create mode 100644 src/components/db-viewer/objects/RoleDetail.tsx
create mode 100644 src/components/db-viewer/objects/RoleForm.test.tsx
create mode 100644 src/components/db-viewer/objects/RoleForm.tsx
create mode 100644 src/components/db-viewer/objects/RoleGrantsEditor.test.tsx
create mode 100644 src/components/db-viewer/objects/RoleGrantsEditor.tsx
create mode 100644 src/components/db-viewer/objects/TableForm.test.tsx
create mode 100644 src/components/db-viewer/objects/TableForm.tsx
diff --git a/AGENTS.md b/AGENTS.md
index 27315ca..873fd21 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.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).
+- **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.7/`). 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
@@ -215,6 +215,7 @@ Planned work is prioritized in the [Project Roadmap](./ROADMAP.md) (source of tr
| 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 |
| SSL/TLS runtime | ✅ | PostgreSQL all modes via rustls (disable/require/verify-ca/verify-full; **v1: `verify-ca` behaves as `verify-full`** — documented refinement), client certs PKCS#1/PKCS#8/EC, encrypted client keys rejected; MySQL test path maps modes (verify-full → VerifyIdentity) |
+| Roles & grants (PG) | ✅ | Create/edit/drop PostgreSQL roles and GRANT/REVOKE privileges per object class from a UI (v0.7.7) |
### Home Screen & Organization
| Feature | Status | Details |
@@ -262,7 +263,7 @@ Planned work is prioritized in the [Project Roadmap](./ROADMAP.md) (source of tr
| Export toolbar (JSON, CSV, SQL, Markdown) | ✅ | Client-side Blob download of visible rows |
| Auto-refresh timer | ✅ | Configurable interval in settings |
| Changes queue (INSERT, UPDATE, DELETE, bulk_insert, empty_table, drop_table) | ✅ | Stage → **Commit All**. Tab bar **Changes** button (amber border + count badge when pending) toggles a **popover** anchored to it: header with **Visual/SQL** toggle (cards showing op badge + table + description + per-change **Revert**, or a generated-SQL preview via `buildChangeSql`), footer **Clear All** + **Commit All (N)** with **⌘S/Ctrl+S** shortcut. Committed cards show a green ✓ (failed ✗); committing `drop_table` auto-closes open tabs of that table |
-| Auto schema-tree refresh | ✅ | Tree auto-refreshes after a successful schema-modifying query run (`CREATE`/`DROP`/`ALTER`/`TRUNCATE` via `isSchemaModifyingQuery`) and after committing `drop_table` via the queue — no manual refresh needed |
+| Auto schema-tree refresh | ✅ | Tree auto-refreshes after a successful schema-modifying query run (`CREATE`/`DROP`/`ALTER`/`TRUNCATE` via `isSchemaModifyingQuery`) and after committing schema-modifying queue changes — `drop_table`, schema-modifying `ddl` (e.g. `CREATE TABLE`), and `rebuild_table` — no manual refresh needed |
| Data import (CSV/JSON) | ✅ | Table overflow menu → ImportDialog: file pick, parse, preview (first 100 rows), header→column mapping, caps 100k rows / 100 MB; stages a bulk_insert change through the queue → Commit All |
| Table menu actions | ✅ | Copy table schema (DDL via pg_dump / sqlite_master), Empty Table (DELETE) / Delete Table (DROP) through the queue with confirm, export stubs wired (JSON/CSV/SQL/Markdown) |
| Edit connection modal (from DB viewer) | ✅ | AnimatedModal with keychain password fetch on test |
@@ -273,6 +274,18 @@ Planned work is prioritized in the [Project Roadmap](./ROADMAP.md) (source of tr
| Keyboard cell navigation (arrow keys, Tab) | ✅ | Arrow keys + Tab/Shift+Tab wrap (`keyboardNav`); Enter opens the editor; **Esc cancels editing even after the editor lost focus** (document-level listener) and closes the context menu |
| Cell-level copy (right-click or Ctrl+C) | ✅ | CellContextMenu: Copy / Copy JSON (jsonb) / Edit / Set NULL / Open FK reference + **View Row** and **Select Row** items; right-click or Ctrl/Cmd+C on the focused cell; menu closes on outside click/Esc |
| FK reference | ✅ | Small ↗ icon at the start of FK cells opens the FK preview popover (also via context menu Open FK reference); plain click on the cell selects/edits and does not open it |
+| Maintenance actions (VACUUM/ANALYZE/REINDEX) | ✅ | Right-click table → VACUUM / ANALYZE / REINDEX (v0.7.7) |
+
+### Table Editor & Roles (v0.7.7)
+| Feature | Status | Details |
+| :--- | :---: | :--- |
+| Create Table (visual editor) | ✅ | "Create Table…" workspace tab: columns grid (name / type dropdown / default / PK per row, drag-to-reorder, add/remove), single + composite PK (first column auto-PK), shorthand PG types (`int`/`int8`/`int2`/`float8`/`bool`), auto-increment gating, live Monaco SQL preview, transparent selects + form-row focus `amber-400/20` |
+| Edit Table (column diff) | ✅ | Same grid on existing tables; Stage diffs old vs new columns → one queue item per statement: `ADD COLUMN`, `DROP COLUMN`, `RENAME COLUMN`, `ALTER COLUMN … TYPE`, `SET|DROP DEFAULT`, `SET|DROP NOT NULL`; stale-write guard (re-fetches live columns, refuses if changed) |
+| Column reorder (atomic rebuild) | ✅ | Drag-to-reorder triggers a table rebuild: single transaction, preserves constraints/indexes/FKs/grants/sequences (copied DDL), fail-closed when triggers/RLS policies/inheritance/partitioning/generated columns are present (`get_table_rebuild_readiness`) |
+| FK management | ✅ | Multi-column FK composer (local col → ref col pairs, referenced PKs first, type-match preview `localType → refType`, auto-named constraints, ref-table picker with `name (type)` options); cross-schema references; ON DELETE / ON UPDATE actions; create mode inlines FKs into the single CREATE TABLE change, edit mode stages ALTERs; FK rows in the form with Edit/Remove (queued changes revert, DB FKs stage DROP CONSTRAINT) |
+| Table options | ✅ | Tablespace picker (non-system, from `pg_tablespace`) + row-level security toggle in the Options section |
+| Roles & grants management | ✅ | Objects → Roles: list non-system roles (attributes incl. connection limit — `rolconnlimit::int8` cast fix), role detail with attribute grid + memberships + privilege explorer; create/edit/drop roles staged through the queue |
+| Role privilege explorer | ✅ | Per-role privileges grouped by object class (tables/sequences/routines/schemas/databases) with collapsible sections — collapsed shows first 5 + fade, expand shows all, chevron hidden when ≤5; GRANT/REVOKE composer (object class + schema + name, WITH GRANT OPTION); aclexplode-based queries (`role_sequence_grants` removed in PG 15, `schema_privileges` never existed) |
### Object Explorer (non-table objects)
| Feature | Status | Details |
@@ -294,6 +307,8 @@ Planned work is prioritized in the [Project Roadmap](./ROADMAP.md) (source of tr
| 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. |
+| Create/Edit table + column-diff + rebuild | ✅ | Create Table + Edit Table column-diff editor (ADD/DROP/RENAME/ALTER TYPE/SET|DROP DEFAULT/SET|DROP NOT NULL, staged one-per-queue-item); atomic column-reorder table rebuild in a single transaction, preserving constraints/indexes/FKs/grants/sequences (v0.7.7) |
+| Relationships (FK CRUD, cross-schema, ON DELETE/UPDATE) | ✅ | FK create/edit/drop with cross-schema references and ON DELETE/UPDATE actions (v0.7.7) |
### Query Editor
| Feature | Status | Details |
diff --git a/README.md b/README.md
index 77ef7bc..e08e84c 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,9 @@
+
+ Data Grid & FK Preview — browse 50+ real demo orders and inspect related rows in one click.
+
Gridline
@@ -9,10 +12,6 @@
Unlimited connections, tabs, and saved queries — with first-class pg_dump, pg_restore, and DB-to-DB sync.
-
- Data Grid & FK Preview — browse 50+ real demo orders and inspect related rows in one click.
-
-
@@ -31,21 +30,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.6**):
+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.7**):
-| OS | Architecture | Download |
-| :--- | :--- | :--- |
-| **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) |
+| OS | Architecture | Download |
+| :--------------------------- | :--------------------------- | :------------------------------------------------------------------------------------------------------------------------------- |
+| **macOS** | Apple Silicon (M1/M2/M3/M4…) | [Gridline_0.7.7_aarch64.dmg](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.7/Gridline_0.7.7_aarch64.dmg) |
+| **macOS** | Intel | [Gridline_0.7.7_x64.dmg](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.7/Gridline_0.7.7_x64.dmg) |
+| **Windows** | x64 | [Gridline_0.7.7_x64-setup.exe](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.7/Gridline_0.7.7_x64-setup.exe) |
+| **Debian / Ubuntu** | amd64 | [Gridline_0.7.7_amd64.deb](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.7/Gridline_0.7.7_amd64.deb) |
+| **Fedora / RHEL / openSUSE** | x86_64 | [Gridline-0.7.7-1.x86_64.rpm](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.7/Gridline-0.7.7-1.x86_64.rpm) |
+| **Other Linux** | amd64 | [Gridline_0.7.7_amd64.AppImage](https://github.com/AdrianBonpin/gridline/releases/download/v0.7.7/Gridline_0.7.7_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.