Skip to content

feat(favorites): linked SQL folders (#997)#999

Merged
datlechin merged 14 commits intomainfrom
feat/linked-sql-folders
May 5, 2026
Merged

feat(favorites): linked SQL folders (#997)#999
datlechin merged 14 commits intomainfrom
feat/linked-sql-folders

Conversation

@datlechin
Copy link
Copy Markdown
Member

@datlechin datlechin commented May 5, 2026

Summary

Implements #997 — Linked SQL Folders, plus all 5 originally-deferred v1.1 follow-ups in a single PR.

Point TablePro at a folder of .sql files (e.g. a Git repo of shared queries) and they appear in the Favorites sidebar live. Recursive subfolder watching via FSEventStreamCreate. Files keep their on-disk identity: clicking opens as a regular editor tab, ⌘S writes back. External modifications surface as a live banner above the tab and as a side-by-side diff at save time. Metadata can be edited inline. Drag a row onto the editor to insert content. Non-UTF-8 files load via auto-detected encoding and round-trip preserved.

What's new

Core (v1)

  • Settings > Editor > Linked SQL Folders to add/remove/toggle watched folders
  • Frontmatter convention -- @name: / -- @keyword: / -- @description: at the top of .sql files for sidebar display + autocomplete keyword binding
  • Mixed inline tree: linked folders sit at the same level as DB-stored favorites, distinguished by a link.circle.fill icon
  • Per-connection scope or global (visible across all connections)
  • ⌘S writes back to disk; mtime-based conflict detection on save
  • Move file to Trash from the sidebar (recoverable from Finder Trash)
  • Open in Finder context menu action
  • No Pro license required

Polish (v1.1, all originally deferred)

  • Inline metadata dialog: right-click a linked favorite → Edit Metadata... opens a dialog to edit name / keyword / description without touching the SQL body. Writes frontmatter back to disk preserving the rest of the file.
  • Live "modified on disk" banner: when the watcher detects a file was touched externally, the corresponding editor tab gets a yellow banner with a one-click Reload. Works alongside the save-time conflict prompt.
  • Side-by-side diff sheet: at save time, conflict prompt is now a 760×540 sheet showing line-level diff (Swift.CollectionDifference) instead of an NSAlert. Same three actions (Keep My Changes / Reload from Disk / Cancel).
  • Drag and drop: every favorite row (linked + regular) is draggable. Drop onto the SQL editor to insert content at the cursor. Linked rows lazily read file content at drop time, not at render time.
  • Non-UTF-8 handling: files load via String(contentsOf: usedEncoding:) with fallback chain (UTF-8 → Latin-1). Sidebar shows a yellow warning icon on non-UTF-8 rows. Saving preserves the file's original encoding (UTF-16, ISO Latin-1, etc.). UTF-8 BOM at the start of frontmatter no longer makes metadata silently disappear.

Architecture

Layer Files
Models LinkedSQLFolder, LinkedSQLFavorite, LinkedFavoriteTransfer
Storage LinkedSQLFolderStorage (UserDefaults), LinkedSQLIndex (separate SQLite linked_sql_index.db with mtime + encoding columns)
Watcher SQLFolderWatcher (FSEventStream, recursive, 1s debounce)
Parser SQLFrontmatterParser (with parseWithBody overload + BOM strip)
Writer LinkedSQLFavoriteWriter (preserves body + original encoding)
Loader FileTextLoader (encoding auto-detect with fallback chain)
UI LinkedSQLFavoritesSection (Settings), LinkedFavoriteRowView, LinkedFavoriteMetadataDialog, FileConflictDiffSheet, FileModifiedOnDiskBanner

Reuses existing TabRouter.openSQLFile() + TabQueryContent.sourceFileURL + saveFileToSourceURL() for the file-backed tab pipeline. New: loadMtime: Date? and externalModificationDetected: Bool fields on TabQueryContent. New: MainContentCoordinator.fileConflictRequest observable for sheet presentation.

Quality

  • 4 parallel code reviewers across two passes (3 for v1, 1 for v1.1)
  • 15 issues addressed before merge: critical pruning bug, UUID v5 RFC compliance, sync I/O moved to detached task with TaskGroup, workspace observer cleanup, symlink handling, doc comments removed, dedup search helpers, internal access modifier, proper Task cancellation, race-condition-safe file reload, pre-computed path components, BOM offset bug, eager .draggable payload, encoding-aware error messaging, CHANGELOG completeness.
  • xcodebuild ... build: SUCCEEDED
  • swiftlint lint --strict: clean

Test plan

v1

  • Add ~/sql-snippets with subfolders → sidebar reflects hierarchy
  • Drop new .sql file → appears live within ~1s
  • Click linked favorite → opens in editor tab
  • Edit + ⌘S → writes back to disk
  • Modify file externally then ⌘S → diff sheet appears
  • Choose Reload → tab content matches disk
  • Move to Trash → file in Finder Trash
  • Type dau keyword in editor → autocomplete shows linked file
  • Restart app → linked folders restored, file content re-read on tab restore
  • Disable folder via Settings toggle → sidebar hides linked folder, index rows preserved
  • Re-enable → sidebar shows folder again

v1.1

  • Right-click linked favorite → Edit Metadata... → change name/keyword/description → Save → file frontmatter updated, body preserved
  • Modify file externally with echo → tab top shows yellow banner → Reload → tab content updates, banner clears
  • Modify file externally then ⌘S → diff sheet shows side-by-side line-level diff (red removed left, yellow added right)
  • Drag a linked favorite row onto the editor → file content inserts at cursor
  • Drag a regular favorite row onto the editor → query inserts at cursor
  • Open a non-UTF-8 file (e.g. ISO Latin-1) → sidebar shows yellow triangle, file opens correctly
  • Save edits to non-UTF-8 file with characters representable in source encoding → succeeds
  • Save edits with characters NOT representable in source encoding → clear error "File encoding (ISO Latin-1) cannot represent these characters."
  • BOM-prefixed file with frontmatter → metadata recognized correctly

Regression

  • xcodebuild ... build passes
  • swiftlint lint --strict passes
  • Existing favorites continue to work (DB-stored, no on-disk file)
  • Existing file-backed editor tabs (File → Open SQL File) continue to work, with the new banner + diff sheet behavior on external mod

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@datlechin datlechin merged commit d318af4 into main May 5, 2026
2 checks passed
@datlechin datlechin deleted the feat/linked-sql-folders branch May 5, 2026 11:18
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