ui(macos): make master discovery selectable
This commit is contained in:
@@ -151,7 +151,7 @@ struct GeneralSettings: View {
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
|
||||
}
|
||||
|
||||
MasterDiscoveryInlineList(discovery: self.masterDiscovery) { master in
|
||||
MasterDiscoveryInlineList(discovery: self.masterDiscovery, currentTarget: self.state.remoteTarget) { master in
|
||||
self.applyDiscoveredMaster(master)
|
||||
}
|
||||
.padding(.leading, 58)
|
||||
|
||||
@@ -4,7 +4,9 @@ import SwiftUI
|
||||
// swiftlint:disable:next inclusive_language
|
||||
struct MasterDiscoveryInlineList: View {
|
||||
@ObservedObject var discovery: MasterDiscoveryModel
|
||||
var currentTarget: String?
|
||||
var onSelect: (MasterDiscoveryModel.DiscoveredMaster) -> Void
|
||||
@State private var hoveredMasterID: MasterDiscoveryModel.DiscoveredMaster.ID?
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
@@ -24,22 +26,54 @@ struct MasterDiscoveryInlineList: View {
|
||||
} else {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
ForEach(self.discovery.masters.prefix(6)) { master in
|
||||
let target = self.suggestedSSHTarget(master)
|
||||
let selected = target != nil && self.currentTarget?.trimmingCharacters(in: .whitespacesAndNewlines) == target
|
||||
|
||||
Button {
|
||||
self.onSelect(master)
|
||||
withAnimation(.spring(response: 0.25, dampingFraction: 0.9)) {
|
||||
self.onSelect(master)
|
||||
}
|
||||
} label: {
|
||||
HStack(spacing: 8) {
|
||||
Text(master.displayName)
|
||||
.lineLimit(1)
|
||||
Spacer()
|
||||
if let host = master.tailnetDns ?? master.lanHost {
|
||||
Text(host)
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
HStack(alignment: .center, spacing: 10) {
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(master.displayName)
|
||||
.font(.callout.weight(.semibold))
|
||||
.lineLimit(1)
|
||||
.truncationMode(.tail)
|
||||
if let target {
|
||||
Text(target)
|
||||
.font(.caption.monospaced())
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
.truncationMode(.middle)
|
||||
}
|
||||
}
|
||||
Spacer(minLength: 0)
|
||||
if selected {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundStyle(Color.accentColor)
|
||||
} else {
|
||||
Image(systemName: "arrow.right.circle")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 8)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 10, style: .continuous)
|
||||
.fill(self.rowBackground(selected: selected, hovered: self.hoveredMasterID == master.id)))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 10, style: .continuous)
|
||||
.strokeBorder(
|
||||
selected ? Color.accentColor.opacity(0.45) : Color.clear,
|
||||
lineWidth: 1))
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.onHover { hovering in
|
||||
self.hoveredMasterID = hovering ? master.id : (self.hoveredMasterID == master.id ? nil : self.hoveredMasterID)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(10)
|
||||
@@ -48,7 +82,24 @@ struct MasterDiscoveryInlineList: View {
|
||||
.fill(Color(NSColor.controlBackgroundColor)))
|
||||
}
|
||||
}
|
||||
.help("Discover Clawdis masters on your LAN")
|
||||
.help("Click a discovered master to fill the SSH target.")
|
||||
}
|
||||
|
||||
private func suggestedSSHTarget(_ master: MasterDiscoveryModel.DiscoveredMaster) -> String? {
|
||||
let host = master.tailnetDns ?? master.lanHost
|
||||
guard let host else { return nil }
|
||||
let user = NSUserName()
|
||||
var target = "\(user)@\(host)"
|
||||
if master.sshPort != 22 {
|
||||
target += ":\(master.sshPort)"
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
private func rowBackground(selected: Bool, hovered: Bool) -> Color {
|
||||
if selected { return Color.accentColor.opacity(0.12) }
|
||||
if hovered { return Color.secondary.opacity(0.08) }
|
||||
return Color.clear
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ struct OnboardingView: View {
|
||||
.frame(width: fieldWidth)
|
||||
}
|
||||
|
||||
MasterDiscoveryInlineList(discovery: self.masterDiscovery) { master in
|
||||
MasterDiscoveryInlineList(discovery: self.masterDiscovery, currentTarget: self.state.remoteTarget) { master in
|
||||
self.applyDiscoveredMaster(master)
|
||||
}
|
||||
.frame(width: fieldWidth, alignment: .leading)
|
||||
|
||||
Reference in New Issue
Block a user