Skip to content

feat(transfer): action-first launcher with .sql/.csv/.xlsx restore + Oracle hardening - #55

Closed
Blankll wants to merge 3 commits into
masterfrom
feat/transfer-hardening
Closed

feat(transfer): action-first launcher with .sql/.csv/.xlsx restore + Oracle hardening#55
Blankll wants to merge 3 commits into
masterfrom
feat/transfer-hardening

Conversation

@Blankll

@Blankll Blankll commented May 23, 2026

Copy link
Copy Markdown
Member

Summary

Reshape Transfer as an action-first launcher at /transfer: user picks Action → Source → Target → Options → Launch. Restore-from-file is a first-class action supporting .sql, .csv, .xlsx. Page-scoped JobsDrawer at bottom; cascading dropdowns replace tree pickers.

Why

Previous Transfer UI required users to right-click in the sidebar tree for backup/migrate. We removed right-click entirely — users now go directly to /transfer and act through the interactive launcher. Restore wasn't even a first-class action before; it is now.

What changed

Backend (src-tauri/)

  • restore_backup Tauri command: accepts job_id: Option<String> so JobsDrawer subscription matches; supports 'excel' alias for 'xlsx'; splits schema.table targets into proper schema/table.
  • DatabaseAdapter trait: new execute_batch_with_params(statement, column_count, values) method using native driver bind APIs.
    • PostgreSQL: tokio_postgres ToSql binds
    • MySQL: mysql_async::Value::Bytes positional params
    • SQL Server: tiberius::Query::bind
    • SQLite: rusqlite::params_from_iter
  • restore.rs (new, 491 LoC + tests):
    • Proper SQL splitter: tracks PostgreSQL dollar quotes ($$, $tag$), single/double quotes, line/block comments, splits every semicolon outside any quoted/dollar context (incl. same-line statements). 4 new tests.
    • CSV/XLSX streaming: iterate records in 500-row batches via parameterized inserts, no full-file collect.
    • qualified_table() helper: proper "schema"."table" quoting per dialect.
  • import.rs: fix Excel header double-consume — rows_iter was advanced then range.rows() re-iterated from top.
  • Removed destructive dropTargetFirst DROP TABLE from CSV/XLSX restore arms (flag still accepted, silently ignored for tabular — tabular restore targets EXISTING tables).

Frontend (src/components/transfer/launcher/)

  • 7 new components: TransferLauncher, ActionPicker, SourcePicker, TargetPicker, OptionsPanel, JobsDrawer, PresetsBar + types.ts, index.ts.
  • OptionsPanel: fileFormat Select (sql/csv/excel) with auto-detect from file extension; conditional targetTable Input for csv/xlsx; removed dangerous dropTargetFirst Checkbox from restore (kept in migrate).
  • TransferLauncher: validation rejects restore without fileFormat or missing targetTable for csv/xlsx; schema-keyed table selection (db.schema key) for PG/MSSQL schema disambiguation.
  • SourcePicker + TargetPicker: requestId race guards on cascading dropdown loaders — late responses from cancelled requests are dropped.
  • JobsDrawer: progress renders 0% when total === 0 instead of NaN%.
  • transferApi.restoreBackup + transferStore.startRestore: pass requestedJobId so JobsDrawer subscribes BEFORE invoke.
  • i18n: 3 new keys (transfer.launcher.fileFormat, .targetTable, .targetTablePlaceholder) in en/zh.

Oracle review

Previous Oracle review (bg_8e9948fb) rejected with 6 P0s + 5 P1s + 3 P2s. All addressed in this PR.

Defect Status
P0-1 jobId not propagated commands/transfer.rs:1891
P0-2 'excel' rejected commands/transfer.rs:1759
P0-3 missing format/table UI OptionsPanel.vue
P0-4 dropTargetFirst destructive ✅ removed from csv/xlsx arms
P0-5 SQL injection in CSV/XLSX INSERTs ✅ parameterized via new trait method
P0-6 splitter breaks on dollar quotes ✅ rewrote with 4 new tests
P1-1 schema lost in selection key TransferLauncher.vue
P1-2 async race in dropdowns ✅ requestId guards
P1-3 NaN% in progress JobsDrawer.vue:121
P1-4 schema/table quoting qualified_table() helper
P1-5 full-file collect ✅ streaming CSV/XLSX batches
P2 arrow consts ⚠️ kept function per antfu top-level-function rule
P2 inline comments ✅ 6 stripped
P2 import.rs Excel header bug import.rs:384

Gates

  • cargo fmt
  • cargo clippy --all-targets -- -D warnings
  • cargo test ✓ (116/116; integration tests requiring live DBs ignored as expected)
  • vue-tsc -b ✓ (pre-existing tsconfig.node.json noEmit warning, unrelated)
  • npm run lint:check ✓ (0 errors, 1 pre-existing warning in ExportWizard.vue:152)
  • npm test ✓ (276/276)

