Skip to content

Commit ae5a63a

Browse files
authored
Merge pull request #261 from datlechin/feat/plugin-settings-system
feat: add plugin settings system with options persistence
2 parents d2d52b6 + 1b7b073 commit ae5a63a

17 files changed

Lines changed: 412 additions & 29 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717

1818
### Changed
1919

20+
- Namespaced `disabledPlugins` UserDefaults key to `com.TablePro.disabledPlugins` with automatic migration
21+
- Removed unused plugin capability types (sqlDialect, aiProvider, cellRenderer, sidebarPanel)
2022
- SQLite driver extracted from built-in bundle to downloadable plugin, reducing app size
2123
- Unified error formatting across all database drivers via default `PluginDriverError.errorDescription`, removing 10 per-driver implementations
2224
- Standardized async bridging: 5 queue-based drivers (MySQL, PostgreSQL, MongoDB, Redis, MSSQL) now use shared `pluginDispatchAsync` helper
@@ -26,6 +28,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2628

2729
### Added
2830

31+
- Export plugin options (CSV, XLSX, JSON, SQL, MQL) now persist across app restarts
32+
- Plugins can declare settings views rendered in Settings > Plugins
2933
- True prepared statements for MSSQL (`sp_executesql`) and ClickHouse (HTTP query parameters), eliminating string interpolation for parameterized queries
3034
- Batch query operations for MSSQL, Oracle, and ClickHouse, eliminating N+1 query patterns for column, foreign key, and database metadata fetching; SQLite adds a batched `fetchAllForeignKeys` override within PRAGMA limitations
3135
- `PluginDriverError` protocol in TableProPluginKit for structured error reporting from driver plugins, with richer connection error messages showing error codes and SQL states

Plugins/CSVExportPlugin/CSVExportModels.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import Foundation
77

