new release script
This commit is contained in:
+109
-24
@@ -8,18 +8,10 @@ import UniformTypeIdentifiers
|
||||
// MARK: - Classic Workbench Colours
|
||||
|
||||
private enum WB {
|
||||
static let toolbar = Color(nsColor: NSColor(
|
||||
calibratedWhite: 0.88, alpha: 1
|
||||
))
|
||||
static let sidebar = Color(nsColor: NSColor(
|
||||
calibratedWhite: 0.94, alpha: 1
|
||||
))
|
||||
static let border = Color(nsColor: NSColor(
|
||||
calibratedWhite: 0.76, alpha: 1
|
||||
))
|
||||
static let header = Color(nsColor: NSColor(
|
||||
calibratedWhite: 0.91, alpha: 1
|
||||
))
|
||||
static let toolbar = Color(nsColor: .controlBackgroundColor)
|
||||
static let sidebar = Color(nsColor: .underPageBackgroundColor)
|
||||
static let border = Color(nsColor: .separatorColor)
|
||||
static let header = Color(nsColor: .controlBackgroundColor)
|
||||
}
|
||||
|
||||
// MARK: - Main Window
|
||||
@@ -85,11 +77,6 @@ struct MainView: View {
|
||||
statusBar
|
||||
}
|
||||
.frame(minWidth: 800, minHeight: 520)
|
||||
.preferredColorScheme(
|
||||
UserDefaults.standard.string(
|
||||
forKey: "preferences.appearance"
|
||||
) == "dark" ? .dark : .light
|
||||
)
|
||||
.background(Color(nsColor: .windowBackgroundColor))
|
||||
.onReceive(NotificationCenter.default.publisher(for: .workbenchRevealSQLEditor)) { _ in
|
||||
administrationPage = nil
|
||||
@@ -1376,6 +1363,7 @@ struct SQLTextView: NSViewRepresentable {
|
||||
@Binding var selectedSQL: String
|
||||
var focusRequest: Int = 0
|
||||
var completions: [String] = []
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(self)
|
||||
@@ -1385,11 +1373,12 @@ struct SQLTextView: NSViewRepresentable {
|
||||
let scroll = NSTextView.scrollableTextView()
|
||||
let editor = scroll.documentView as! NSTextView
|
||||
|
||||
scroll.appearance = NSAppearance(named: .aqua)
|
||||
editor.appearance = NSAppearance(named: .aqua)
|
||||
editor.backgroundColor = .white
|
||||
editor.textColor = .black
|
||||
scroll.backgroundColor = .white
|
||||
let nativeAppearance = NSAppearance(named: colorScheme == .dark ? .darkAqua : .aqua)
|
||||
scroll.appearance = nativeAppearance
|
||||
editor.appearance = nativeAppearance
|
||||
editor.backgroundColor = .textBackgroundColor
|
||||
editor.textColor = .textColor
|
||||
scroll.backgroundColor = .textBackgroundColor
|
||||
|
||||
editor.isEditable = true
|
||||
editor.isRichText = false
|
||||
@@ -1429,6 +1418,13 @@ struct SQLTextView: NSViewRepresentable {
|
||||
return
|
||||
}
|
||||
context.coordinator.parent = self
|
||||
let nativeAppearance = NSAppearance(named: colorScheme == .dark ? .darkAqua : .aqua)
|
||||
scroll.appearance = nativeAppearance
|
||||
editor.appearance = nativeAppearance
|
||||
editor.backgroundColor = .textBackgroundColor
|
||||
editor.textColor = .textColor
|
||||
scroll.backgroundColor = .textBackgroundColor
|
||||
context.coordinator.highlight(editor)
|
||||
if context.coordinator.lastFocusRequest != focusRequest {
|
||||
context.coordinator.lastFocusRequest = focusRequest
|
||||
DispatchQueue.main.async { [weak editor] in
|
||||
@@ -2073,6 +2069,7 @@ struct NativeResultGrid: NSViewRepresentable {
|
||||
let columns: [String]
|
||||
let rows: [[String]]
|
||||
var hiddenColumnIndices: Set<Int> = []
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator()
|
||||
@@ -2084,10 +2081,13 @@ struct NativeResultGrid: NSViewRepresentable {
|
||||
scroll.hasHorizontalScroller = true
|
||||
scroll.autohidesScrollers = true
|
||||
scroll.drawsBackground = true
|
||||
scroll.backgroundColor = .white
|
||||
scroll.backgroundColor = .textBackgroundColor
|
||||
|
||||
let table = NSTableView()
|
||||
table.headerView = NSTableHeaderView()
|
||||
let nativeAppearance = NSAppearance(named: colorScheme == .dark ? .darkAqua : .aqua)
|
||||
scroll.appearance = nativeAppearance
|
||||
table.appearance = nativeAppearance
|
||||
table.usesAlternatingRowBackgroundColors =
|
||||
UserDefaults.standard.object(
|
||||
forKey: "preferences.alternatingRows"
|
||||
@@ -2102,7 +2102,7 @@ struct NativeResultGrid: NSViewRepresentable {
|
||||
table.allowsColumnResizing = true
|
||||
table.allowsColumnReordering = true
|
||||
table.columnAutoresizingStyle = .noColumnAutoresizing
|
||||
table.backgroundColor = .white
|
||||
table.backgroundColor = .textBackgroundColor
|
||||
|
||||
context.coordinator.columns = columns
|
||||
context.coordinator.rows = rows
|
||||
@@ -2126,6 +2126,12 @@ struct NativeResultGrid: NSViewRepresentable {
|
||||
return
|
||||
}
|
||||
|
||||
let nativeAppearance = NSAppearance(named: colorScheme == .dark ? .darkAqua : .aqua)
|
||||
scroll.appearance = nativeAppearance
|
||||
table.appearance = nativeAppearance
|
||||
scroll.backgroundColor = .textBackgroundColor
|
||||
table.backgroundColor = .textBackgroundColor
|
||||
|
||||
let oldColumns = context.coordinator.columns
|
||||
|
||||
context.coordinator.columns = columns
|
||||
@@ -2963,6 +2969,42 @@ struct WorkbenchDatabaseTransferView: View {
|
||||
@State private var loadingDatabases = false
|
||||
@State private var lastBackupURL: URL?
|
||||
@State private var lastVerificationReport = ""
|
||||
// Phase 61: Recent backups are kept locally, never uploaded or copied.
|
||||
@State private var recentBackups: [String] = UserDefaults.standard.stringArray(forKey: "DBSyn.recentBackups.v1") ?? []
|
||||
@State private var selectedBackupPath = ""
|
||||
|
||||
private func rememberBackup(_ url: URL) {
|
||||
let path = url.standardizedFileURL.path
|
||||
recentBackups.removeAll { $0 == path }
|
||||
recentBackups.insert(path, at: 0)
|
||||
recentBackups = Array(recentBackups.prefix(20))
|
||||
selectedBackupPath = path
|
||||
UserDefaults.standard.set(recentBackups, forKey: "DBSyn.recentBackups.v1")
|
||||
}
|
||||
|
||||
private var selectedBackupURL: URL? {
|
||||
guard !selectedBackupPath.isEmpty,
|
||||
FileManager.default.fileExists(atPath: selectedBackupPath) else { return nil }
|
||||
return URL(fileURLWithPath: selectedBackupPath)
|
||||
}
|
||||
|
||||
private func verifyRecentBackup() {
|
||||
guard let url = selectedBackupURL else { return }
|
||||
operationTask = Task {
|
||||
isWorking = true
|
||||
defer { isWorking = false; operationTask = nil }
|
||||
do {
|
||||
try await Task.detached(priority: .utility) {
|
||||
try WorkbenchBackupIntegrity.verify(url)
|
||||
}.value
|
||||
status = "Verified SHA-256: \(url.lastPathComponent)"
|
||||
progress = 1
|
||||
} catch {
|
||||
status = "Verification failed: \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var selectedProfile: ConnectionProfile? {
|
||||
model.selected
|
||||
@@ -3075,6 +3117,48 @@ struct WorkbenchDatabaseTransferView: View {
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox("Recent Backups") {
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
Text("Previously exported SQL backups. Files stay in their original locations; missing files cannot be verified or restored.")
|
||||
.font(.caption).foregroundStyle(.secondary)
|
||||
if recentBackups.isEmpty {
|
||||
Text("No DBSyn backups recorded yet.").foregroundStyle(.secondary)
|
||||
} else {
|
||||
Picker("Backup", selection: $selectedBackupPath) {
|
||||
Text("Select a backup").tag("")
|
||||
ForEach(recentBackups, id: \.self) { path in
|
||||
Text(URL(fileURLWithPath: path).lastPathComponent +
|
||||
(FileManager.default.fileExists(atPath: path) ? "" : " (missing)"))
|
||||
.tag(path)
|
||||
}
|
||||
}
|
||||
.labelsHidden()
|
||||
HStack {
|
||||
Button("Reveal in Finder") {
|
||||
if let url = selectedBackupURL {
|
||||
NSWorkspace.shared.activateFileViewerSelecting([url])
|
||||
}
|
||||
}.disabled(selectedBackupURL == nil)
|
||||
Button("Verify SHA-256") { verifyRecentBackup() }
|
||||
.disabled(selectedBackupURL == nil || isWorking)
|
||||
Button("Restore Selected…") {
|
||||
if let url = selectedBackupURL {
|
||||
selectedMode = 1
|
||||
pendingImportURL = url
|
||||
showingImportConfirmation = true
|
||||
}
|
||||
}.disabled(selectedBackupURL == nil || isWorking || database.isEmpty || selectedProfile == nil)
|
||||
Spacer()
|
||||
Button("Clear History") {
|
||||
recentBackups = []
|
||||
selectedBackupPath = ""
|
||||
UserDefaults.standard.removeObject(forKey: "DBSyn.recentBackups.v1")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox("Progress") {
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
ProgressView(value: progress)
|
||||
@@ -3721,6 +3805,7 @@ struct WorkbenchDatabaseTransferView: View {
|
||||
)
|
||||
try manifest.write(for: url)
|
||||
lastBackupURL = url
|
||||
rememberBackup(url)
|
||||
progress = 1
|
||||
status = "Export complete and SHA-256 verified: \(tables.count) tables, \(views.count) views, \(transferredRows.formatted()) rows"
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user