Skip to content

feat(plugins): remember last-used export and import settings#1593

Merged
datlechin merged 2 commits into
mainfrom
fix-1591-export-settings
Jun 5, 2026
Merged

feat(plugins): remember last-used export and import settings#1593
datlechin merged 2 commits into
mainfrom
fix-1591-export-settings

Conversation

@datlechin

@datlechin datlechin commented Jun 5, 2026

Copy link
Copy Markdown
Member

Closes #1591

What

Export and import dialogs reopen with the last-used format, options, and encoding. Option changes are kept only when the export or import completes, so cancelling no longer overwrites saved settings. A Reset to Defaults button in both dialogs restores the stock options for the current format.

Why

Format-specific options have persisted since v0.18.0, but three gaps made repeat exports feel like starting over:

  1. The format tab reset to CSV on every open. The dialog created a fresh ExportConfiguration each presentation.
  2. Options views bind straight to the plugin singleton, whose didSet writes to UserDefaults on every toggle. Cancelling a dialog silently committed half-changed options.
  3. Import encoding reset to UTF-8 on every open. It was never stored.

The fix follows HIG Launching ("restore the previous state... avoid making people retrace steps") and the persist-on-success contract Sequel Ace uses (state saved only in the OK handler, never on Cancel).

How

  • New TransferDialogStorage (UserDefaults, same pattern as AppSettingsStorage) holds the last export format id and last import encoding. Both are written only on successful completion. The query-results export shares ExportDialog, so it gets format memory for free.
  • Both dialogs snapshot every available plugin's settings on appear. Any dismissal without success restores the snapshots through the normal persist path, reverting memory and disk together.
  • SettablePluginDiscoverable gains snapshotSettingsData(), restoreSettingsData(_:), and resetSettingsToDefaults(), all with default implementations. Additive under Library Evolution: no PluginKit version bump, no plugin re-release. Each bundled plugin overrides reset with one line because the Settings associated type has no init() requirement.
  • The save panel keeps directoryURL unset, so macOS continues to remember the last directory natively.

Tests

  • TransferDialogStorageTests: round-trips, overwrite, empty defaults, unknown-encoding fallback, on an isolated UserDefaults suite.
  • SettablePluginSnapshotTests: snapshot encodes current settings, restore reverts memory and storage, invalid data ignored, reset returns defaults, dispatch through the type-erased protocol as the dialogs use it.

No UI automation: the dialogs need a live database connection and the out-of-process NSSavePanel/NSOpenPanel, which UI tests cannot drive deterministically. The persistence logic is covered by the unit tests above.

Notes

  • Known pre-existing limitation, unchanged: two export dialogs open in two windows share plugin singletons, so concurrent edits could cross.
  • The "Reset to Defaults" string catalog entry will be auto-extracted on the next Xcode build; SwiftUI button literals auto-localize.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a87029ebfa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

private func resetCurrentFormatSettings() {
guard let settable = currentPlugin as? any SettablePluginDiscoverable else { return }
settable.resetSettingsToDefaults()
settingsSnapshots[config.formatId] = settable.snapshotSettingsData()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep reset changes cancellable

When a user clicks Reset to Defaults and then cancels/closes the export dialog, this line replaces the original on-appear snapshot with the reset data. onDisappear then restores the reset settings rather than the pre-dialog settings, and restoreSettingsData persists through the plugin didSet, so cancelling still overwrites saved plugin options; the analogous import reset path has the same behavior. Keep the original snapshot until a successful export/import clears it.

Useful? React with 👍 / 👎.

@mintlify

mintlify Bot commented Jun 5, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟢 Ready View Preview Jun 5, 2026, 4:48 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0b1d83f793

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +12 to +14
func snapshotSettingsData() -> Data?
func restoreSettingsData(_ data: Data)
func resetSettingsToDefaults()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Bump the plugin kit ABI version

Adding these requirements changes the SettablePluginDiscoverable witness table that export/import plugins compiled against kit 18 provide, but PluginManager.currentPluginKitVersion and the bundled Info.plist kit declarations still remain at 18. In an installation with an existing third-party settable export/import plugin built against the previous kit 18, version validation will still accept and load it, and the new dialog paths call snapshotSettingsData/resetSettingsToDefaults through this existential, which can dispatch against a stale witness table instead of forcing the plugin to rebuild against the new protocol. Please bump the plugin kit version and bundled plugin declarations so incompatible plugins are rejected or updated.

Useful? React with 👍 / 👎.

@datlechin datlechin merged commit 200478c into main Jun 5, 2026
4 of 5 checks passed
@datlechin datlechin deleted the fix-1591-export-settings branch June 5, 2026 17:01
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.

Save export configurations

1 participant