import Foundation import SwiftUI extension AppState { enum GatewayConfigField: String, CaseIterable { case mode = "gateway.mode" case remoteTransport = "gateway.remote.transport" case remoteUrl = "gateway.remote.url" case remoteTarget = "gateway.remote.sshTarget" case remoteIdentity = "gateway.remote.sshIdentity" case remoteHostKeyPolicy = "gateway.remote.sshHostKeyPolicy" case remoteToken = "gateway.remote.token" var remoteKey: String? { switch self { case .mode: nil case .remoteTransport: "transport" case .remoteUrl: "url" case .remoteTarget: "sshTarget" case .remoteIdentity: "sshIdentity" case .remoteHostKeyPolicy: "sshHostKeyPolicy" case .remoteToken: "token" } } var displayName: String { switch self { case .mode: String(localized: "Gateway location") case .remoteTransport: String(localized: "Transport") case .remoteUrl: String(localized: "Gateway URL") case .remoteTarget: String(localized: "SSH target") case .remoteIdentity: String(localized: "Identity file") case .remoteHostKeyPolicy: String(localized: "SSH host key policy") case .remoteToken: String(localized: "Gateway token") } } } struct GatewayConfigConflict: Equatable { let fields: [GatewayConfigField] let fieldNames: [String] let message: String } enum GatewayConfigValue: Equatable { case missing case json(Data) } struct GatewayConfigSnapshot { static let empty = GatewayConfigSnapshot(values: [:]) let values: [GatewayConfigField: GatewayConfigValue] subscript(field: GatewayConfigField) -> GatewayConfigValue { self.values[field] ?? .missing } } struct RemoteGatewayConfigDraft { var transport: RemoteTransport var remoteUrl: String var remoteHost: String? var remoteTarget: String var remoteIdentity: String var remoteToken: String var dirtyFields: Set } struct GatewayConfigSyncDraft { var connectionMode: ConnectionMode var remoteTransport: RemoteTransport var remoteTarget: String var remoteIdentity: String var remoteUrl: String var remoteToken: String var dirtyFields: Set } struct GatewaySelectionSnapshot: Equatable { let connectionMode: ConnectionMode let remoteTransport: RemoteTransport let remoteUrl: String let remoteTarget: String } } struct GatewayConfigConflictRecoveryView: View { @Bindable var state: AppState var body: some View { if let conflict = state.gatewayConfigConflict { HStack(alignment: .top, spacing: 10) { Image(systemName: "exclamationmark.triangle.fill") .foregroundStyle(.orange) .accessibilityHidden(true) VStack(alignment: .leading, spacing: 8) { Text(verbatim: conflict.message) .font(.footnote) .fixedSize(horizontal: false, vertical: true) HStack(spacing: 8) { Button("Use file version") { self.state.useFileGatewayConfigConflict() } .buttonStyle(.bordered) Button("Keep my edits") { self.state.keepGatewayConfigEdits() } .buttonStyle(.borderedProminent) } .controlSize(.small) } } .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal, 14) .padding(.vertical, 11) .background(.orange.opacity(0.08)) } } }