Manual QA checklist (deferred)

  • PG: SQL backup → restore round-trip
  • MySQL: CSV export → restore to fresh table
  • SQL Server: XLSX export → restore (excel alias path)
  • SQLite: SQL restore with dollar-quoted function body
  • All 4 engines × restore-to-existing-table (no DROP)

Base automatically changed from feat/transfer-redesign-scope-first to master May 23, 2026 13:09
…l pagination

Four correctness fixes to the scope-first transfer module:

1. backup_server partial-failure summary parity
   Mirror migrate_server semantics via new summarize_backup_outcome helper.
   Per-table failures aggregated with db.schema.table context.
   - All succeed -> Completed, error=None
   - Partial    -> Completed, error=Some(summary)
   - All fail   -> Failed, error=Some(summary)

2. PG + MSSQL ensure_target_database always probes accessibility
   Previously only verified connectivity when CREATEing the DB. Now opens
   a temp adapter to target and runs SELECT 1 whether DB was just created
   or already existed, surfacing inaccessible targets upfront instead of
   mid-transfer. MySQL unchanged (same-connection semantics).

3. System database exclusion in whole-server scope
   New list_databases_for_connection(exclude_system_databases) +
   should_exclude_system_database + filter_system_databases_for_whole_server.
   Applied only via expand_selection implicit expansion; explicit user
   selections respected; browse.rs::list_databases unchanged (UI sidebar
   unaffected).
   - MySQL : mysql, information_schema, performance_schema, sys
   - PG    : template0, template1 (kept 'postgres' as legitimate user DB)
   - MSSQL : master, msdb, tempdb, model

4. SQL Server pagination
   New paginate_clause(db_type, offset, limit, base_has_order_by) helper.
   - MySQL/PG/SQLite -> LIMIT n OFFSET m
   - MSSQL          -> [ORDER BY (SELECT NULL)] OFFSET n ROWS FETCH NEXT m ROWS ONLY
   The synthetic ORDER BY is suppressed when the base query already has
   one (e.g. ExportSource.order_by), preventing invalid T-SQL with two
   ORDER BY clauses. Replaces inline LIMIT/OFFSET in export.rs (batch and
   preview paths) and migration.rs.

Gates: cargo fmt clean, cargo test --lib 82/82 (+6 new tests),
vue-tsc clean, eslint 0 errors, jest 276/276.

Stacked on feat/transfer-redesign-scope-first (PR #54).
@Blankll
Blankll force-pushed the feat/transfer-hardening branch from 4dfa37d to 569a915 Compare May 23, 2026 13:11
Action-first Transfer page (/transfer) with Action -> Source -> Target -> Options -> Launch flow.
Restore-from-file as first-class action supporting .sql, .csv, .xlsx.
Page-scoped JobsDrawer at bottom; cascading dropdowns for source/target picking.

Backend (src-tauri/):
- restore_backup: accept job_id, support 'excel' alias, split schema.table targets
- DatabaseAdapter: new execute_batch_with_params trait method
- pg/mysql/mssql/sqlite: parameterized batch INSERT implementations
- restore.rs: new SQL splitter handles dollar quotes ($$, $tag$), same-line semicolons,
  string literals, comments; streaming CSV/XLSX batches; schema-qualified quoting
- import.rs: fix Excel header double-consume bug

Frontend (src/components/transfer/launcher/):
- TransferLauncher, ActionPicker, SourcePicker, TargetPicker, OptionsPanel,
  JobsDrawer, PresetsBar (new)
- File format selector + auto-detect; target table input for csv/xlsx
- Async race guards in cascading dropdowns
- Schema-keyed table selection
- NaN% guard in JobsDrawer progress
- transferApi/transferStore wire jobId through restoreBackup

Removed destructive dropTargetFirst from tabular restore paths.
i18n: 3 new launcher keys in en/zh.

Gates: cargo fmt/clippy/test 116/116, vue-tsc 0 errors, eslint 0E/1W (pre-existing),
jest 276/276.
@Blankll Blankll changed the title fix(transfer): harden backup, target-db probe, system-db filter, mssql pagination feat(transfer): action-first launcher with .sql/.csv/.xlsx restore + Oracle hardening May 23, 2026
Redesign launcher from stacked cards to console-style split layout:
- Context bar with live breadcrumb (CONN → SCOPE → DB → ACTION → FMT)
- Side-by-side source/destination panels for at-a-glance awareness
- Summary bar showing scope, tables, format, status with READY/INCOMPLETE
- Action tiles replacing card grid, with accent highlight on selection
- Activity bar replacing floating drawer, always visible at bottom
- Monospace labels, steel-blue-gray palette, teal accents

Design tokens in CSS variables across light/dark mode:
- OKLCH color system with tinted neutrals
- JetBrains Mono, Sofia Sans, Wix Madefor Text fonts
- Transfer console component classes (panels, sections, tiles, bar)

Also:
- Add .impeccable.md design context document
- Ignore .omo/ agent runtime data
@Blankll Blankll closed this May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant