From ebd0bd1e29ffb4246f6cbfda00bf36e969468515 Mon Sep 17 00:00:00 2001 From: Mark Gregory Date: Sun, 18 Oct 2026 14:43:13 +0100 Subject: [PATCH] Improved progress display Previously, the progress bar updated only after completing an entire table. For large tables such as LIBARC, this could make the application appear to have stopped responding. Phase 10 updates the interface while rows are being exported. --- .../project.pbxproj | 56 +++++++++--------- {WorkbenchReplacement => DBSyn}/App.swift | 25 +++++--- .../DatabaseModel.swift | 0 .../MainView.swift | 4 +- .../MySQLProtocol.swift | 2 +- .../Resources/DBSyn.icns | Bin .../Resources/DBSynBrand.png | Bin docs/PHASE59-2-DBSYN-REBRAND.md | 10 ++++ scripts/release-dbsyn.sh | 17 ++++++ 9 files changed, 76 insertions(+), 38 deletions(-) rename {WorkbenchReplacement.xcodeproj => DBSyn.xcodeproj}/project.pbxproj (76%) rename {WorkbenchReplacement => DBSyn}/App.swift (93%) rename {WorkbenchReplacement => DBSyn}/DatabaseModel.swift (100%) rename {WorkbenchReplacement => DBSyn}/MainView.swift (99%) rename {WorkbenchReplacement => DBSyn}/MySQLProtocol.swift (99%) rename WorkbenchReplacement/Resources/WorkbenchReplacement.icns => DBSyn/Resources/DBSyn.icns (100%) rename WorkbenchReplacement/Resources/WorkbenchBrand.png => DBSyn/Resources/DBSynBrand.png (100%) create mode 100644 docs/PHASE59-2-DBSYN-REBRAND.md create mode 100755 scripts/release-dbsyn.sh diff --git a/WorkbenchReplacement.xcodeproj/project.pbxproj b/DBSyn.xcodeproj/project.pbxproj similarity index 76% rename from WorkbenchReplacement.xcodeproj/project.pbxproj rename to DBSyn.xcodeproj/project.pbxproj index 4df0f0e..f02b8ca 100644 --- a/WorkbenchReplacement.xcodeproj/project.pbxproj +++ b/DBSyn.xcodeproj/project.pbxproj @@ -12,19 +12,19 @@ 000000000000000000000015 /* DatabaseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 000000000000000000000012 /* DatabaseModel.swift */; }; 000000000000000000000017 /* MySQLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 000000000000000000000016 /* MySQLProtocol.swift */; }; - A10000000000000000000003 /* WorkbenchReplacement.icns in Resources */ = {isa = PBXBuildFile; fileRef = A10000000000000000000001 /* WorkbenchReplacement.icns */; }; - A10000000000000000000004 /* WorkbenchBrand.png in Resources */ = {isa = PBXBuildFile; fileRef = A10000000000000000000002 /* WorkbenchBrand.png */; }; + A10000000000000000000003 /* DBSyn.icns in Resources */ = {isa = PBXBuildFile; fileRef = A10000000000000000000001 /* DBSyn.icns */; }; + A10000000000000000000004 /* DBSynBrand.png in Resources */ = {isa = PBXBuildFile; fileRef = A10000000000000000000002 /* DBSynBrand.png */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 00000000000000000000000F /* WorkbenchReplacement.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WorkbenchReplacement.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 00000000000000000000000F /* DBSyn.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DBSyn.app; sourceTree = BUILT_PRODUCTS_DIR; }; 000000000000000000000010 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; 000000000000000000000011 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 000000000000000000000012 /* DatabaseModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseModel.swift; sourceTree = ""; }; 000000000000000000000016 /* MySQLProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MySQLProtocol.swift; sourceTree = ""; }; - A10000000000000000000001 /* WorkbenchReplacement.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = WorkbenchReplacement.icns; sourceTree = ""; }; - A10000000000000000000002 /* WorkbenchBrand.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = WorkbenchBrand.png; sourceTree = ""; }; + A10000000000000000000001 /* DBSyn.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = DBSyn.icns; sourceTree = ""; }; + A10000000000000000000002 /* DBSynBrand.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DBSynBrand.png; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -41,12 +41,12 @@ 000000000000000000000002 = { isa = PBXGroup; children = ( - 000000000000000000000003 /* WorkbenchReplacement */, + 000000000000000000000003 /* DBSyn */, 000000000000000000000004 /* Products */, ); sourceTree = ""; }; - 000000000000000000000003 /* WorkbenchReplacement */ = { + 000000000000000000000003 /* DBSyn */ = { isa = PBXGroup; children = ( 000000000000000000000010 /* App.swift */, @@ -55,13 +55,13 @@ 000000000000000000000016 /* MySQLProtocol.swift */, A10000000000000000000005 /* Resources */,); - path = WorkbenchReplacement; + path = DBSyn; sourceTree = ""; }; 000000000000000000000004 /* Products */ = { isa = PBXGroup; children = ( - 00000000000000000000000F /* WorkbenchReplacement.app */, + 00000000000000000000000F /* DBSyn.app */, ); name = Products; sourceTree = ""; @@ -70,8 +70,8 @@ A10000000000000000000005 /* Resources */ = { isa = PBXGroup; children = ( - A10000000000000000000001 /* WorkbenchReplacement.icns */, - A10000000000000000000002 /* WorkbenchBrand.png */, + A10000000000000000000001 /* DBSyn.icns */, + A10000000000000000000002 /* DBSynBrand.png */, ); path = Resources; sourceTree = ""; @@ -79,9 +79,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 000000000000000000000005 /* WorkbenchReplacement */ = { + 000000000000000000000005 /* DBSyn */ = { isa = PBXNativeTarget; - buildConfigurationList = 00000000000000000000000A /* Build configuration list for PBXNativeTarget "WorkbenchReplacement" */; + buildConfigurationList = 00000000000000000000000A /* Build configuration list for PBXNativeTarget "DBSyn" */; buildPhases = ( 000000000000000000000006 /* Sources */, 000000000000000000000008 /* Frameworks */, @@ -91,9 +91,9 @@ ); dependencies = ( ); - name = WorkbenchReplacement; - productName = WorkbenchReplacement; - productReference = 00000000000000000000000F /* WorkbenchReplacement.app */; + name = DBSyn; + productName = DBSyn; + productReference = 00000000000000000000000F /* DBSyn.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -109,7 +109,7 @@ }; }; }; - buildConfigurationList = 000000000000000000000009 /* Build configuration list for PBXProject "WorkbenchReplacement" */; + buildConfigurationList = 000000000000000000000009 /* Build configuration list for PBXProject "DBSyn" */; compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; @@ -122,7 +122,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 000000000000000000000005 /* WorkbenchReplacement */, + 000000000000000000000005 /* DBSyn */, ); }; /* End PBXProject section */ @@ -133,8 +133,8 @@ buildActionMask = 2147483647; files = ( - A10000000000000000000003 /* WorkbenchReplacement.icns in Resources */, - A10000000000000000000004 /* WorkbenchBrand.png in Resources */,); + A10000000000000000000003 /* DBSyn.icns in Resources */, + A10000000000000000000004 /* DBSynBrand.png in Resources */,); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ @@ -184,10 +184,10 @@ DEVELOPMENT_TEAM = 39R6U3437D; ENABLE_APP_SANDBOX = NO; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "Workbench Replacement"; - INFOPLIST_KEY_CFBundleIconFile = WorkbenchReplacement; + INFOPLIST_KEY_CFBundleDisplayName = "DBSyn"; + INFOPLIST_KEY_CFBundleIconFile = DBSyn; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; - PRODUCT_BUNDLE_IDENTIFIER = net.absdev.WorkbenchReplacement; + PRODUCT_BUNDLE_IDENTIFIER = net.absdev.DBSyn; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -202,10 +202,10 @@ DEVELOPMENT_TEAM = 39R6U3437D; ENABLE_APP_SANDBOX = NO; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_CFBundleDisplayName = "Workbench Replacement"; - INFOPLIST_KEY_CFBundleIconFile = WorkbenchReplacement; + INFOPLIST_KEY_CFBundleDisplayName = "DBSyn"; + INFOPLIST_KEY_CFBundleIconFile = DBSyn; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools"; - PRODUCT_BUNDLE_IDENTIFIER = net.absdev.WorkbenchReplacement; + PRODUCT_BUNDLE_IDENTIFIER = net.absdev.DBSyn; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; @@ -215,7 +215,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 000000000000000000000009 /* Build configuration list for PBXProject "WorkbenchReplacement" */ = { + 000000000000000000000009 /* Build configuration list for PBXProject "DBSyn" */ = { isa = XCConfigurationList; buildConfigurations = ( 00000000000000000000000B /* Debug */, @@ -224,7 +224,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 00000000000000000000000A /* Build configuration list for PBXNativeTarget "WorkbenchReplacement" */ = { + 00000000000000000000000A /* Build configuration list for PBXNativeTarget "DBSyn" */ = { isa = XCConfigurationList; buildConfigurations = ( 00000000000000000000000D /* Debug */, diff --git a/WorkbenchReplacement/App.swift b/DBSyn/App.swift similarity index 93% rename from WorkbenchReplacement/App.swift rename to DBSyn/App.swift index 7066cd1..1c7edef 100644 --- a/WorkbenchReplacement/App.swift +++ b/DBSyn/App.swift @@ -2,18 +2,18 @@ import SwiftUI import AppKit extension Notification.Name { - static let workbenchRevealSQLEditor = Notification.Name("WorkbenchReplacement.RevealSQLEditor") + static let workbenchRevealSQLEditor = Notification.Name("DBSyn.RevealSQLEditor") } @main -struct WorkbenchReplacementApp: App { +struct DBSynApp: App { @StateObject private var model = DatabaseModel() var body: some Scene { - WindowGroup("Workbench Replacement") { + WindowGroup("DBSyn") { WorkbenchLaunchView() .onAppear { - if let iconURL = Bundle.main.url(forResource: "WorkbenchReplacement", withExtension: "icns"), + if let iconURL = Bundle.main.url(forResource: "DBSyn", withExtension: "icns"), let icon = NSImage(contentsOf: iconURL) { NSApplication.shared.applicationIconImage = icon } @@ -24,6 +24,17 @@ struct WorkbenchReplacementApp: App { .defaultSize(width: 1200, height: 800) .windowResizability(.contentSize) .commands { + CommandGroup(replacing: .appInfo) { + Button("About DBSyn") { + let icon = NSImage(contentsOfFile: Bundle.main.path(forResource: "DBSynBrand", ofType: "png") ?? "") + NSApplication.shared.orderFrontStandardAboutPanel(options: [ + .applicationName: "DBSyn", + .applicationIcon: icon ?? NSApplication.shared.applicationIconImage, + .version: "Phase 59.2", + .credits: NSAttributedString(string: "Native MySQL client for macOS") + ]) + } + } WorkbenchFileCommands(model: model) } @@ -343,7 +354,7 @@ struct WorkbenchSplashView: View { Spacer() if let path = Bundle.main.path( - forResource: "WorkbenchBrand", + forResource: "DBSynBrand", ofType: "png" ), let image = NSImage(contentsOfFile: path) { Image(nsImage: image) @@ -352,7 +363,7 @@ struct WorkbenchSplashView: View { .frame(width: 160, height: 160) } - Text("Workbench Replacement") + Text("DBSyn") .font(.system(size: 30, weight: .bold)) Text("Modern MySQL Client for macOS") @@ -372,7 +383,7 @@ struct WorkbenchSplashView: View { ProgressView() .frame(width: 260) - Text("Starting Workbench Replacement…") + Text("Starting DBSyn…") .font(.caption) .foregroundStyle(.secondary) .padding(.bottom, 30) diff --git a/WorkbenchReplacement/DatabaseModel.swift b/DBSyn/DatabaseModel.swift similarity index 100% rename from WorkbenchReplacement/DatabaseModel.swift rename to DBSyn/DatabaseModel.swift diff --git a/WorkbenchReplacement/MainView.swift b/DBSyn/MainView.swift similarity index 99% rename from WorkbenchReplacement/MainView.swift rename to DBSyn/MainView.swift index ae52ac4..974e3bf 100644 --- a/WorkbenchReplacement/MainView.swift +++ b/DBSyn/MainView.swift @@ -175,7 +175,7 @@ struct MainView: View { private var mainToolbar: some View { HStack(spacing: 16) { - Image(nsImage: NSImage(named: "WorkbenchBrand") ?? NSImage(contentsOfFile: Bundle.main.path(forResource: "WorkbenchBrand", ofType: "png") ?? "") ?? NSImage()) + Image(nsImage: NSImage(named: "DBSynBrand") ?? NSImage(contentsOfFile: Bundle.main.path(forResource: "DBSynBrand", ofType: "png") ?? "") ?? NSImage()) .resizable() .scaledToFit() .frame(width: 30, height: 30) @@ -3463,7 +3463,7 @@ struct WorkbenchDatabaseTransferView: View { func write(_ value: String) throws { try handle?.write(contentsOf: Data(value.utf8)) } - try write("-- WorkbenchReplacement native export\n-- Database: \(database)\n-- Generated: \(Date())\nSET NAMES utf8mb4;\n\n") + try write("-- DBSyn native export\n-- Database: \(database)\n-- Generated: \(Date())\nSET NAMES utf8mb4;\n\n") let db = quoteIdentifier(database) for (index, table) in tables.enumerated() { try Task.checkCancellation() diff --git a/WorkbenchReplacement/MySQLProtocol.swift b/DBSyn/MySQLProtocol.swift similarity index 99% rename from WorkbenchReplacement/MySQLProtocol.swift rename to DBSyn/MySQLProtocol.swift index 1c38113..ab7fdc9 100644 --- a/WorkbenchReplacement/MySQLProtocol.swift +++ b/DBSyn/MySQLProtocol.swift @@ -358,7 +358,7 @@ private final class PersistentMySQLSessions { let connection: MySQLWireConnection } - private let queue = DispatchQueue(label: "WorkbenchReplacement.MySQLSessions") + private let queue = DispatchQueue(label: "DBSyn.MySQLSessions") private var connections: [UUID: Entry] = [:] func execute(profile: ConnectionProfile, database: String, diff --git a/WorkbenchReplacement/Resources/WorkbenchReplacement.icns b/DBSyn/Resources/DBSyn.icns similarity index 100% rename from WorkbenchReplacement/Resources/WorkbenchReplacement.icns rename to DBSyn/Resources/DBSyn.icns diff --git a/WorkbenchReplacement/Resources/WorkbenchBrand.png b/DBSyn/Resources/DBSynBrand.png similarity index 100% rename from WorkbenchReplacement/Resources/WorkbenchBrand.png rename to DBSyn/Resources/DBSynBrand.png diff --git a/docs/PHASE59-2-DBSYN-REBRAND.md b/docs/PHASE59-2-DBSYN-REBRAND.md new file mode 100644 index 0000000..981b597 --- /dev/null +++ b/docs/PHASE59-2-DBSYN-REBRAND.md @@ -0,0 +1,10 @@ +# Phase 59.2 — DBSyn rebrand + +- Renamed Xcode project, app target, product, source directory, icon resource, image resource and release script to DBSyn. +- Updated bundle display name and identifier to `net.absdev.DBSyn`. +- Replaced the default About menu with an explicit About DBSyn action and branded About panel. +- Preserved original icon artwork (now `DBSyn.icns` and `DBSynBrand.png`). +- Kept six legacy UserDefaults/Keychain service identifiers intentionally to preserve previously saved connections, SQL history, scripts, credentials and snapshots. These are internal compatibility keys, not displayed branding. +- Xcode project needs to be opened using `DBSyn.xcodeproj`; old project path no longer exists. +- Because the bundle identifier changes, existing macOS Keychain access may require credentials to be re-entered depending on code-signing identity. +- Swift parser verified on all four Swift files; Xcode build requires macOS. diff --git a/scripts/release-dbsyn.sh b/scripts/release-dbsyn.sh new file mode 100755 index 0000000..e2c4641 --- /dev/null +++ b/scripts/release-dbsyn.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +PHASE="${1:?Usage: release-dbsyn.sh PHASE NAME}" +NAME="${2:?Usage: release-dbsyn.sh PHASE NAME}" +cd "$ROOT" +mkdir -p releases +xcodebuild -project DBSyn.xcodeproj -scheme DBSyn -configuration Release -destination 'platform=macOS' -derivedDataPath "$ROOT/build" clean build +APP="$ROOT/build/Build/Products/Release/DBSyn.app" +test -d "$APP" +SOURCE="DBSyn-Phase${PHASE}-${NAME}-Source.zip" +BINARY="DBSyn-Phase${PHASE}-${NAME}-App-Unsigned.zip" +/usr/bin/zip -qr "releases/$SOURCE" DBSyn DBSyn.xcodeproj docs scripts -x '*.DS_Store' +(cd "$ROOT/build/Build/Products/Release" && /usr/bin/zip -qr "$ROOT/releases/$BINARY" DBSyn.app) +/usr/bin/unzip -tq "releases/$SOURCE" >/dev/null +/usr/bin/unzip -tq "releases/$BINARY" >/dev/null +printf 'Created:\n %s\n %s\n' "releases/$SOURCE" "releases/$BINARY"