v0.7.7: PG roles/grants, table maintenance, Create/Edit Table + atomic column-reorder rebuild, FK management, table options (#13)
Release / publish (, ubuntu-22.04) (push) Failing after 14m39s
Release / publish (--target aarch64-apple-darwin, macos-latest) (push) Canceled after 0s
Release / publish (--target x86_64-apple-darwin, macos-15-intel) (push) Canceled after 0s
Release / publish (, windows-latest) (push) Canceled after 0s

* 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
This commit is contained in:
2026-08-07 05:51:23 +08:00
committed by GitHub
parent 0c74d77e75
commit 7401e91a12
64 changed files with 6255 additions and 200 deletions
+46 -16
View File
@@ -5,6 +5,7 @@ import { useUiStore } from "../../stores/uiStore";
import { useNotificationStore } from "../../stores/notificationStore";
import * as cmd from "../../lib/commands";
import { buildChangePayload, buildChangeSql } from "../../lib/changePayload";
import { isSchemaModifyingQuery } from "../../lib/utils";
import type { QueueItem, QueueStatus } from "../../stores/dbViewerStore";
const statusBg: Record<QueueStatus, string> = {
@@ -25,6 +26,8 @@ function formatChangeLabel(change: QueueItem): string {
return `Empty Table: ${fullName}`;
case "drop_table":
return `Drop Table: ${fullName}`;
case "rebuild_table":
return change.description ?? `Rebuild ${fullName}`;
case "ddl":
return change.description ?? "DDL";
default:
@@ -52,9 +55,11 @@ function capitalizeType(type: string) {
return type.charAt(0).toUpperCase() + type.slice(1);
}
/** Badge label for a queue-item type — ddl renders uppercase to match its acronym. */
/** Badge label for a queue-item type — ddl/rebuild render uppercase. */
function badgeLabel(type: string): string {
return type === "ddl" ? "DDL" : capitalizeType(type);
if (type === "ddl") return "DDL";
if (type === "rebuild_table") return "REBUILD";
return capitalizeType(type);
}
function tableRef(change: QueueItem): string {
@@ -97,6 +102,11 @@ export function ChangesQueuePanel({ onCommitted }: { onCommitted?: () => void }
treeDirty = true;
const st = useDbViewerStore.getState();
st.closeTabsForTable(change.schema ?? "", change.table ?? "");
} else if (
change.type === "rebuild_table" ||
(change.type === "ddl" && change.sql && isSchemaModifyingQuery(change.sql))
) {
treeDirty = true;
}
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
@@ -177,7 +187,14 @@ export function ChangesQueuePanel({ onCommitted }: { onCommitted?: () => void }
>
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 min-w-0">
<span className="rounded bg-surface-raised px-1.5 py-0.5 text-xs font-medium text-text-muted">
<span
className={[
"rounded px-1.5 py-0.5 text-xs font-medium",
change.type === "rebuild_table"
? "bg-amber-500/10 text-amber-400"
: "bg-surface-raised text-text-muted",
].join(" ")}
>
{badgeLabel(change.type)}
</span>
<span className="text-sm text-text truncate">
@@ -204,19 +221,32 @@ export function ChangesQueuePanel({ onCommitted }: { onCommitted?: () => void }
</span>
) : null}
</div>
<div className="mt-1 text-xs text-text-muted truncate">
{formatChangeLabel(change)}
</div>
{formatValueDiff(change) && (
<div className="mt-0.5 font-mono text-xs text-text">
<span className="text-text-muted line-through">
{formatValueDiff(change)!.split(" → ")[0]}
</span>
<span className="mx-1 text-text-muted">→</span>
<span className="text-accent">
{formatValueDiff(change)!.split(" → ")[1]}
</span>
</div>
{change.type === "rebuild_table" ? (
<>
<div className="mt-1 text-xs text-text-muted truncate">
{formatChangeLabel(change)}
</div>
<pre className="mt-2 max-h-40 overflow-auto whitespace-pre-wrap rounded-md bg-canvas border border-border p-2 text-xs text-text-muted font-mono">
{buildChangeSql(change)}
</pre>
</>
) : (
<>
<div className="mt-1 text-xs text-text-muted truncate">
{formatChangeLabel(change)}
</div>
{formatValueDiff(change) && (
<div className="mt-0.5 font-mono text-xs text-text">
<span className="text-text-muted line-through">
{formatValueDiff(change)!.split(" → ")[0]}
</span>
<span className="mx-1 text-text-muted">→</span>
<span className="text-accent">
{formatValueDiff(change)!.split(" → ")[1]}
</span>
</div>
)}
</>
)}
</div>
))