Major update for stability
This commit is contained in:
@@ -10,8 +10,7 @@ struct SettingsView: View {
|
||||
@AppStorage("backgroundSchedulesEnabled") private var backgroundSchedulesEnabled = true
|
||||
@AppStorage("fileWatchingEnabled") private var fileWatchingEnabled = true
|
||||
@AppStorage("defaultWatchDebounceSeconds") private var defaultWatchDebounceSeconds = 3
|
||||
@State private var defaultPassword = ""
|
||||
@State private var passwordSaved = false
|
||||
@AppStorage("historyRetentionDays") private var historyRetentionDays = 90
|
||||
@State private var launchAtLogin = false
|
||||
@State private var launchError: String?
|
||||
|
||||
@@ -30,18 +29,9 @@ struct SettingsView: View {
|
||||
}
|
||||
}
|
||||
|
||||
SecureField("Default password", text: $defaultPassword)
|
||||
HStack {
|
||||
Text("Stored securely in the macOS Keychain, never in SwiftData or UserDefaults.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
Spacer()
|
||||
Button(passwordSaved ? "Saved" : "Save Password") {
|
||||
KeychainStore.set(defaultPassword, for: "defaultSSHPassword")
|
||||
passwordSaved = true
|
||||
}
|
||||
.disabled(defaultPassword.isEmpty)
|
||||
}
|
||||
Label("Authentication uses an SSH private key or your macOS SSH agent. Passwords are intentionally not stored or passed on the command line.", systemImage: "lock.shield")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Section("New Jobs") {
|
||||
@@ -71,6 +61,13 @@ struct SettingsView: View {
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Section("History & Privacy") {
|
||||
Stepper("Keep run history for \(historyRetentionDays) days", value: $historyRetentionDays, in: 7...3650, step: 7)
|
||||
Text("Run output is sanitised, ANSI control sequences are removed, and individual stdout/stderr logs are capped at approximately 2 MB before storage.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Section("File Watching") {
|
||||
Toggle("Watch enabled jobs for changes", isOn: $fileWatchingEnabled)
|
||||
Stepper("Default debounce: \(defaultWatchDebounceSeconds) seconds", value: $defaultWatchDebounceSeconds, in: 1...60)
|
||||
@@ -91,7 +88,16 @@ struct SettingsView: View {
|
||||
Form {
|
||||
Section("Rsync") {
|
||||
LabeledContent("Detected executable", value: RsyncLocator.locate())
|
||||
Text("Rsync Manager prefers Homebrew rsync, then /usr/local/bin/rsync, and finally the version supplied with macOS.")
|
||||
LabeledContent("Executable validation", value: RsyncLocator.isTrustedExecutableCandidate(RsyncLocator.locate()) ? "Passed" : "Failed")
|
||||
Text("Only executable regular-file rsync candidates are accepted. Symlinks are resolved before validation.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
Section("Security") {
|
||||
LabeledContent("SSH mode", value: "Batch / key or agent")
|
||||
LabeledContent("Host-key verification", value: "System default")
|
||||
Text("SSH connections use BatchMode, connection timeouts and keepalive limits. Rsync Manager never disables SSH host-key verification.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
@@ -107,11 +113,9 @@ struct SettingsView: View {
|
||||
}
|
||||
.frame(width: 650, height: 455)
|
||||
.onAppear {
|
||||
defaultPassword = KeychainStore.string(for: "defaultSSHPassword")
|
||||
passwordSaved = !defaultPassword.isEmpty
|
||||
KeychainStore.delete("defaultSSHPassword")
|
||||
launchAtLogin = SMAppService.mainApp.status == .enabled
|
||||
}
|
||||
.onChange(of: defaultPassword) { _, _ in passwordSaved = false }
|
||||
.onChange(of: backgroundSchedulesEnabled) { _, _ in automation.refreshConfiguration() }
|
||||
.onChange(of: fileWatchingEnabled) { _, _ in automation.refreshConfiguration() }
|
||||
.alert("Launch at Login", isPresented: Binding(
|
||||
|
||||
Reference in New Issue
Block a user