Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions .claude/skills/release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ and `CURRENT_PROJECT_VERSION = 1`:
- **Test target** (TableProTests)
- **TableProPluginKit** framework
- **Bundled plugins** (included in app bundle): MySQLDriverPlugin,
PostgreSQLDriverPlugin, MSSQLDriverPlugin, MongoDBDriverPlugin,
RedisDriverPlugin, plus export/import plugins (CSV, JSON, SQL,
XLSX, MQL export; SQL import)
PostgreSQLDriverPlugin, SQLiteDriverPlugin, plus export plugins
(CSV, JSON, SQL export)
- **Separate plugin bundles** (not included in app bundle, distributed
independently): OracleDriverPlugin, ClickHouseDriverPlugin,
SQLiteDriverPlugin, DuckDBDriverPlugin
DuckDBDriverPlugin, MSSQLDriverPlugin, MongoDBDriverPlugin,
RedisDriverPlugin, XLSXExportPlugin, MQLExportPlugin, SQLImportPlugin

Use `replace_all: true` for each edit — the main app target's version
values are always unique (e.g., `MARKETING_VERSION = 0.16.1` and
Expand Down Expand Up @@ -219,7 +219,8 @@ with the release in Step 3 — no separate commit needed.
### Step 7: Check for Separate Plugin Changes

After the app release is pushed, check if any **separate plugin bundles**
(Oracle, ClickHouse, SQLite, DuckDB) have changes since their last
(Oracle, ClickHouse, DuckDB, MSSQL, MongoDB, Redis, XLSX, MQL,
SQLImport) have changes since their last
release. Also check `Plugins/TableProPluginKit/` — changes there affect
all plugins.

Expand All @@ -230,8 +231,13 @@ for commits:
# Separate plugins and their directory + tag-name mappings:
# Oracle: Plugins/OracleDriverPlugin/ plugin-oracle
# ClickHouse: Plugins/ClickHouseDriverPlugin/ plugin-clickhouse
# SQLite: Plugins/SQLiteDriverPlugin/ plugin-sqlite
# DuckDB: Plugins/DuckDBDriverPlugin/ plugin-duckdb
# MSSQL: Plugins/MSSQLDriverPlugin/ plugin-mssql
# MongoDB: Plugins/MongoDBDriverPlugin/ plugin-mongodb
# Redis: Plugins/RedisDriverPlugin/ plugin-redis
# XLSX: Plugins/XLSXExportPlugin/ plugin-xlsx
# MQL: Plugins/MQLExportPlugin/ plugin-mql
# SQLImport: Plugins/SQLImportPlugin/ plugin-sqlimport

# For each plugin, find the latest tag:
LAST_TAG=$(git tag -l "plugin-<name>-v*" --sort=-version:refname | head -1)
Expand Down Expand Up @@ -274,8 +280,9 @@ Plugin releases:

## Plugin Releases

Separate plugin bundles (Oracle, ClickHouse, SQLite, DuckDB) are released
independently from the main app via a dedicated workflow
Separate plugin bundles (Oracle, ClickHouse, DuckDB, MSSQL, MongoDB,
Redis, XLSX, MQL, SQLImport) are released independently from the main
app via a dedicated workflow
(`.github/workflows/build-plugin.yml`). They are also checked
automatically during app releases (Step 7 above).

Expand All @@ -296,8 +303,8 @@ plugin-<name>-v<version>
Examples: `plugin-oracle-v1.0.0`, `plugin-clickhouse-v1.2.0`

The `<name>` must match one of the cases in the workflow's mapping:
`oracle`, `clickhouse` (sqlite and duckdb need to be added to the
workflow's case statement when ready).
`oracle`, `clickhouse`, `duckdb`, `cassandra`, `mssql`, `mongodb`,
`redis`, `xlsx`, `mql`, `sqlimport`.

### Plugin Release Steps

Expand Down
45 changes: 38 additions & 7 deletions .github/workflows/build-plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,27 +57,57 @@ jobs:
TARGET="OracleDriver"; BUNDLE_ID="com.TablePro.OracleDriver"
DISPLAY_NAME="Oracle Driver"; SUMMARY="Oracle Database 12c+ driver via OracleNIO"
DB_TYPE_IDS='["Oracle"]'; ICON="server.rack"; BUNDLE_NAME="OracleDriver"
HOMEPAGE="https://docs.tablepro.app/databases/oracle" ;;
CATEGORY="database-driver"; HOMEPAGE="https://docs.tablepro.app/databases/oracle" ;;
clickhouse)
TARGET="ClickHouseDriver"; BUNDLE_ID="com.TablePro.ClickHouseDriver"
DISPLAY_NAME="ClickHouse Driver"; SUMMARY="ClickHouse OLAP database driver via HTTP interface"
DB_TYPE_IDS='["ClickHouse"]'; ICON="chart.bar.xaxis"; BUNDLE_NAME="ClickHouseDriver"
HOMEPAGE="https://docs.tablepro.app/databases/clickhouse" ;;
CATEGORY="database-driver"; HOMEPAGE="https://docs.tablepro.app/databases/clickhouse" ;;
sqlite)
TARGET="SQLiteDriver"; BUNDLE_ID="com.TablePro.SQLiteDriver"
DISPLAY_NAME="SQLite Driver"; SUMMARY="SQLite embedded database driver"
DB_TYPE_IDS='["SQLite"]'; ICON="internaldrive"; BUNDLE_NAME="SQLiteDriver"
HOMEPAGE="https://docs.tablepro.app/databases/sqlite" ;;
CATEGORY="database-driver"; HOMEPAGE="https://docs.tablepro.app/databases/sqlite" ;;
duckdb)
TARGET="DuckDBDriver"; BUNDLE_ID="com.TablePro.DuckDBDriver"
DISPLAY_NAME="DuckDB Driver"; SUMMARY="DuckDB analytical database driver"
DB_TYPE_IDS='["DuckDB"]'; ICON="bird"; BUNDLE_NAME="DuckDBDriver"
HOMEPAGE="https://docs.tablepro.app/databases/duckdb" ;;
CATEGORY="database-driver"; HOMEPAGE="https://docs.tablepro.app/databases/duckdb" ;;
cassandra)
TARGET="CassandraDriver"; BUNDLE_ID="com.TablePro.CassandraDriver"
DISPLAY_NAME="Cassandra Driver"; SUMMARY="Apache Cassandra and ScyllaDB driver via DataStax C driver"
DB_TYPE_IDS='["Cassandra", "ScyllaDB"]'; ICON="cassandra-icon"; BUNDLE_NAME="CassandraDriver"
HOMEPAGE="https://docs.tablepro.app/databases/cassandra" ;;
CATEGORY="database-driver"; HOMEPAGE="https://docs.tablepro.app/databases/cassandra" ;;
mssql)
TARGET="MSSQLDriver"; BUNDLE_ID="com.TablePro.MSSQLDriver"
DISPLAY_NAME="MSSQL Driver"; SUMMARY="Microsoft SQL Server driver via FreeTDS"
DB_TYPE_IDS='["SQL Server"]'; ICON="mssql-icon"; BUNDLE_NAME="MSSQLDriver"
CATEGORY="database-driver"; HOMEPAGE="https://docs.tablepro.app/databases/mssql" ;;
mongodb)
TARGET="MongoDBDriver"; BUNDLE_ID="com.TablePro.MongoDBDriver"
DISPLAY_NAME="MongoDB Driver"; SUMMARY="MongoDB document database driver via libmongoc"
DB_TYPE_IDS='["MongoDB"]'; ICON="mongodb-icon"; BUNDLE_NAME="MongoDBDriver"
CATEGORY="database-driver"; HOMEPAGE="https://docs.tablepro.app/databases/mongodb" ;;
redis)
TARGET="RedisDriver"; BUNDLE_ID="com.TablePro.RedisDriver"
DISPLAY_NAME="Redis Driver"; SUMMARY="Redis in-memory data store driver via hiredis"
DB_TYPE_IDS='["Redis"]'; ICON="redis-icon"; BUNDLE_NAME="RedisDriver"
CATEGORY="database-driver"; HOMEPAGE="https://docs.tablepro.app/databases/redis" ;;
xlsx)
TARGET="XLSXExport"; BUNDLE_ID="com.TablePro.XLSXExportPlugin"
DISPLAY_NAME="XLSX Export"; SUMMARY="Export data to Microsoft Excel XLSX format"
DB_TYPE_IDS='null'; ICON="doc.richtext"; BUNDLE_NAME="XLSXExport"
CATEGORY="export-format"; HOMEPAGE="https://docs.tablepro.app/features/export" ;;
mql)
TARGET="MQLExport"; BUNDLE_ID="com.TablePro.MQLExportPlugin"
DISPLAY_NAME="MQL Export"; SUMMARY="Export MongoDB data as MQL statements"
DB_TYPE_IDS='null'; ICON="doc.text"; BUNDLE_NAME="MQLExport"
CATEGORY="export-format"; HOMEPAGE="https://docs.tablepro.app/features/export" ;;
sqlimport)
TARGET="SQLImport"; BUNDLE_ID="com.TablePro.SQLImportPlugin"
DISPLAY_NAME="SQL Import"; SUMMARY="Import data from SQL dump files"
DB_TYPE_IDS='null'; ICON="square.and.arrow.down"; BUNDLE_NAME="SQLImport"
CATEGORY="import-format"; HOMEPAGE="https://docs.tablepro.app/features/import" ;;
*) echo "Unknown plugin: $plugin_name"; return 1 ;;
esac
}
Expand Down Expand Up @@ -157,7 +187,7 @@ jobs:
"$BUNDLE_ID" "$DISPLAY_NAME" "$VERSION" "$SUMMARY" \
"$DB_TYPE_IDS" "$ARM64_URL" "$ARM64_SHA" \
"$X86_64_URL" "$X86_SHA" "$MIN_APP_VERSION" \
"$ICON" "$HOMEPAGE" \
"$ICON" "$HOMEPAGE" "$CATEGORY" \
<<'PYTHON_SCRIPT'
import json, sys

