updates
This commit is contained in:
@@ -2,43 +2,100 @@ import SwiftUI
|
||||
|
||||
struct SettingsView: View {
|
||||
@ObservedObject var monitor: ServerMonitor
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@AppStorage("server.host") private var host = "192.168.1.2"
|
||||
@AppStorage("server.user") private var user = "mag"
|
||||
@AppStorage("server.port") private var port = "22"
|
||||
@AppStorage("server.keyFile") private var keyFile = ""
|
||||
@AppStorage("monitor.intervalMinutes") private var intervalMinutes = 5
|
||||
@AppStorage("monitor.notifications") private var notifications = true
|
||||
@State private var draft = ServerProfile()
|
||||
@State private var editingID: UUID?
|
||||
@State private var validation = ""
|
||||
@State private var interval = 5
|
||||
@State private var notifications = true
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
TextField("Host", text: $host)
|
||||
TextField("SSH user", text: $user)
|
||||
TextField("SSH port", text: $port)
|
||||
TextField("SSH key path (optional)", text: $keyFile)
|
||||
.help("Leave blank to use your SSH agent or ~/.ssh/config")
|
||||
Picker("Refresh interval", selection: $intervalMinutes) {
|
||||
Text("1 minute").tag(1)
|
||||
Text("5 minutes").tag(5)
|
||||
Text("10 minutes").tag(10)
|
||||
Text("15 minutes").tag(15)
|
||||
Text("30 minutes").tag(30)
|
||||
}
|
||||
Toggle("Notify when server becomes unhealthy", isOn: $notifications)
|
||||
HStack {
|
||||
Button("Close") {
|
||||
dismiss()
|
||||
HStack(spacing: 0) {
|
||||
VStack(spacing: 8) {
|
||||
Text("Servers").font(.headline).frame(maxWidth: .infinity, alignment: .leading)
|
||||
List(selection: $editingID) {
|
||||
ForEach(monitor.servers) { server in
|
||||
HStack {
|
||||
Image(systemName: "server.rack")
|
||||
Text(server.name)
|
||||
if !server.enabled { Image(systemName: "pause.circle") }
|
||||
}.tag(server.id)
|
||||
}
|
||||
.onMove { monitor.move(from: $0, to: $1) }
|
||||
}
|
||||
Spacer()
|
||||
Button("Apply and Refresh") {
|
||||
monitor.configureTimer()
|
||||
Task { await monitor.refresh() }
|
||||
HStack {
|
||||
Button { newProfile() } label: { Image(systemName: "plus") }
|
||||
Button { if let id = editingID { monitor.remove(id); editingID = monitor.servers.first?.id } } label: { Image(systemName: "minus") }
|
||||
.disabled(editingID == nil)
|
||||
Spacer()
|
||||
}
|
||||
.buttonStyle(.borderless)
|
||||
}
|
||||
.frame(width: 205)
|
||||
.padding()
|
||||
Divider()
|
||||
VStack(alignment: .leading, spacing: 14) {
|
||||
Text(editingID == nil ? "Add a server" : "Connection details")
|
||||
.font(.title3.bold())
|
||||
Form {
|
||||
TextField("Display name", text: $draft.name)
|
||||
TextField("Host / SSH alias", text: $draft.host)
|
||||
TextField("SSH username", text: $draft.user)
|
||||
TextField("SSH port", text: $draft.port)
|
||||
TextField("SSH key path (optional)", text: $draft.keyFile)
|
||||
TextField("Remote health command", text: $draft.remoteCommand)
|
||||
Toggle("Monitoring enabled", isOn: $draft.enabled)
|
||||
}
|
||||
Text("Use the Pegasus adapter for Pegasus, or install server/remote-health-json on other Linux servers. SSH must work without interactive prompts. SSH known_hosts is enforced.")
|
||||
.font(.caption).foregroundStyle(.secondary)
|
||||
if !validation.isEmpty { Text(validation).foregroundStyle(.red).font(.caption) }
|
||||
HStack {
|
||||
Button("New Server") { newProfile() }
|
||||
Spacer()
|
||||
Button("Save and Refresh") { save() }
|
||||
.buttonStyle(.borderedProminent)
|
||||
}
|
||||
Divider()
|
||||
HStack {
|
||||
Picker("Refresh every", selection: $interval) {
|
||||
ForEach([1, 5, 10, 15, 30], id: \.self) { value in
|
||||
Text("\(value) min").tag(value)
|
||||
}
|
||||
}
|
||||
Toggle("Notifications", isOn: $notifications)
|
||||
}
|
||||
}
|
||||
Text("SSH must authenticate without prompts. Server requires /usr/local/bin/pegasus-health-json accessible via sudo -n. Host keys are verified using your existing SSH known_hosts file.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(20)
|
||||
}
|
||||
.padding(20)
|
||||
.onAppear {
|
||||
interval = monitor.intervalMinutes
|
||||
notifications = monitor.notifications
|
||||
editingID = monitor.selectedID
|
||||
if let selected = monitor.selected { draft = selected }
|
||||
}
|
||||
.onChange(of: editingID) { _, newValue in
|
||||
if let id = newValue, let server = monitor.servers.first(where: { $0.id == id }) { draft = server }
|
||||
validation = ""
|
||||
}
|
||||
.onChange(of: interval) { _, value in monitor.intervalMinutes = value }
|
||||
.onChange(of: notifications) { _, value in monitor.notifications = value }
|
||||
}
|
||||
|
||||
private func newProfile() {
|
||||
editingID = nil
|
||||
draft = ServerProfile()
|
||||
validation = ""
|
||||
}
|
||||
private func save() {
|
||||
guard !draft.name.trimmingCharacters(in: .whitespaces).isEmpty,
|
||||
!draft.host.trimmingCharacters(in: .whitespaces).isEmpty,
|
||||
!draft.user.trimmingCharacters(in: .whitespaces).isEmpty,
|
||||
let port = Int(draft.port), (1...65535).contains(port),
|
||||
!draft.remoteCommand.trimmingCharacters(in: .whitespaces).isEmpty else {
|
||||
validation = "Enter a name, host, SSH username, valid port and remote command."
|
||||
return
|
||||
}
|
||||
monitor.save(draft)
|
||||
editingID = draft.id
|
||||
validation = ""
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user