82 lines
2.6 KiB
Swift
82 lines
2.6 KiB
Swift
import AppKit
|
|
import SwiftUI
|
|
|
|
struct OAuthSetupView: View {
|
|
@State private var tokenManager = TokenManager.shared
|
|
@State private var statusMessage: String?
|
|
|
|
var body: some View {
|
|
VStack(spacing: 16) {
|
|
Image(systemName: "link.circle")
|
|
.font(.system(size: 40))
|
|
.foregroundStyle(.blue)
|
|
|
|
Text("Connect Feishu")
|
|
.font(.headline)
|
|
|
|
Text("Authorize Bugger to read bugs assigned to you from your Feishu Bitable.")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
.multilineTextAlignment(.center)
|
|
|
|
if tokenManager.authorizeURL == nil {
|
|
Text("Set FEISHU_APP_ID and FEISHU_APP_SECRET in the Xcode build settings before connecting.")
|
|
.font(.caption)
|
|
.foregroundStyle(.orange)
|
|
.multilineTextAlignment(.center)
|
|
} else {
|
|
Button("Connect Feishu") {
|
|
connectFeishu()
|
|
}
|
|
.buttonStyle(.borderedProminent)
|
|
}
|
|
|
|
if case .authenticating = tokenManager.state {
|
|
ProgressView("Completing sign-in...")
|
|
}
|
|
|
|
if case .error(let message) = tokenManager.state {
|
|
Text(message)
|
|
.font(.caption)
|
|
.foregroundStyle(.red)
|
|
.multilineTextAlignment(.center)
|
|
}
|
|
|
|
if let statusMessage {
|
|
Text(statusMessage)
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
.padding(24)
|
|
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
}
|
|
|
|
private func connectFeishu() {
|
|
Task {
|
|
let server = LocalOAuthServer()
|
|
tokenManager.authService.redirectURI = server.redirectURI
|
|
|
|
guard let url = tokenManager.authorizeURL else {
|
|
statusMessage = "Missing credentials. Check FEISHU_APP_ID."
|
|
return
|
|
}
|
|
|
|
statusMessage = "Complete authorization in your browser."
|
|
NSWorkspace.shared.open(url)
|
|
|
|
do {
|
|
let code = try await server.receiveCode()
|
|
statusMessage = "Completing sign-in..."
|
|
try await tokenManager.handleCallback(code: code)
|
|
await PollerService.shared.startIfConfigured()
|
|
await PollerService.shared.fetchNow()
|
|
} catch {
|
|
await MainActor.run {
|
|
tokenManager.setError(error.localizedDescription)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|