Expand All @@ -166,6 +196,7 @@ jobs:
arm64_url, arm64_sha = sys.argv[6], sys.argv[7]
x86_64_url, x86_64_sha = sys.argv[8], sys.argv[9]
min_app_version, icon, homepage = sys.argv[10], sys.argv[11], sys.argv[12]
category = sys.argv[13] if len(sys.argv) > 13 else "database-driver"

with open("plugins.json", "r") as f:
manifest = json.load(f)
Expand All @@ -174,7 +205,7 @@ jobs:
"id": bundle_id, "name": name, "version": version,
"summary": summary,
"author": {"name": "TablePro", "url": "https://tablepro.app"},
"homepage": homepage, "category": "database-driver",
"homepage": homepage, "category": category,
"databaseTypeIds": db_type_ids,
"downloadURL": arm64_url, "sha256": arm64_sha,
"binaries": [
Expand Down
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Replaced fragmented Theme/DesignConstants/SQLEditorTheme/ToolbarDesignTokens with unified ThemeEngine
- Moved editor and data grid font settings into the theme system (Settings > Appearance)
- Extracted MSSQL, MongoDB, Redis, XLSX export, MQL export, and SQL import plugins from the app bundle into separately distributed plugins, downloadable from the plugin registry. MySQL, PostgreSQL, SQLite, CSV, JSON, and SQL export remain built-in
- Redesigned Plugins settings tab with HSplitView master-detail layout: plugin list on the left, detail pane on the right, matching macOS conventions. Plugin rows now show version, author/capability, and install status at a glance
- Download counts in browse tab now always fetch latest from GitHub API (5-minute in-memory cooldown per session)
- Replaced ~40 hardcoded `DatabaseType` switches across ~20 UI files with dynamic plugin property lookups via `PluginManager`, so third-party plugins get correct UI behavior (colors, labels, editor language, feature toggles) automatically
Expand All @@ -28,6 +31,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Full theme engine with 9 built-in presets (Default Light/Dark, Dracula, Solarized Light/Dark, One Dark, GitHub Light/Dark, Nord) and custom theme support
- Theme browser with visual preview cards in Settings > Appearance
- Per-theme customization of all colors (editor syntax, data grid, UI, sidebar, toolbar) and fonts
- Theme import/export as JSON files for sharing
- SSH TOTP/two-factor authentication support (auto-generate and prompt modes)
- SSH host key verification with fingerprint confirmation
- Keyboard Interactive SSH authentication method
Expand All @@ -47,7 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- SQL import options (wrap in transaction, disable FK checks) now persist across launches
- `needsRestart` banner persists across app quit/relaunch after plugin uninstall
- Copy as INSERT/UPDATE SQL statements from data grid context menu
- Configurable font family and size for data grid (Settings > Data Grid > Font)
- Configurable font family and size for data grid (now via theme customization in Settings > Appearance)
- Plugin download count display in Browse Plugins — fetched from GitHub Releases API and cached for 1 hour
- MSSQL query cancellation (`cancelQuery`) and lock timeout (`applyQueryTimeout`) support
- `~/.pgpass` file support for PostgreSQL/Redshift connections with live validation in the connection form
Expand Down
23 changes: 12 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
TablePro is a native macOS database client (SwiftUI + AppKit) — a fast, lightweight alternative to TablePlus. macOS 14.0+, Swift 5.9, Universal Binary (arm64 + x86_64).

- **Source**: `TablePro/` — `Core/` (business logic, services), `Views/` (UI), `Models/` (data structures), `ViewModels/`, `Extensions/`, `Theme/`
- **Plugins**: `Plugins/` — 8 `.tableplugin` bundles (MySQL, PostgreSQL, SQLite, ClickHouse, MSSQL, MongoDB, Redis, Oracle) + `TableProPluginKit` shared framework
- **Plugins**: `Plugins/` — `.tableplugin` bundles + `TableProPluginKit` shared framework. Built-in (bundled in app): MySQL, PostgreSQL, SQLite, CSV, JSON, SQL export. Separately distributed via plugin registry: ClickHouse, MSSQL, MongoDB, Redis, Oracle, DuckDB, XLSX, MQL, SQLImport
- **C bridges**: Each plugin contains its own C bridge module (e.g., `Plugins/MySQLDriverPlugin/CMariaDB/`, `Plugins/PostgreSQLDriverPlugin/CLibPQ/`)
- **Static libs**: `Libs/` — pre-built `libmariadb*.a`, `libpq*.a`, etc. (Git LFS tracked)
- **SPM deps**: CodeEditSourceEditor (`main` branch, tree-sitter editor), Sparkle (2.8.1, auto-update), OracleNIO. Managed via Xcode, no `Package.swift`.
Expand Down Expand Up @@ -55,16 +55,17 @@ All database drivers are `.tableplugin` bundles loaded at runtime by `PluginMana

Plugin bundles under `Plugins/`:

| Plugin | Database Types | C Bridge |
| ---------------------- | -------------------- | -------------------- |
| MySQLDriverPlugin | MySQL, MariaDB | CMariaDB |
| PostgreSQLDriverPlugin | PostgreSQL, Redshift | CLibPQ |
| SQLiteDriverPlugin | SQLite | (Foundation sqlite3) |
| ClickHouseDriverPlugin | ClickHouse | (URLSession HTTP) |
| MSSQLDriverPlugin | SQL Server | CFreeTDS |
| MongoDBDriverPlugin | MongoDB | CLibMongoc |
| RedisDriverPlugin | Redis | CRedis |
| OracleDriverPlugin | Oracle | OracleNIO (SPM) |
| Plugin | Database Types | C Bridge | Distribution |
| ---------------------- | -------------------- | -------------------- | ------------ |
| MySQLDriverPlugin | MySQL, MariaDB | CMariaDB | Built-in |
| PostgreSQLDriverPlugin | PostgreSQL, Redshift | CLibPQ | Built-in |
| SQLiteDriverPlugin | SQLite | (Foundation sqlite3) | Built-in |
| ClickHouseDriverPlugin | ClickHouse | (URLSession HTTP) | Registry |
| MSSQLDriverPlugin | SQL Server | CFreeTDS | Registry |
| MongoDBDriverPlugin | MongoDB | CLibMongoc | Registry |
| RedisDriverPlugin | Redis | CRedis | Registry |
| DuckDBDriverPlugin | DuckDB | CDuckDB | Registry |
| OracleDriverPlugin | Oracle | OracleNIO (SPM) | Registry |

When adding a new driver: create a new plugin bundle under `Plugins/`, implement `DriverPlugin` + `PluginDatabaseDriver`, add target to pbxproj. See `docs/development/plugin-system/` for details.

Expand Down
Loading
Loading