mirror of
https://github.com/neon443/ShhShell.git
synced 2026-03-11 13:26:16 +00:00
improve ui on keydetailview
add set(keypair, onHost) to set a keypair on host remove getkeys it always returns [] add delete button to remove rsa from keytype rename symbolpreview ->hostsymbolpreview
This commit is contained in:
@@ -63,7 +63,7 @@
|
|||||||
A9D8192F2E0F1BEE00442D38 /* ThemePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */; };
|
A9D8192F2E0F1BEE00442D38 /* ThemePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */; };
|
||||||
A9D819312E102D8700442D38 /* HostkeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819302E102D8700442D38 /* HostkeysView.swift */; };
|
A9D819312E102D8700442D38 /* HostkeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819302E102D8700442D38 /* HostkeysView.swift */; };
|
||||||
A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97702E0D30ED00142DDC /* HostSymbol.swift */; };
|
A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97702E0D30ED00142DDC /* HostSymbol.swift */; };
|
||||||
A9DA97732E0D40C100142DDC /* SymbolPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97722E0D40C100142DDC /* SymbolPreview.swift */; };
|
A9DA97732E0D40C100142DDC /* HostSymbolPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97722E0D40C100142DDC /* HostSymbolPreview.swift */; };
|
||||||
A9FD37552E143D23005319A8 /* SecKeyConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FD37542E143D23005319A8 /* SecKeyConvertible.swift */; };
|
A9FD37552E143D23005319A8 /* SecKeyConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FD37542E143D23005319A8 /* SecKeyConvertible.swift */; };
|
||||||
A9FD37572E143D5A005319A8 /* SecKeyStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FD37562E143D5A005319A8 /* SecKeyStore.swift */; };
|
A9FD37572E143D5A005319A8 /* SecKeyStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FD37562E143D5A005319A8 /* SecKeyStore.swift */; };
|
||||||
A9FD37592E143D74005319A8 /* GenericPasswordConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FD37582E143D74005319A8 /* GenericPasswordConvertible.swift */; };
|
A9FD37592E143D74005319A8 /* GenericPasswordConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FD37582E143D74005319A8 /* GenericPasswordConvertible.swift */; };
|
||||||
@@ -165,7 +165,7 @@
|
|||||||
A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemePreview.swift; sourceTree = "<group>"; };
|
A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemePreview.swift; sourceTree = "<group>"; };
|
||||||
A9D819302E102D8700442D38 /* HostkeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostkeysView.swift; sourceTree = "<group>"; };
|
A9D819302E102D8700442D38 /* HostkeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostkeysView.swift; sourceTree = "<group>"; };
|
||||||
A9DA97702E0D30ED00142DDC /* HostSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbol.swift; sourceTree = "<group>"; };
|
A9DA97702E0D30ED00142DDC /* HostSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbol.swift; sourceTree = "<group>"; };
|
||||||
A9DA97722E0D40C100142DDC /* SymbolPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymbolPreview.swift; sourceTree = "<group>"; };
|
A9DA97722E0D40C100142DDC /* HostSymbolPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbolPreview.swift; sourceTree = "<group>"; };
|
||||||
A9FD37542E143D23005319A8 /* SecKeyConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecKeyConvertible.swift; sourceTree = "<group>"; };
|
A9FD37542E143D23005319A8 /* SecKeyConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecKeyConvertible.swift; sourceTree = "<group>"; };
|
||||||
A9FD37562E143D5A005319A8 /* SecKeyStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecKeyStore.swift; sourceTree = "<group>"; };
|
A9FD37562E143D5A005319A8 /* SecKeyStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecKeyStore.swift; sourceTree = "<group>"; };
|
||||||
A9FD37582E143D74005319A8 /* GenericPasswordConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericPasswordConvertible.swift; sourceTree = "<group>"; };
|
A9FD37582E143D74005319A8 /* GenericPasswordConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericPasswordConvertible.swift; sourceTree = "<group>"; };
|
||||||
@@ -349,6 +349,7 @@
|
|||||||
A93143C52DF61FE300FCD5DB /* ViewModifiers.swift */,
|
A93143C52DF61FE300FCD5DB /* ViewModifiers.swift */,
|
||||||
A9B15A992E0ABA0400F66E02 /* DialogView.swift */,
|
A9B15A992E0ABA0400F66E02 /* DialogView.swift */,
|
||||||
A96C90A02E12B87900724253 /* TextBox.swift */,
|
A96C90A02E12B87900724253 /* TextBox.swift */,
|
||||||
|
A9DA97722E0D40C100142DDC /* HostSymbolPreview.swift */,
|
||||||
);
|
);
|
||||||
path = Misc;
|
path = Misc;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -379,7 +380,6 @@
|
|||||||
A93143BF2DF61B3200FCD5DB /* Host.swift */,
|
A93143BF2DF61B3200FCD5DB /* Host.swift */,
|
||||||
A98554602E058433009051BD /* HostsManager.swift */,
|
A98554602E058433009051BD /* HostsManager.swift */,
|
||||||
A9DA97702E0D30ED00142DDC /* HostSymbol.swift */,
|
A9DA97702E0D30ED00142DDC /* HostSymbol.swift */,
|
||||||
A9DA97722E0D40C100142DDC /* SymbolPreview.swift */,
|
|
||||||
);
|
);
|
||||||
path = Host;
|
path = Host;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -601,7 +601,7 @@
|
|||||||
A93143C62DF61FE300FCD5DB /* ViewModifiers.swift in Sources */,
|
A93143C62DF61FE300FCD5DB /* ViewModifiers.swift in Sources */,
|
||||||
A98554632E0587DF009051BD /* HostsView.swift in Sources */,
|
A98554632E0587DF009051BD /* HostsView.swift in Sources */,
|
||||||
A96C6A8A2E0C0B1100F377FE /* SSHState.swift in Sources */,
|
A96C6A8A2E0C0B1100F377FE /* SSHState.swift in Sources */,
|
||||||
A9DA97732E0D40C100142DDC /* SymbolPreview.swift in Sources */,
|
A9DA97732E0D40C100142DDC /* HostSymbolPreview.swift in Sources */,
|
||||||
A96BE6A62E113DB000C0FEE9 /* ColorCodable.swift in Sources */,
|
A96BE6A62E113DB000C0FEE9 /* ColorCodable.swift in Sources */,
|
||||||
A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */,
|
A92538C82DEE0742007E0A18 /* ContentView.swift in Sources */,
|
||||||
A96BE6A42E113D9400C0FEE9 /* ThemeCodable.swift in Sources */,
|
A96BE6A42E113D9400C0FEE9 /* ThemeCodable.swift in Sources */,
|
||||||
|
|||||||
@@ -169,12 +169,10 @@ class HostsManager: ObservableObject, @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getKeys() -> [Keypair] {
|
func set(keypair: Keypair, onHost: Host) {
|
||||||
var result: [Keypair] = []
|
guard let index = hosts.firstIndex(where: { $0.id == onHost.id }) else { return }
|
||||||
for host in hosts {
|
hosts[index].privateKeyID = keypair.id
|
||||||
guard let keyID = host.privateKeyID else { continue }
|
saveHosts()
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHostsUsingKeys(_ keys: [Keypair]) -> [Host] {
|
func getHostsUsingKeys(_ keys: [Keypair]) -> [Host] {
|
||||||
|
|||||||
@@ -140,7 +140,8 @@ class KeyManager: ObservableObject {
|
|||||||
|
|
||||||
func importKey(type: KeyType, priv: String, name: String) {
|
func importKey(type: KeyType, priv: String, name: String) {
|
||||||
if type == .ed25519 {
|
if type == .ed25519 {
|
||||||
saveToKeychain(KeyManager.importSSHPrivkey(priv: priv))
|
guard let importedKeypair = KeyManager.importSSHPrivkey(priv: priv) else { return }
|
||||||
|
saveToKeychain(importedKeypair)
|
||||||
saveKeypairs()
|
saveKeypairs()
|
||||||
} else { fatalError() }
|
} else { fatalError() }
|
||||||
}
|
}
|
||||||
@@ -156,8 +157,6 @@ class KeyManager: ObservableObject {
|
|||||||
)
|
)
|
||||||
saveToKeychain(keypair)
|
saveToKeychain(keypair)
|
||||||
saveKeypairs()
|
saveKeypairs()
|
||||||
case .rsa:
|
|
||||||
fatalError("unimplemented")
|
|
||||||
}
|
}
|
||||||
loadKeypairs()
|
loadKeypairs()
|
||||||
}
|
}
|
||||||
@@ -187,7 +186,8 @@ class KeyManager: ObservableObject {
|
|||||||
return Data(pubkeyline.utf8)
|
return Data(pubkeyline.utf8)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func importSSHPrivkey(priv: String) -> Keypair {
|
static func importSSHPrivkey(priv: String) -> Keypair? {
|
||||||
|
guard !priv.isEmpty else { return nil }
|
||||||
var split = priv.replacingOccurrences(of: "-----BEGIN OPENSSH PRIVATE KEY-----\n", with: "")
|
var split = priv.replacingOccurrences(of: "-----BEGIN OPENSSH PRIVATE KEY-----\n", with: "")
|
||||||
split = split.replacingOccurrences(of: "-----BEGIN OPENSSH PRIVATE KEY-----", with: "")
|
split = split.replacingOccurrences(of: "-----BEGIN OPENSSH PRIVATE KEY-----", with: "")
|
||||||
split = split.replacingOccurrences(of: "\n-----END OPENSSH PRIVATE KEY-----\n", with: "")
|
split = split.replacingOccurrences(of: "\n-----END OPENSSH PRIVATE KEY-----\n", with: "")
|
||||||
|
|||||||
@@ -9,14 +9,11 @@ import Foundation
|
|||||||
|
|
||||||
enum KeyType: Codable, Equatable, Hashable, CustomStringConvertible, CaseIterable {
|
enum KeyType: Codable, Equatable, Hashable, CustomStringConvertible, CaseIterable {
|
||||||
case ed25519
|
case ed25519
|
||||||
case rsa
|
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .ed25519:
|
case .ed25519:
|
||||||
return "Ed25519"
|
return "Ed25519"
|
||||||
case .rsa:
|
|
||||||
return "RSA"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ struct ConnectionView: View {
|
|||||||
RoundedRectangle(cornerRadius: 10)
|
RoundedRectangle(cornerRadius: 10)
|
||||||
.fill(.gray.opacity(0.5))
|
.fill(.gray.opacity(0.5))
|
||||||
}
|
}
|
||||||
SymbolPreview(symbol: symbol, label: handler.host.label)
|
HostSymbolPreview(symbol: symbol, label: handler.host.label)
|
||||||
.padding(5)
|
.padding(5)
|
||||||
}
|
}
|
||||||
.frame(width: 60, height: 60)
|
.frame(width: 60, height: 60)
|
||||||
@@ -47,7 +47,7 @@ struct ConnectionView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
SymbolPreview(symbol: handler.host.symbol, label: handler.host.label)
|
HostSymbolPreview(symbol: handler.host.symbol, label: handler.host.label)
|
||||||
.id(handler.host)
|
.id(handler.host)
|
||||||
.frame(width: 60, height: 60)
|
.frame(width: 60, height: 60)
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ struct HostsView: View {
|
|||||||
keyManager: keyManager
|
keyManager: keyManager
|
||||||
)
|
)
|
||||||
} label: {
|
} label: {
|
||||||
SymbolPreview(symbol: host.symbol, label: host.label)
|
HostSymbolPreview(symbol: host.symbol, label: host.label)
|
||||||
.frame(width: 40, height: 40)
|
.frame(width: 40, height: 40)
|
||||||
Text(host.description)
|
Text(host.description)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,79 +22,102 @@ struct KeyDetailView: View {
|
|||||||
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
|
||||||
.ignoresSafeArea(.all)
|
.ignoresSafeArea(.all)
|
||||||
List {
|
List {
|
||||||
TextBox(label: "Name", text: $keyname, prompt: "A name for your key")
|
|
||||||
.onAppear {
|
|
||||||
keyname = keypair.name
|
|
||||||
}
|
|
||||||
.onChange(of: keyname) { _ in
|
|
||||||
keyManager.renameKey(keypair: keypair, newName: keyname)
|
|
||||||
}
|
|
||||||
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text("Used on")
|
Text("Used on")
|
||||||
.bold()
|
.bold()
|
||||||
ForEach(hostsManager.getHostsUsingKeys([keypair])) { host in
|
ForEach(hostsManager.getHostsUsingKeys([keypair])) { host in
|
||||||
HStack {
|
HStack {
|
||||||
SymbolPreview(symbol: host.symbol, label: host.label)
|
HostSymbolPreview(symbol: host.symbol, label: host.label)
|
||||||
.frame(width: 40, height: 40)
|
.frame(width: 40, height: 40)
|
||||||
Text(host.description)
|
Text(host.description)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Menu("Add") {
|
||||||
VStack(alignment: .leading) {
|
let hostsNotUsingKey = hostsManager.hosts.filter(
|
||||||
Text("Public key")
|
{
|
||||||
.bold()
|
hostsManager.getHostsUsingKeys([keypair]).contains($0)
|
||||||
Text(keypair.openSshPubkey)
|
})
|
||||||
}
|
ForEach(hostsNotUsingKey) { host in
|
||||||
VStack(alignment: .leading) {
|
Button() {
|
||||||
Text("Private key")
|
hostsManager.set(keypair: keypair, onHost: host)
|
||||||
.bold()
|
} label: {
|
||||||
.frame(maxWidth: .infinity)
|
Image(systemName: "plus")
|
||||||
ZStack(alignment: .center) {
|
.resizable().scaledToFit()
|
||||||
Text(keypair.openSshPrivkey)
|
.foregroundStyle(.blue)
|
||||||
.blur(radius: reveal ? 0 : 5)
|
.frame(width: 30, height: 30)
|
||||||
VStack {
|
Text("Add")
|
||||||
Image(systemName: "eye.slash.fill")
|
.foregroundStyle(.blue)
|
||||||
.resizable().scaledToFit()
|
|
||||||
.frame(width: 50)
|
|
||||||
Text("Tap to reveal")
|
|
||||||
}
|
|
||||||
.opacity(reveal ? 0 : 1)
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.onTapGesture {
|
|
||||||
Task {
|
|
||||||
if !reveal {
|
|
||||||
guard await authWithBiometrics() else { return }
|
|
||||||
}
|
}
|
||||||
withAnimation(.spring) { reveal.toggle() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Section() {
|
||||||
UIPasteboard.general.string = keypair.openSshPubkey
|
TextBox(label: "Name", text: $keyname, prompt: "A name for your key")
|
||||||
} label: {
|
.onAppear {
|
||||||
CenteredLabel(title: "Copy public key", systemName: "document.on.document")
|
keyname = keypair.name
|
||||||
}
|
}
|
||||||
.listRowSeparator(.hidden)
|
.onChange(of: keyname) { _ in
|
||||||
|
keyManager.renameKey(keypair: keypair, newName: keyname)
|
||||||
Button {
|
}
|
||||||
Task {
|
|
||||||
guard await authWithBiometrics() else { return }
|
Button {
|
||||||
UIPasteboard.general.string = String(data: KeyManager.makeSSHPrivkey(keypair), encoding: .utf8) ?? ""
|
UIPasteboard.general.string = keypair.openSshPubkey
|
||||||
|
} label: {
|
||||||
|
CenteredLabel(title: "Copy public key", systemName: "document.on.document")
|
||||||
}
|
}
|
||||||
} label: {
|
.listRowSeparator(.hidden)
|
||||||
CenteredLabel(title: "Copy private key", systemName: "document.on.document")
|
|
||||||
}
|
Button {
|
||||||
.listRowSeparator(.hidden)
|
Task {
|
||||||
|
guard await authWithBiometrics() else { return }
|
||||||
CenteredLabel(title: "Delete", systemName: "trash")
|
UIPasteboard.general.string = String(data: KeyManager.makeSSHPrivkey(keypair), encoding: .utf8) ?? ""
|
||||||
.foregroundStyle(.red)
|
}
|
||||||
.onTapGesture {
|
} label: {
|
||||||
keyManager.deleteKey(keypair)
|
CenteredLabel(title: "Copy private key", systemName: "document.on.document")
|
||||||
dismiss()
|
|
||||||
}
|
}
|
||||||
|
.listRowSeparator(.hidden)
|
||||||
|
|
||||||
|
CenteredLabel(title: "Delete", systemName: "trash")
|
||||||
|
.foregroundStyle(.red)
|
||||||
|
.onTapGesture {
|
||||||
|
keyManager.deleteKey(keypair)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Section("Key") {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("Public key")
|
||||||
|
.bold()
|
||||||
|
Text(keypair.openSshPubkey.dropLast(2))
|
||||||
|
}
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("Private key")
|
||||||
|
.bold()
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
ZStack(alignment: .center) {
|
||||||
|
Text(keypair.openSshPrivkey.dropLast(2))
|
||||||
|
.blur(radius: reveal ? 0 : 5)
|
||||||
|
VStack {
|
||||||
|
Image(systemName: "eye.slash.fill")
|
||||||
|
.resizable().scaledToFit()
|
||||||
|
.frame(width: 50)
|
||||||
|
Text("Tap to reveal")
|
||||||
|
}
|
||||||
|
.opacity(reveal ? 0 : 1)
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.onTapGesture {
|
||||||
|
Task {
|
||||||
|
if !reveal {
|
||||||
|
guard await authWithBiometrics() else { return }
|
||||||
|
}
|
||||||
|
withAnimation(.spring) { reveal.toggle() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.scrollContentBackground(.hidden)
|
.scrollContentBackground(.hidden)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,14 +46,18 @@ struct KeyImporterView: View {
|
|||||||
.foregroundStyle(.gray)
|
.foregroundStyle(.gray)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button() {
|
|
||||||
keyManager.importKey(type: keyType, priv: privkeyStr, name: keyName)
|
|
||||||
dismiss()
|
|
||||||
} label: {
|
|
||||||
Label("Import", systemImage: "key.horizontal")
|
|
||||||
}
|
|
||||||
.buttonStyle(.borderedProminent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button() {
|
||||||
|
keyManager.importKey(type: keyType, priv: privkeyStr, name: keyName)
|
||||||
|
dismiss()
|
||||||
|
} label: {
|
||||||
|
Text("Import")
|
||||||
|
}
|
||||||
|
.onTapGesture {
|
||||||
|
UINotificationFeedbackGenerator().notificationOccurred(.success)
|
||||||
|
}
|
||||||
|
.buttonStyle(.borderedProminent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// SymbolPreview.swift
|
// HostSymbolPreview.swift
|
||||||
// ShhShell
|
// ShhShell
|
||||||
//
|
//
|
||||||
// Created by neon443 on 26/06/2025.
|
// Created by neon443 on 26/06/2025.
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SymbolPreview: View {
|
struct HostSymbolPreview: View {
|
||||||
@State var symbol: HostSymbol
|
@State var symbol: HostSymbol
|
||||||
@State var label: String
|
@State var label: String
|
||||||
|
|
||||||
@@ -30,5 +30,5 @@ struct SymbolPreview: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
SymbolPreview(symbol: HostSymbol.desktopcomputer, label: "lo0")
|
HostSymbolPreview(symbol: HostSymbol.desktopcomputer, label: "lo0")
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ struct SessionView: View {
|
|||||||
.resizable().scaledToFit()
|
.resizable().scaledToFit()
|
||||||
.frame(width: 40, height: 40)
|
.frame(width: 40, height: 40)
|
||||||
.foregroundStyle(.terminalGreen)
|
.foregroundStyle(.terminalGreen)
|
||||||
SymbolPreview(symbol: host.symbol, label: host.label)
|
HostSymbolPreview(symbol: host.symbol, label: host.label)
|
||||||
.frame(width: 40, height: 40)
|
.frame(width: 40, height: 40)
|
||||||
Text(host.description)
|
Text(host.description)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user