8-
public enum CSVDelimiter: String, CaseIterable, Identifiable {
8+
public enum CSVDelimiter: String, CaseIterable, Identifiable, Codable {
99
case comma = ","
1010
case semicolon = ";"
1111
case tab = "\\t"
@@ -27,7 +27,7 @@ public enum CSVDelimiter: String, CaseIterable, Identifiable {
2727
}
2828
}
2929

30-
public enum CSVQuoteHandling: String, CaseIterable, Identifiable {
30+
public enum CSVQuoteHandling: String, CaseIterable, Identifiable, Codable {
3131
case always = "Always"
3232
case asNeeded = "Quote if needed"
3333
case never = "Never"
@@ -43,7 +43,7 @@ public enum CSVQuoteHandling: String, CaseIterable, Identifiable {
4343
}
4444
}
4545

46-
public enum CSVLineBreak: String, CaseIterable, Identifiable {
46+
public enum CSVLineBreak: String, CaseIterable, Identifiable, Codable {
4747
case lf = "\\n"
4848
case crlf = "\\r\\n"
4949
case cr = "\\r"
@@ -59,7 +59,7 @@ public enum CSVLineBreak: String, CaseIterable, Identifiable {
5959
}
6060
}
6161

62-
public enum CSVDecimalFormat: String, CaseIterable, Identifiable {
62+
public enum CSVDecimalFormat: String, CaseIterable, Identifiable, Codable {
6363
case period = "."
6464
case comma = ","
6565

@@ -68,7 +68,7 @@ public enum CSVDecimalFormat: String, CaseIterable, Identifiable {
6868
public var separator: String { rawValue }
6969
}
7070

71-
public struct CSVExportOptions: Equatable {
71+
public struct CSVExportOptions: Equatable, Codable {
7272
public var convertNullToEmpty: Bool = true
7373
public var convertLineBreakToSpace: Bool = false
7474
public var includeFieldNames: Bool = true

Plugins/CSVExportPlugin/CSVExportPlugin.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,17 @@ final class CSVExportPlugin: ExportFormatPlugin {
2020
// swiftlint:disable:next force_try
2121
static let decimalFormatRegex = try! NSRegularExpression(pattern: #"^[+-]?\d+\.\d+$"#)
2222

23-
var options = CSVExportOptions()
23+
private let storage = PluginSettingsStorage(pluginId: "csv")
2424

25-
required init() {}
25+
var options = CSVExportOptions() {
26+
didSet { storage.save(options) }
27+
}
28+
29+
required init() {
30+
if let saved = storage.load(CSVExportOptions.self) {
31+
options = saved
32+
}
33+
}
2634

2735
func optionsView() -> AnyView? {
2836
AnyView(CSVExportOptionsView(plugin: self))

Plugins/JSONExportPlugin/JSONExportModels.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import Foundation
77

8-
public struct JSONExportOptions: Equatable {
8+
public struct JSONExportOptions: Equatable, Codable {
99
public var prettyPrint: Bool = true
1010
public var includeNullValues: Bool = true
1111
public var preserveAllAsStrings: Bool = false

Plugins/JSONExportPlugin/JSONExportPlugin.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,17 @@ final class JSONExportPlugin: ExportFormatPlugin {
1717
static let defaultFileExtension = "json"
1818
static let iconName = "curlybraces"
1919

20-
var options = JSONExportOptions()
20+
private let storage = PluginSettingsStorage(pluginId: "json")
2121

22-
required init() {}
22+
var options = JSONExportOptions() {
23+
didSet { storage.save(options) }
24+
}
25+
26+
required init() {
27+
if let saved = storage.load(JSONExportOptions.self) {
28+
options = saved
29+
}
30+
}
2331

2432
func optionsView() -> AnyView? {
2533
AnyView(JSONExportOptionsView(plugin: self))

Plugins/MQLExportPlugin/MQLExportModels.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import Foundation
77

8-
public struct MQLExportOptions: Equatable {
8+
public struct MQLExportOptions: Equatable, Codable {
99
public var batchSize: Int = 500
1010

1111
public init() {}

Plugins/MQLExportPlugin/MQLExportPlugin.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,17 @@ final class MQLExportPlugin: ExportFormatPlugin {
2424
PluginExportOptionColumn(id: "data", label: "Data", width: 44)
2525
]
2626

27-
var options = MQLExportOptions()
27+
private let storage = PluginSettingsStorage(pluginId: "mql")
2828

29-
required init() {}
29+
var options = MQLExportOptions() {
30+
didSet { storage.save(options) }
31+
}
32+
33+
required init() {
34+
if let saved = storage.load(MQLExportOptions.self) {
35+
options = saved
36+
}
37+
}
3038

3139
func defaultTableOptionValues() -> [Bool] {
3240
[true, true, true]

Plugins/SQLExportPlugin/SQLExportModels.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import Foundation
77

8-
public struct SQLExportOptions: Equatable {
8+
public struct SQLExportOptions: Equatable, Codable {
99
public var compressWithGzip: Bool = false
1010
public var batchSize: Int = 500
1111

Plugins/SQLExportPlugin/SQLExportPlugin.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,21 @@ final class SQLExportPlugin: ExportFormatPlugin {
2525
PluginExportOptionColumn(id: "data", label: "Data", width: 44)
2626
]
2727

28-
var options = SQLExportOptions()
28+
private let storage = PluginSettingsStorage(pluginId: "sql")
29+
30+
var options = SQLExportOptions() {
31+
didSet { storage.save(options) }
32+
}
33+
2934
var ddlFailures: [String] = []
3035

3136
private static let logger = Logger(subsystem: "com.TablePro", category: "SQLExportPlugin")
3237

33-
required init() {}
38+
required init() {
39+
if let saved = storage.load(SQLExportOptions.self) {
40+
options = saved
41+
}
42+
}
3443

3544
func defaultTableOptionValues() -> [Bool] {
3645
[true, true, true]

Plugins/TableProPluginKit/PluginCapability.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,4 @@ public enum PluginCapability: Int, Codable, Sendable {
44
case databaseDriver
55
case exportFormat
66
case importFormat
7-
case sqlDialect
8-
case aiProvider
9-
case cellRenderer
10-
case sidebarPanel
117
}

0 commit comments

Comments
 (0)