Fix Xcode build phase permissions and increase General tab height

- Add tty-fwd-universal to inputPaths to fix "Operation not permitted" error
- Set alwaysOutOfDate flag to ensure build phase runs when needed
- Increase General settings tab height from 300 to 400 pixels
- Fix ngrok alert handling to use SwiftUI alerts instead of NSAlert
This commit is contained in:
Peter Steinberger 2025-06-16 06:35:04 +02:00
parent 347d79914f
commit 6cbe2b8cbb
2 changed files with 47 additions and 19 deletions

View file

@ -264,6 +264,7 @@
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
A189466CB0AD49BEBE16B954 /* Build tty-fwd Universal Binary */ = { A189466CB0AD49BEBE16B954 /* Build tty-fwd Universal Binary */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
@ -276,6 +277,7 @@
"$(SRCROOT)/tty-fwd/src/utils.rs", "$(SRCROOT)/tty-fwd/src/utils.rs",
"$(SRCROOT)/tty-fwd/Cargo.toml", "$(SRCROOT)/tty-fwd/Cargo.toml",
"$(SRCROOT)/tty-fwd/build-universal.sh", "$(SRCROOT)/tty-fwd/build-universal.sh",
"$(SRCROOT)/tty-fwd/target/release/tty-fwd-universal",
); );
name = "Build tty-fwd Universal Binary"; name = "Build tty-fwd Universal Binary";
outputFileListPaths = ( outputFileListPaths = (

View file

@ -39,7 +39,7 @@ struct SettingsView: View {
/// Define ideal sizes for each tab /// Define ideal sizes for each tab
private let tabSizes: [SettingsTab: CGSize] = [ private let tabSizes: [SettingsTab: CGSize] = [
.general: CGSize(width: 500, height: 300), .general: CGSize(width: 500, height: 400),
.advanced: CGSize(width: 500, height: 500), .advanced: CGSize(width: 500, height: 500),
.debug: CGSize(width: 600, height: 650), .debug: CGSize(width: 600, height: 650),
.about: CGSize(width: 500, height: 550) .about: CGSize(width: 500, height: 550)
@ -259,6 +259,10 @@ struct AdvancedSettingsView: View {
@State private var ngrokStatus: NgrokTunnelStatus? @State private var ngrokStatus: NgrokTunnelStatus?
@State private var isStartingNgrok = false @State private var isStartingNgrok = false
@State private var ngrokError: String? @State private var ngrokError: String?
@State private var showingAuthTokenAlert = false
@State private var showingKeychainAlert = false
@State private var showingServerErrorAlert = false
@State private var serverErrorMessage = ""
private let ngrokService = NgrokService.shared private let ngrokService = NgrokService.shared
@ -296,7 +300,13 @@ struct AdvancedSettingsView: View {
.onChange(of: ngrokEnabled) { oldValue, newValue in .onChange(of: ngrokEnabled) { oldValue, newValue in
print("ngrok toggle changed from \(oldValue) to \(newValue)") print("ngrok toggle changed from \(oldValue) to \(newValue)")
if newValue { if newValue {
checkAndStartNgrok() // Add a small delay to ensure auth token is saved to keychain
Task {
try? await Task.sleep(for: .milliseconds(100))
await MainActor.run {
checkAndStartNgrok()
}
}
} else { } else {
stopNgrok() stopNgrok()
// Clear error only when user manually turns off the toggle // Clear error only when user manually turns off the toggle
@ -419,6 +429,21 @@ struct AdvancedSettingsView: View {
ngrokAuthToken = ngrokService.authToken ?? "" ngrokAuthToken = ngrokService.authToken ?? ""
print("AdvancedSettingsView appeared - auth token present: \(!ngrokAuthToken.isEmpty)") print("AdvancedSettingsView appeared - auth token present: \(!ngrokAuthToken.isEmpty)")
} }
.alert("ngrok Auth Token Required", isPresented: $showingAuthTokenAlert) {
Button("OK") { }
} message: {
Text("Please enter your ngrok auth token before enabling the tunnel. You can get a free auth token at ngrok.com")
}
.alert("Keychain Access Error", isPresented: $showingKeychainAlert) {
Button("OK") { }
} message: {
Text("Failed to save the auth token to the keychain. Please check your keychain permissions and try again.")
}
.alert("Failed to Restart Server", isPresented: $showingServerErrorAlert) {
Button("OK") { }
} message: {
Text(serverErrorMessage)
}
} }
private func restartServerWithNewPort(_ port: Int) { private func restartServerWithNewPort(_ port: Int) {
@ -445,11 +470,8 @@ struct AdvancedSettingsView: View {
print("Failed to restart server on port \(port): \(error)") print("Failed to restart server on port \(port): \(error)")
// Show error alert // Show error alert
await MainActor.run { await MainActor.run {
let alert = NSAlert() serverErrorMessage = "Could not start server on port \(port): \(error.localizedDescription)"
alert.messageText = "Failed to Restart Server" showingServerErrorAlert = true
alert.informativeText = "Could not start server on port \(port): \(error.localizedDescription)"
alert.alertStyle = .critical
alert.runModal()
} }
} }
} }
@ -457,20 +479,24 @@ struct AdvancedSettingsView: View {
private func checkAndStartNgrok() { private func checkAndStartNgrok() {
print("checkAndStartNgrok called") print("checkAndStartNgrok called")
guard !ngrokService.authToken.isNilOrEmpty else { print("Local auth token state: '\(ngrokAuthToken)' (length: \(ngrokAuthToken.count))")
print("No auth token found") print("Service auth token: '\(ngrokService.authToken ?? "nil")' (present: \(ngrokService.authToken != nil))")
// First check the local state variable
guard !ngrokAuthToken.isEmpty else {
print("No auth token in local state")
ngrokError = "Please enter your ngrok auth token first" ngrokError = "Please enter your ngrok auth token first"
ngrokEnabled = false ngrokEnabled = false
showingAuthTokenAlert = true
// Show alert dialog return
Task { @MainActor in }
let alert = NSAlert()
alert.messageText = "ngrok Auth Token Required" // Then verify it's saved in the service
alert.informativeText = "Please enter your ngrok auth token before enabling the tunnel. You can get a free auth token at ngrok.com" guard !ngrokService.authToken.isNilOrEmpty else {
alert.alertStyle = .warning print("Auth token not saved in keychain")
alert.addButton(withTitle: "OK") ngrokError = "Failed to save auth token. Please try again."
alert.runModal() ngrokEnabled = false
} showingKeychainAlert = true
return return
} }