feat(app): add support for Ollama service integration

- Added Ollama endpoint to `Config.swift` and `install.py`.
- Updated `ServiceChecker` to handle Ollama status checks and errors.
- Enhanced `StatusView` with a sixth traffic light for Ollama.
This commit is contained in:
chrisfu 2025-12-30 23:56:24 -08:00
parent 10adb0e53a
commit 7140933f28
4 changed files with 26 additions and 8 deletions

View File

@ -3108,9 +3108,13 @@ svc.4.name=OpenBAO
svc.4.host={host}
svc.4.port=8200
svc.5.name=PostgreSQL
svc.5.name=Ollama
svc.5.host={host}
svc.5.port=5432
svc.5.port=11434
svc.6.name=PostgreSQL
svc.6.host={host}
svc.6.port=5432
"""
props_path.write_text(content)
print(f"Generated {props_path} for {env} environment")

View File

@ -104,6 +104,7 @@ final class Config {
ServiceEndpoint(name: "Prometheus", host: "localhost", port: 9090),
ServiceEndpoint(name: "Grafana", host: "localhost", port: 3000),
ServiceEndpoint(name: "OpenBAO", host: "localhost", port: 8200),
ServiceEndpoint(name: "Ollama", host: "localhost", port: 11434),
ServiceEndpoint(name: "PostgreSQL", host: "localhost", port: 5432)
]

View File

@ -17,6 +17,7 @@ final class ServiceChecker {
private(set) var prometheusReachable = false
private(set) var grafanaReachable = false
private(set) var openbaoReachable = false
private(set) var ollamaReachable = false
private(set) var postgresReachable = false
// Last error messages (for tooltips when red)
@ -24,6 +25,7 @@ final class ServiceChecker {
private(set) var prometheusError: String? = nil
private(set) var grafanaError: String? = nil
private(set) var openbaoError: String? = nil
private(set) var ollamaError: String? = nil
private(set) var postgresError: String? = nil
// Generic per-endpoint state so UI can query dynamically from Preferences
@ -85,7 +87,7 @@ final class ServiceChecker {
let group = DispatchGroup()
// clear previous errors before a new round (legacy fields)
k3dError = nil; prometheusError = nil; grafanaError = nil; openbaoError = nil; postgresError = nil
k3dError = nil; prometheusError = nil; grafanaError = nil; openbaoError = nil; ollamaError = nil; postgresError = nil
let cfg = Config.shared
// Iterate Services from Preferences
@ -127,6 +129,9 @@ final class ServiceChecker {
case "GRAFANA":
self.grafanaReachable = ok
self.grafanaError = err
case "OLLAMA":
self.ollamaReachable = ok
self.ollamaError = err
case "POSTGRESQL":
self.postgresReachable = ok
self.postgresError = err

View File

@ -6,6 +6,7 @@ final class StatusView: NSView {
private let light3 = TrafficLight()
private let light4 = TrafficLight()
private let light5 = TrafficLight()
private let light6 = TrafficLight()
private let marquee = MarqueeView()
private let maximizeButton: NSButton = {
let b = NSButton(title: "", target: nil, action: nil)
@ -42,7 +43,7 @@ final class StatusView: NSView {
wantsLayer = true
translatesAutoresizingMaskIntoConstraints = false
let stack = NSStackView(views: [light1, light2, light3, light4, light5, marquee, maximizeButton])
let stack = NSStackView(views: [light1, light2, light3, light4, light5, light6, marquee, maximizeButton])
stack.orientation = .horizontal
stack.alignment = .centerY
stack.distribution = .equalSpacing
@ -79,7 +80,7 @@ final class StatusView: NSView {
}
// Allow interaction with traffic lights for tooltips
for light in [light1, light2, light3, light4, light5] {
for light in [light1, light2, light3, light4, light5, light6] {
let pointInLight = convert(point, to: light)
if light.bounds.contains(pointInLight) {
return light
@ -126,13 +127,20 @@ final class StatusView: NSView {
light4.state = (state?.reachable ?? false) ? .green : .red
light4.toolTip = c.tooltipFor(name: s.name)
}
// Light 5: PostgreSQL
if let s = services.first(where: { $0.name.uppercased() == "POSTGRESQL" }) {
// Light 5: Ollama
if let s = services.first(where: { $0.name.uppercased() == "OLLAMA" }) {
let state = c.serviceStates[s.name]
light5.state = (state?.reachable ?? false) ? .green : .red
light5.toolTip = c.tooltipFor(name: s.name)
}
// Light 6: PostgreSQL
if let s = services.first(where: { $0.name.uppercased() == "POSTGRESQL" }) {
let state = c.serviceStates[s.name]
light6.state = (state?.reachable ?? false) ? .green : .red
light6.toolTip = c.tooltipFor(name: s.name)
}
// Update marquee text with status summary and ensure it scrolls
// For the scrolling status, use new contents: scroll the output of kubectl cnpg status | head -10