feat: add alert grace period controls
This commit is contained in:
@@ -31,6 +31,7 @@ struct MainView: View {
|
||||
@AppStorage("refreshInterval") private var refreshInterval: Int = 60
|
||||
@AppStorage("enableStatusNotifications") private var enableStatusNotifications: Bool = true
|
||||
@AppStorage("enableAlertNotifications") private var enableAlertNotifications: Bool = true
|
||||
@AppStorage("alertGracePeriod") private var alertGracePeriod: Int = 30
|
||||
@State private var refreshTimer: Timer.TimerPublisher?
|
||||
@State private var refreshSubscription: AnyCancellable?
|
||||
@State private var pingTimer: Timer?
|
||||
@@ -40,6 +41,8 @@ struct MainView: View {
|
||||
@State private var lastRefreshInterval: Int?
|
||||
@State private var lastMetricPrune: Date?
|
||||
@State private var previousServiceStates: [String: String] = [:]
|
||||
@State private var serviceFailureStartedAt: [String: Date] = [:]
|
||||
@State private var serviceOfflineAlerted: [String: Bool] = [:]
|
||||
private let serverOrderKey = MainView.serverOrderKeyStatic
|
||||
private let storedGroupsKey = MainView.storedGroupsKeyStatic
|
||||
@Environment(\.modelContext) private var modelContext
|
||||
@@ -242,9 +245,10 @@ struct MainView: View {
|
||||
private func sidebarRow(for server: Server) -> some View {
|
||||
HStack {
|
||||
Image(systemName: "dot.circle.fill")
|
||||
.foregroundColor(server.pingable ? .green : .red)
|
||||
.foregroundColor(sidebarStatusColor(for: server))
|
||||
Text(server.hostname)
|
||||
}
|
||||
.help(sidebarStatusTooltip(for: server))
|
||||
.tag(server.id)
|
||||
.contextMenu {
|
||||
Button("Edit") {
|
||||
@@ -259,6 +263,23 @@ struct MainView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func sidebarStatusColor(for server: Server) -> Color {
|
||||
if !server.pingable {
|
||||
return .red
|
||||
}
|
||||
if server.info?.rebootRequired == true {
|
||||
return .yellow
|
||||
}
|
||||
return .green
|
||||
}
|
||||
|
||||
private func sidebarStatusTooltip(for server: Server) -> String {
|
||||
if !server.pingable {
|
||||
return "This host is offline."
|
||||
}
|
||||
return server.info?.statusTooltip ?? "This host is online."
|
||||
}
|
||||
|
||||
private func groupHeader(for group: ServerGroup) -> some View {
|
||||
let activePlacement = groupDropIndicator?.groupID == group.id ? groupDropIndicator?.placement : nil
|
||||
|
||||
@@ -616,17 +637,45 @@ struct MainView: View {
|
||||
for port in ports {
|
||||
let key = "\(hostname)-\(port.id)"
|
||||
let previousStatus = previousServiceStates[key]
|
||||
let currentStatus = port.status
|
||||
|
||||
previousServiceStates[key] = currentStatus
|
||||
let currentStatus = port.status.lowercased()
|
||||
let now = Date()
|
||||
|
||||
if let previousStatus, previousStatus != currentStatus {
|
||||
if currentStatus == "offline" && enableStatusNotifications {
|
||||
sendServiceNotification(service: port.service, hostname: hostname, status: "offline")
|
||||
} else if currentStatus == "online" && previousStatus == "offline" && enableStatusNotifications {
|
||||
sendServiceNotification(service: port.service, hostname: hostname, status: "online")
|
||||
if currentStatus == "offline" {
|
||||
serviceFailureStartedAt[key] = now
|
||||
serviceOfflineAlerted[key] = false
|
||||
} else if currentStatus == "online" {
|
||||
let hadOfflineAlert = serviceOfflineAlerted[key] == true
|
||||
serviceFailureStartedAt.removeValue(forKey: key)
|
||||
serviceOfflineAlerted.removeValue(forKey: key)
|
||||
if hadOfflineAlert && enableStatusNotifications {
|
||||
sendServiceNotification(service: port.service, hostname: hostname, status: "online")
|
||||
}
|
||||
}
|
||||
} else if previousStatus == nil {
|
||||
if currentStatus == "offline" {
|
||||
serviceFailureStartedAt[key] = now
|
||||
serviceOfflineAlerted[key] = false
|
||||
} else if currentStatus == "online" {
|
||||
serviceFailureStartedAt.removeValue(forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
if currentStatus == "offline" {
|
||||
let startedAt = serviceFailureStartedAt[key] ?? now
|
||||
if serviceFailureStartedAt[key] == nil {
|
||||
serviceFailureStartedAt[key] = startedAt
|
||||
}
|
||||
|
||||
if serviceOfflineAlerted[key] != true,
|
||||
enableAlertNotifications,
|
||||
now.timeIntervalSince(startedAt) >= TimeInterval(alertGracePeriod) {
|
||||
sendServiceNotification(service: port.service, hostname: hostname, status: "offline")
|
||||
serviceOfflineAlerted[key] = true
|
||||
}
|
||||
}
|
||||
|
||||
previousServiceStates[key] = currentStatus
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user