new ui
This commit is contained in:
@@ -25,6 +25,8 @@ struct MainView: View {
|
||||
@EnvironmentObject private var model: DatabaseModel
|
||||
|
||||
@State private var showingEditor = false
|
||||
@State private var showingDatabaseTransfer = false
|
||||
|
||||
@State private var editing = ConnectionProfile()
|
||||
@State private var editingPassword = ""
|
||||
|
||||
@@ -66,6 +68,9 @@ struct MainView: View {
|
||||
) == "dark" ? .dark : .light
|
||||
)
|
||||
.background(Color(nsColor: .windowBackgroundColor))
|
||||
.sheet(isPresented: $showingDatabaseTransfer) {
|
||||
WorkbenchDatabaseTransferView(model: model)
|
||||
}
|
||||
.sheet(isPresented: $showingEditor) {
|
||||
ConnectionEditor(
|
||||
profile: $editing,
|
||||
@@ -102,6 +107,13 @@ struct MainView: View {
|
||||
showingEditor = true
|
||||
}
|
||||
|
||||
toolbarButton(
|
||||
"Import / Export",
|
||||
icon: "arrow.up.arrow.down.square"
|
||||
) {
|
||||
showingDatabaseTransfer = true
|
||||
}
|
||||
|
||||
toolbarButton(
|
||||
"Refresh",
|
||||
icon: "arrow.clockwise"
|
||||
@@ -1539,3 +1551,503 @@ struct WorkbenchAdministrationView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Built-in Database Import / Export
|
||||
|
||||
struct WorkbenchDatabaseTransferView: View {
|
||||
@ObservedObject var model: DatabaseModel
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
@State private var selectedMode = 0
|
||||
@State private var database = ""
|
||||
@State private var isWorking = false
|
||||
@State private var progress = 0.0
|
||||
@State private var status = "Ready"
|
||||
@State private var operationTask: Task<Void, Never>?
|
||||
@State private var showingImportConfirmation = false
|
||||
@State private var pendingImportURL: URL?
|
||||
|
||||
private var selectedProfile: ConnectionProfile? {
|
||||
model.selected
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
header
|
||||
|
||||
Divider()
|
||||
|
||||
Picker("Operation", selection: $selectedMode) {
|
||||
Text("Data Export").tag(0)
|
||||
Text("Data Import / Restore").tag(1)
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
.padding(20)
|
||||
|
||||
Form {
|
||||
Section("MySQL Connection") {
|
||||
LabeledContent("Connection") {
|
||||
Text(selectedProfile?.name ?? "Not selected")
|
||||
}
|
||||
|
||||
Picker("Database", selection: $database) {
|
||||
Text("Select Database").tag("")
|
||||
|
||||
ForEach(model.databases, id: \.self) { name in
|
||||
Text(name).tag(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if selectedMode == 0 {
|
||||
Section("Export Options") {
|
||||
Text("Export the SQL definitions of all base tables in the selected database.")
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
Text("This version exports table structure. Table data, views, triggers and stored routines will be added in the next stage.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
} else {
|
||||
Section("Import Options") {
|
||||
Text("Import SQL statements into the selected database.")
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
Text("Supports ordinary SQL statements. Dumps using custom DELIMITER directives or stored routines are not supported yet.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
Section("Progress") {
|
||||
ProgressView(value: progress)
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
Text(status)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
|
||||
Divider()
|
||||
|
||||
HStack {
|
||||
Button("Close") {
|
||||
operationTask?.cancel()
|
||||
dismiss()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
if isWorking {
|
||||
Button("Cancel") {
|
||||
operationTask?.cancel()
|
||||
status = "Cancelling after current statement…"
|
||||
}
|
||||
} else {
|
||||
Button(
|
||||
selectedMode == 0
|
||||
? "Export SQL…"
|
||||
: "Import SQL…"
|
||||
) {
|
||||
if selectedMode == 0 {
|
||||
chooseExportDestination()
|
||||
} else {
|
||||
chooseImportSource()
|
||||
}
|
||||
}
|
||||
.buttonStyle(.borderedProminent)
|
||||
.disabled(
|
||||
selectedProfile == nil ||
|
||||
database.isEmpty
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding(16)
|
||||
}
|
||||
.frame(minWidth: 650, idealWidth: 780, minHeight: 500)
|
||||
.onAppear {
|
||||
if database.isEmpty {
|
||||
database = model.selectedDatabase.isEmpty
|
||||
? (model.databases.first ?? "")
|
||||
: model.selectedDatabase
|
||||
}
|
||||
}
|
||||
.confirmationDialog(
|
||||
"Import SQL into \(database)?",
|
||||
isPresented: $showingImportConfirmation
|
||||
) {
|
||||
Button("Import SQL") {
|
||||
guard let url = pendingImportURL else { return }
|
||||
|
||||
operationTask = Task {
|
||||
await importSQL(from: url)
|
||||
}
|
||||
}
|
||||
|
||||
Button("Cancel", role: .cancel) {
|
||||
pendingImportURL = nil
|
||||
}
|
||||
} message: {
|
||||
Text(
|
||||
"SQL files can modify or delete existing database objects and data. Ensure you have a backup before continuing."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private var header: some View {
|
||||
HStack(spacing: 12) {
|
||||
Image(systemName: "externaldrive.badge.timemachine")
|
||||
.font(.system(size: 28))
|
||||
.foregroundStyle(.blue)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text("Database Import / Export")
|
||||
.font(.system(size: 22, weight: .semibold))
|
||||
|
||||
Text("Built-in native MySQL database tools")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(20)
|
||||
}
|
||||
|
||||
private func chooseExportDestination() {
|
||||
let panel = NSSavePanel()
|
||||
panel.title = "Export MySQL Database"
|
||||
panel.nameFieldStringValue = "\(database).sql"
|
||||
panel.canCreateDirectories = true
|
||||
|
||||
guard panel.runModal() == .OK,
|
||||
let url = panel.url
|
||||
else { return }
|
||||
|
||||
operationTask = Task {
|
||||
await exportSQL(to: url)
|
||||
}
|
||||
}
|
||||
|
||||
private func chooseImportSource() {
|
||||
let panel = NSOpenPanel()
|
||||
panel.title = "Import MySQL SQL File"
|
||||
panel.allowedContentTypes = [.plainText]
|
||||
panel.allowsOtherFileTypes = true
|
||||
panel.canChooseDirectories = false
|
||||
panel.canChooseFiles = true
|
||||
|
||||
guard panel.runModal() == .OK,
|
||||
let url = panel.url
|
||||
else { return }
|
||||
|
||||
pendingImportURL = url
|
||||
showingImportConfirmation = true
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func execute(_ statement: String) async throws -> QueryResult {
|
||||
guard let profile = selectedProfile else {
|
||||
throw WorkbenchTransferError.message(
|
||||
"No MySQL connection selected"
|
||||
)
|
||||
}
|
||||
|
||||
return try await NativeMySQLRunner.run(
|
||||
profile: profile,
|
||||
database: database,
|
||||
password: PasswordStore.read(profile.id),
|
||||
sql: statement
|
||||
)
|
||||
}
|
||||
|
||||
private func quoteIdentifier(_ identifier: String) -> String {
|
||||
"`" + identifier.replacingOccurrences(
|
||||
of: "`",
|
||||
with: "``"
|
||||
) + "`"
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func exportSQL(to url: URL) async {
|
||||
isWorking = true
|
||||
progress = 0
|
||||
status = "Reading database structure…"
|
||||
|
||||
defer {
|
||||
isWorking = false
|
||||
operationTask = nil
|
||||
}
|
||||
|
||||
do {
|
||||
let quotedDatabase = quoteIdentifier(database)
|
||||
|
||||
let tableResult = try await execute(
|
||||
"SHOW FULL TABLES FROM \(quotedDatabase)"
|
||||
)
|
||||
|
||||
let tables = tableResult.rows.compactMap { row -> String? in
|
||||
guard row.count >= 2,
|
||||
row[1].uppercased() == "BASE TABLE"
|
||||
else { return nil }
|
||||
|
||||
return row[0]
|
||||
}
|
||||
|
||||
var output = """
|
||||
-- WorkbenchReplacement SQL Export
|
||||
-- Database: \(database)
|
||||
-- Generated: \(Date())
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
"""
|
||||
|
||||
for (index, table) in tables.enumerated() {
|
||||
try Task.checkCancellation()
|
||||
|
||||
status = "Exporting structure: \(table)"
|
||||
|
||||
let result = try await execute(
|
||||
"SHOW CREATE TABLE \(quotedDatabase).\(quoteIdentifier(table))"
|
||||
)
|
||||
|
||||
guard let row = result.rows.first,
|
||||
row.count >= 2
|
||||
else {
|
||||
throw WorkbenchTransferError.message(
|
||||
"Cannot retrieve CREATE TABLE for \(table)"
|
||||
)
|
||||
}
|
||||
|
||||
output += "\n-- Table: \(table)\n"
|
||||
output += row[1]
|
||||
output += ";\n\n"
|
||||
|
||||
progress = Double(index + 1) /
|
||||
Double(max(tables.count, 1))
|
||||
}
|
||||
|
||||
try Task.checkCancellation()
|
||||
|
||||
try output.write(
|
||||
to: url,
|
||||
atomically: true,
|
||||
encoding: .utf8
|
||||
)
|
||||
|
||||
progress = 1
|
||||
status = "Export complete: \(tables.count) table definitions"
|
||||
|
||||
} catch is CancellationError {
|
||||
status = "Export cancelled"
|
||||
} catch {
|
||||
status = "Export failed: \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func importSQL(from url: URL) async {
|
||||
isWorking = true
|
||||
progress = 0
|
||||
status = "Reading SQL file…"
|
||||
|
||||
defer {
|
||||
isWorking = false
|
||||
operationTask = nil
|
||||
}
|
||||
|
||||
do {
|
||||
let sql = try String(
|
||||
contentsOf: url,
|
||||
encoding: .utf8
|
||||
)
|
||||
|
||||
let statements = try WorkbenchSQLImportParser.parse(sql)
|
||||
|
||||
guard !statements.isEmpty else {
|
||||
status = "No SQL statements found"
|
||||
return
|
||||
}
|
||||
|
||||
for (index, statement) in statements.enumerated() {
|
||||
try Task.checkCancellation()
|
||||
|
||||
status = "Executing statement \(index + 1) of \(statements.count)"
|
||||
|
||||
_ = try await execute(statement)
|
||||
|
||||
progress = Double(index + 1) /
|
||||
Double(statements.count)
|
||||
}
|
||||
|
||||
status = "Import complete: \(statements.count) statements"
|
||||
|
||||
model.loadDatabases()
|
||||
|
||||
} catch is CancellationError {
|
||||
status = "Import cancelled; previously executed statements may remain applied"
|
||||
} catch {
|
||||
status = "Import failed: \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum WorkbenchTransferError: LocalizedError {
|
||||
case message(String)
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .message(let message):
|
||||
return message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SQL Import Parser
|
||||
//
|
||||
// Handles ordinary SQL statements with quoted strings,
|
||||
// quoted identifiers, line comments and block comments.
|
||||
// Stored routines and custom DELIMITER directives are
|
||||
// deliberately rejected rather than executed incorrectly.
|
||||
|
||||
enum WorkbenchSQLImportParser {
|
||||
static func parse(_ sql: String) throws -> [String] {
|
||||
var statements: [String] = []
|
||||
var current = ""
|
||||
var quote: Character?
|
||||
var escaped = false
|
||||
var lineComment = false
|
||||
var blockComment = false
|
||||
|
||||
let characters = Array(sql)
|
||||
var index = 0
|
||||
|
||||
while index < characters.count {
|
||||
let char = characters[index]
|
||||
let next: Character? = index + 1 < characters.count
|
||||
? characters[index + 1]
|
||||
: nil
|
||||
|
||||
if lineComment {
|
||||
if char == "\n" {
|
||||
lineComment = false
|
||||
current.append("\n")
|
||||
}
|
||||
index += 1
|
||||
continue
|
||||
}
|
||||
|
||||
if blockComment {
|
||||
if char == "*", next == "/" {
|
||||
blockComment = false
|
||||
index += 2
|
||||
} else {
|
||||
index += 1
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if let activeQuote = quote {
|
||||
current.append(char)
|
||||
|
||||
if escaped {
|
||||
escaped = false
|
||||
} else if char == "\\" && activeQuote != "`" {
|
||||
escaped = true
|
||||
} else if char == activeQuote {
|
||||
if next == activeQuote {
|
||||
current.append(next!)
|
||||
index += 1
|
||||
} else {
|
||||
quote = nil
|
||||
}
|
||||
}
|
||||
|
||||
index += 1
|
||||
continue
|
||||
}
|
||||
|
||||
if char == "'" || char == "\"" || char == "`" {
|
||||
quote = char
|
||||
current.append(char)
|
||||
index += 1
|
||||
continue
|
||||
}
|
||||
|
||||
if char == "#"
|
||||
|| (char == "-" && next == "-"
|
||||
&& (index + 2 >= characters.count
|
||||
|| characters[index + 2].isWhitespace)) {
|
||||
lineComment = true
|
||||
index += char == "#" ? 1 : 2
|
||||
continue
|
||||
}
|
||||
|
||||
if char == "/", next == "*" {
|
||||
// Executable MySQL comments are not safe to discard.
|
||||
if index + 2 < characters.count,
|
||||
characters[index + 2] == "!" {
|
||||
throw WorkbenchTransferError.message(
|
||||
"This SQL file contains MySQL executable comments, which are not supported by this importer yet."
|
||||
)
|
||||
}
|
||||
|
||||
blockComment = true
|
||||
index += 2
|
||||
continue
|
||||
}
|
||||
|
||||
if char == ";" {
|
||||
let statement = current.trimmingCharacters(
|
||||
in: .whitespacesAndNewlines
|
||||
)
|
||||
|
||||
if !statement.isEmpty {
|
||||
statements.append(statement)
|
||||
}
|
||||
|
||||
current = ""
|
||||
index += 1
|
||||
continue
|
||||
}
|
||||
|
||||
current.append(char)
|
||||
index += 1
|
||||
}
|
||||
|
||||
if quote != nil || blockComment {
|
||||
throw WorkbenchTransferError.message(
|
||||
"SQL file contains an unterminated quote or comment."
|
||||
)
|
||||
}
|
||||
|
||||
let remaining = current.trimmingCharacters(
|
||||
in: .whitespacesAndNewlines
|
||||
)
|
||||
|
||||
if !remaining.isEmpty {
|
||||
statements.append(remaining)
|
||||
}
|
||||
|
||||
for statement in statements {
|
||||
let upper = statement.uppercased()
|
||||
|
||||
if upper.hasPrefix("DELIMITER ")
|
||||
|| upper.hasPrefix("CREATE PROCEDURE")
|
||||
|| upper.hasPrefix("CREATE FUNCTION")
|
||||
|| upper.hasPrefix("CREATE TRIGGER")
|
||||
|| upper.hasPrefix("CREATE EVENT") {
|
||||
throw WorkbenchTransferError.message(
|
||||
"Stored routines, triggers, events and DELIMITER directives require the advanced SQL importer."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return statements
|
||||
}
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+232
-40
@@ -7,7 +7,7 @@
|
||||
"key": "MySQL Workbench",
|
||||
"location": {
|
||||
"startingColumn": 18,
|
||||
"startingLine": 88
|
||||
"startingLine": 93
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -15,7 +15,7 @@
|
||||
"key": "Navigator",
|
||||
"location": {
|
||||
"startingColumn": 20,
|
||||
"startingLine": 170
|
||||
"startingLine": 182
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -23,7 +23,7 @@
|
||||
"key": "Administration",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 171
|
||||
"startingLine": 183
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -31,7 +31,7 @@
|
||||
"key": "Schemas",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 172
|
||||
"startingLine": 184
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -39,7 +39,7 @@
|
||||
"key": "SCHEMAS",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 192
|
||||
"startingLine": 204
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -47,7 +47,7 @@
|
||||
"key": "Edit Connection",
|
||||
"location": {
|
||||
"startingColumn": 36,
|
||||
"startingLine": 246
|
||||
"startingLine": 258
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -55,7 +55,7 @@
|
||||
"key": "Set as Default Schema",
|
||||
"location": {
|
||||
"startingColumn": 24,
|
||||
"startingLine": 363
|
||||
"startingLine": 375
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -63,7 +63,7 @@
|
||||
"key": "Refresh Tables",
|
||||
"location": {
|
||||
"startingColumn": 24,
|
||||
"startingLine": 367
|
||||
"startingLine": 379
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -71,7 +71,7 @@
|
||||
"key": "Load Tables",
|
||||
"location": {
|
||||
"startingColumn": 28,
|
||||
"startingLine": 437
|
||||
"startingLine": 449
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -79,7 +79,7 @@
|
||||
"key": "Tables",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 410
|
||||
"startingLine": 422
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -87,7 +87,7 @@
|
||||
"key": "Select First 100 Rows",
|
||||
"location": {
|
||||
"startingColumn": 20,
|
||||
"startingLine": 493
|
||||
"startingLine": 505
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -95,7 +95,7 @@
|
||||
"key": "New Query Tab",
|
||||
"location": {
|
||||
"startingColumn": 19,
|
||||
"startingLine": 614
|
||||
"startingLine": 626
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -103,7 +103,7 @@
|
||||
"key": "Default Schema:",
|
||||
"location": {
|
||||
"startingColumn": 18,
|
||||
"startingLine": 639
|
||||
"startingLine": 651
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -111,7 +111,7 @@
|
||||
"key": "SQL Editor",
|
||||
"location": {
|
||||
"startingColumn": 18,
|
||||
"startingLine": 649
|
||||
"startingLine": 661
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -119,7 +119,7 @@
|
||||
"key": "Execute SQL",
|
||||
"location": {
|
||||
"startingColumn": 19,
|
||||
"startingLine": 627
|
||||
"startingLine": 639
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -127,7 +127,7 @@
|
||||
"key": "Format SQL",
|
||||
"location": {
|
||||
"startingColumn": 19,
|
||||
"startingLine": 634
|
||||
"startingLine": 646
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -135,7 +135,7 @@
|
||||
"key": "%lld",
|
||||
"location": {
|
||||
"startingColumn": 26,
|
||||
"startingLine": 689
|
||||
"startingLine": 701
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -143,7 +143,7 @@
|
||||
"key": "Result Grid",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 721
|
||||
"startingLine": 733
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -151,7 +151,7 @@
|
||||
"key": "No query results",
|
||||
"location": {
|
||||
"startingColumn": 26,
|
||||
"startingLine": 739
|
||||
"startingLine": 751
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -159,7 +159,7 @@
|
||||
"key": "Action Output",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 761
|
||||
"startingLine": 773
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -167,7 +167,7 @@
|
||||
"key": "UTF-8",
|
||||
"location": {
|
||||
"startingColumn": 18,
|
||||
"startingLine": 836
|
||||
"startingLine": 848
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -175,7 +175,7 @@
|
||||
"key": "Connection Settings",
|
||||
"location": {
|
||||
"startingColumn": 18,
|
||||
"startingLine": 1011
|
||||
"startingLine": 1023
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -183,7 +183,7 @@
|
||||
"key": "Connection Name",
|
||||
"location": {
|
||||
"startingColumn": 21,
|
||||
"startingLine": 1016
|
||||
"startingLine": 1028
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -191,7 +191,7 @@
|
||||
"key": "Hostname",
|
||||
"location": {
|
||||
"startingColumn": 21,
|
||||
"startingLine": 1021
|
||||
"startingLine": 1033
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -199,7 +199,7 @@
|
||||
"key": "Port",
|
||||
"location": {
|
||||
"startingColumn": 21,
|
||||
"startingLine": 1026
|
||||
"startingLine": 1038
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -207,7 +207,7 @@
|
||||
"key": "Username",
|
||||
"location": {
|
||||
"startingColumn": 21,
|
||||
"startingLine": 1032
|
||||
"startingLine": 1044
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -215,7 +215,7 @@
|
||||
"key": "Password (macOS Keychain)",
|
||||
"location": {
|
||||
"startingColumn": 21,
|
||||
"startingLine": 1037
|
||||
"startingLine": 1049
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -223,7 +223,7 @@
|
||||
"key": "Default Schema",
|
||||
"location": {
|
||||
"startingColumn": 21,
|
||||
"startingLine": 1042
|
||||
"startingLine": 1054
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -231,7 +231,7 @@
|
||||
"key": "Cancel",
|
||||
"location": {
|
||||
"startingColumn": 24,
|
||||
"startingLine": 1050
|
||||
"startingLine": 1062
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -239,7 +239,7 @@
|
||||
"key": "Save",
|
||||
"location": {
|
||||
"startingColumn": 24,
|
||||
"startingLine": 1054
|
||||
"startingLine": 1066
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -247,7 +247,7 @@
|
||||
"key": "The server did not return any columns.",
|
||||
"location": {
|
||||
"startingColumn": 25,
|
||||
"startingLine": 1376
|
||||
"startingLine": 1388
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -255,7 +255,7 @@
|
||||
"key": "Loading %@…",
|
||||
"location": {
|
||||
"startingColumn": 30,
|
||||
"startingLine": 1354
|
||||
"startingLine": 1366
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -263,7 +263,7 @@
|
||||
"key": "No Data",
|
||||
"location": {
|
||||
"startingColumn": 21,
|
||||
"startingLine": 1373
|
||||
"startingLine": 1385
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -271,7 +271,7 @@
|
||||
"key": "Unable to Load %@",
|
||||
"location": {
|
||||
"startingColumn": 25,
|
||||
"startingLine": 1360
|
||||
"startingLine": 1372
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -279,7 +279,7 @@
|
||||
"key": "Retry",
|
||||
"location": {
|
||||
"startingColumn": 28,
|
||||
"startingLine": 1366
|
||||
"startingLine": 1378
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -287,7 +287,7 @@
|
||||
"key": "Refresh",
|
||||
"location": {
|
||||
"startingColumn": 23,
|
||||
"startingLine": 1415
|
||||
"startingLine": 1427
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -295,7 +295,7 @@
|
||||
"key": "SQL Editor",
|
||||
"location": {
|
||||
"startingColumn": 23,
|
||||
"startingLine": 1422
|
||||
"startingLine": 1434
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -303,7 +303,7 @@
|
||||
"key": "Not loaded",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 1500
|
||||
"startingLine": 1512
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -311,7 +311,7 @@
|
||||
"key": "Updated %@",
|
||||
"location": {
|
||||
"startingColumn": 21,
|
||||
"startingLine": 1497
|
||||
"startingLine": 1509
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -319,7 +319,199 @@
|
||||
"key": "%lld rows",
|
||||
"location": {
|
||||
"startingColumn": 18,
|
||||
"startingLine": 1505
|
||||
"startingLine": 1517
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Import SQL into %@?",
|
||||
"location": {
|
||||
"startingColumn": 13,
|
||||
"startingLine": 1680
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Operation",
|
||||
"location": {
|
||||
"startingColumn": 20,
|
||||
"startingLine": 1581
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Data Export",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 1582
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Data Import / Restore",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 1583
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "MySQL Connection",
|
||||
"location": {
|
||||
"startingColumn": 25,
|
||||
"startingLine": 1589
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Export Options",
|
||||
"location": {
|
||||
"startingColumn": 29,
|
||||
"startingLine": 1604
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Import Options",
|
||||
"location": {
|
||||
"startingColumn": 29,
|
||||
"startingLine": 1613
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Progress",
|
||||
"location": {
|
||||
"startingColumn": 25,
|
||||
"startingLine": 1623
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Connection",
|
||||
"location": {
|
||||
"startingColumn": 36,
|
||||
"startingLine": 1590
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Database",
|
||||
"location": {
|
||||
"startingColumn": 28,
|
||||
"startingLine": 1594
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Select Database",
|
||||
"location": {
|
||||
"startingColumn": 30,
|
||||
"startingLine": 1595
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Export the SQL definitions of all base tables in the selected database.",
|
||||
"location": {
|
||||
"startingColumn": 30,
|
||||
"startingLine": 1605
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "This version exports table structure. Table data, views, triggers and stored routines will be added in the next stage.",
|
||||
"location": {
|
||||
"startingColumn": 30,
|
||||
"startingLine": 1608
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Import SQL statements into the selected database.",
|
||||
"location": {
|
||||
"startingColumn": 30,
|
||||
"startingLine": 1614
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Supports ordinary SQL statements. Dumps using custom DELIMITER directives or stored routines are not supported yet.",
|
||||
"location": {
|
||||
"startingColumn": 30,
|
||||
"startingLine": 1617
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Close",
|
||||
"location": {
|
||||
"startingColumn": 24,
|
||||
"startingLine": 1638
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Cancel",
|
||||
"location": {
|
||||
"startingColumn": 28,
|
||||
"startingLine": 1646
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Export SQL…",
|
||||
"location": {
|
||||
"startingColumn": 31,
|
||||
"startingLine": 1653
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Import SQL…",
|
||||
"location": {
|
||||
"startingColumn": 31,
|
||||
"startingLine": 1654
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Import SQL",
|
||||
"location": {
|
||||
"startingColumn": 20,
|
||||
"startingLine": 1683
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Cancel",
|
||||
"location": {
|
||||
"startingColumn": 20,
|
||||
"startingLine": 1691
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "SQL files can modify or delete existing database objects and data. Ensure you have a backup before continuing.",
|
||||
"location": {
|
||||
"startingColumn": 17,
|
||||
"startingLine": 1696
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Database Import / Export",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 1708
|
||||
}
|
||||
},
|
||||
{
|
||||
"comment": "",
|
||||
"key": "Built-in native MySQL database tools",
|
||||
"location": {
|
||||
"startingColumn": 22,
|
||||
"startingLine": 1711
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -4,3 +4,4 @@
|
||||
/Volumes/Developer/Applications/WorkbenchReplacement/build/Build/Products/Debug/WorkbenchReplacement.app
|
||||
/Volumes/Developer/Applications/WorkbenchReplacement/build/Build/Products/Debug/WorkbenchReplacement.app
|
||||
/Volumes/Developer/Applications/WorkbenchReplacement/build/Build/Products/Debug/WorkbenchReplacement.app
|
||||
/Volumes/Developer/Applications/WorkbenchReplacement/build/Build/Products/Debug/WorkbenchReplacement.app
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
+1
-1
@@ -19,7 +19,7 @@
|
||||
<dict>
|
||||
<key>cdhash</key>
|
||||
<data>
|
||||
5Wek/oPAL5JjNIHDxN/dkqjd0UI=
|
||||
aPFwAkm/guZ4EeZintWn1SNqigs=
|
||||
</data>
|
||||
<key>requirement</key>
|
||||
<string>identifier "WorkbenchReplacement.debug" and anchor apple generic and certificate leaf[subject.CN] = "Apple Development: Mark Gregory (FLBRJ3BYDD)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */</string>
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -132,6 +132,48 @@
|
||||
<key>uniqueIdentifier</key>
|
||||
<string>AD44F407-7FE5-46AE-A82F-8FAC1CA2720B</string>
|
||||
</dict>
|
||||
<key>BA4E5983-8DAA-49CA-A677-11E73E67F0B0</key>
|
||||
<dict>
|
||||
<key>className</key>
|
||||
<string>IDECommandLineBuildLog</string>
|
||||
<key>documentTypeString</key>
|
||||
<string><nil></string>
|
||||
<key>domainType</key>
|
||||
<string>Xcode.IDEActivityLogDomainType.BuildLog</string>
|
||||
<key>fileName</key>
|
||||
<string>BA4E5983-8DAA-49CA-A677-11E73E67F0B0.xcactivitylog</string>
|
||||
<key>hasPrimaryLog</key>
|
||||
<true/>
|
||||
<key>primaryObservable</key>
|
||||
<dict>
|
||||
<key>highLevelStatus</key>
|
||||
<string>S</string>
|
||||
<key>totalNumberOfAnalyzerIssues</key>
|
||||
<integer>0</integer>
|
||||
<key>totalNumberOfErrors</key>
|
||||
<integer>0</integer>
|
||||
<key>totalNumberOfTestFailures</key>
|
||||
<integer>0</integer>
|
||||
<key>totalNumberOfWarnings</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>schemeIdentifier-containerName</key>
|
||||
<string>WorkbenchReplacement project</string>
|
||||
<key>schemeIdentifier-schemeName</key>
|
||||
<string>WorkbenchReplacement</string>
|
||||
<key>schemeIdentifier-sharedScheme</key>
|
||||
<integer>1</integer>
|
||||
<key>signature</key>
|
||||
<string>Building project WorkbenchReplacement with scheme WorkbenchReplacement and configuration Debug</string>
|
||||
<key>timeStartedRecording</key>
|
||||
<real>813875867.553792</real>
|
||||
<key>timeStoppedRecording</key>
|
||||
<real>813875879.94755697</real>
|
||||
<key>title</key>
|
||||
<string>Building project WorkbenchReplacement with scheme WorkbenchReplacement and configuration Debug</string>
|
||||
<key>uniqueIdentifier</key>
|
||||
<string>BA4E5983-8DAA-49CA-A677-11E73E67F0B0</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1792182904.277697: Module build session file for module cache at Path(str: "/Volumes/Developer/Applications/WorkbenchReplacement/build/ModuleCache.noindex")
|
||||
1792183067.957757: Module build session file for module cache at Path(str: "/Volumes/Developer/Applications/WorkbenchReplacement/build/ModuleCache.noindex")
|
||||
|
||||
BIN
Binary file not shown.
+1
-1
@@ -3,7 +3,7 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>LastAccessedDate</key>
|
||||
<date>2026-10-16T20:35:04Z</date>
|
||||
<date>2026-10-16T20:37:47Z</date>
|
||||
<key>WorkspacePath</key>
|
||||
<string>/Volumes/Developer/Applications/WorkbenchReplacement/WorkbenchReplacement.xcodeproj</string>
|
||||
</dict>
|
||||
|
||||
Reference in New Issue
Block a user