Change Telnet's icon

This commit is contained in:
Kaede Akino committed 2026-09-22 01:13:35 +08:00
1 parent 0f6c365dd5
commit 90fb1bfbcc
13 files changed
+94 -33

No files matched your search

@@ -21,7 +21,7 @@ public nonisolated struct ConnectionHistoryEntry: Identifiable, Hashable, Sendab
public var symbol: String {
switch self {
case .ssh: "terminal"
case .telnet: "terminal"
case .telnet: "text.rectangle"
case .sftp: "folder"
}
}
@@ -233,14 +233,7 @@ private struct JourneyEndpointView: View {
#endif
case .jump: return "server.rack"
case .destination:
return switch purpose {
case .sshSession: "apple.terminal.fill"
case .telnetSession: "terminal.fill"
case .sftpChannel: "folder.fill"
case .metrics: "waveform.path.ecg"
case .portForwarding: "arrow.left.arrow.right"
case .serialSession: "cable.connector"
}
return purpose.symbol(for: .routeDestination)
}
}
@@ -1,6 +1,25 @@
import SwiftUI
import TermindApplication
nonisolated enum ConnectionJourneySymbolPlacement {
case header
case routeDestination
}
extension ConnectionPurpose {
nonisolated func symbol(for placement: ConnectionJourneySymbolPlacement) -> String {
switch (self, placement) {
case (.sshSession, _): "apple.terminal.fill"
case (.telnetSession, _): "text.rectangle.fill"
case (.sftpChannel, .header): "folder.fill.badge.gearshape"
case (.sftpChannel, .routeDestination): "folder.fill"
case (.serialSession, _): "cable.connector"
case (.metrics, _): "waveform.path.ecg"
case (.portForwarding, _): "arrow.left.arrow.right"
}
}
}
public struct ConnectionJourneyHeader: View {
let journey: ConnectionJourney
let selectedForeground: Color
@@ -29,7 +48,7 @@ public struct ConnectionJourneyHeader: View {
.fill(Color.accentColor.gradient)
.frame(width: 52, height: 52)
.overlay {
Image(systemName: symbol)
Image(systemName: journey.purpose.symbol(for: .header))
.font(.system(size: 22, weight: .semibold))
.foregroundStyle(selectedForeground)
}
@@ -82,16 +101,6 @@ public struct ConnectionJourneyHeader: View {
return "\(protocolName) \(address)"
}
private var symbol: String {
switch journey.purpose {
case .sshSession: "apple.terminal.fill"
case .telnetSession: "terminal.fill"
case .sftpChannel: "folder.fill.badge.gearshape"
case .serialSession: "cable.connector"
case .metrics: "waveform.path.ecg"
case .portForwarding: "arrow.left.arrow.right"
}
}
}
public struct ConnectionJourneyStatus: View {
+3 -3
View File
@@ -609,13 +609,13 @@ struct MobileVaultView: View {
private func hostMenuButton(_ action: MobileHostMenuAction, host: Host) -> some View {
switch action {
case .ssh:
Button("SSH", systemImage: "terminal") { open(host.id, .ssh) }
Button("SSH", systemImage: ConnectionHistoryEntry.Kind.ssh.symbol) { open(host.id, .ssh) }
.disabled(!host.sshEnabled)
case .telnet:
Button("Telnet", systemImage: "terminal") { open(host.id, .telnet) }
Button("Telnet", systemImage: ConnectionHistoryEntry.Kind.telnet.symbol) { open(host.id, .telnet) }
.disabled(!host.telnetEnabled)
case .sftp:
Button("SFTP", systemImage: "folder") { open(host.id, .sftp) }
Button("SFTP", systemImage: ConnectionHistoryEntry.Kind.sftp.symbol) { open(host.id, .sftp) }
.disabled(!host.sshEnabled)
case .edit:
Button("Edit", systemImage: "pencil") { editingHost = host }
@@ -11,7 +11,9 @@ import struct TermindDomain.Host
struct MobileHomeScreenQuickActionTests {
@Test func descriptorsUseTheNewestThreeUniqueValidHistoryRows() throws {
let app = try MobileAppModel(inMemory: true)
let repeated = Host(name: "Production", host: "production.example.invalid")
let repeated = Host(
name: "Production", host: "production.example.invalid",
telnetEnabled: true)
let others = (0..<3).map { Host(name: "Host \($0)", host: "host-\($0).example.invalid") }
app.library.upsert(repeated)
for host in others { app.library.upsert(host) }
@@ -20,6 +22,8 @@ struct MobileHomeScreenQuickActionTests {
kind: .ssh, for: repeated.id, at: Date(timeIntervalSince1970: 60))
_ = app.connectionHistory.record(
kind: .ssh, for: repeated.id, at: Date(timeIntervalSince1970: 50))
_ = app.connectionHistory.record(
kind: .telnet, for: repeated.id, at: Date(timeIntervalSince1970: 45))
_ = app.connectionHistory.record(
kind: .sftp, for: repeated.id, at: Date(timeIntervalSince1970: 40))
_ = app.connectionHistory.record(
@@ -43,11 +47,13 @@ struct MobileHomeScreenQuickActionTests {
descriptors.map(\.action)
== [
.history(hostID: repeated.id, kind: .ssh),
.history(hostID: repeated.id, kind: .telnet),
.history(hostID: repeated.id, kind: .sftp),
.history(hostID: others[0].id, kind: .ssh),
])
#expect(descriptors.map(\.title) == ["Production", "Production", "Host 0"])
#expect(descriptors.map(\.symbol) == ["terminal", "folder", "terminal"])
#expect(descriptors.map(\.title) == ["Production", "Production", "Production"])
#expect(descriptors.map(\.symbol) == ["terminal", "text.rectangle", "folder"])
#expect(UIImage(systemName: descriptors[1].symbol) != nil)
#expect(descriptors[1].shortcutItem.icon != nil)
}
@Test func historyShortcutPayloadRoundTripsAndMalformedItemsAreRejected() throws {
@@ -219,7 +219,7 @@ final class AppCommandRegistry {
AppCommandDescriptor(
id: "host.telnet.\(host.id.uuidString)", title: host.name,
subtitle: String(localized: "Connect with Telnet · \(host.displayAddress(for: .telnet))"),
symbol: "terminal", section: .hosts, keywords: keywords + ["telnet"],
symbol: MenuSymbol.telnet, section: .hosts, keywords: keywords + ["telnet"],
target: .connectHost(host.id, .telnetSession)))
}
return commands
+2 -1
View File
@@ -33,6 +33,7 @@ nonisolated enum MenuSymbol {
static let connect = "network"
static let batchStartup = "wind"
static let ssh = "apple.terminal"
static let telnet = "text.rectangle"
static let sftp = "folder"
// MARK: Creating
@@ -121,7 +122,7 @@ nonisolated enum MenuSymbol {
/// is exactly the kind of mistake no one notices in review.
static let all: [String] = [
settings, quickOpen, find, actions, support, showAssistant,
quickConnect, connect, batchStartup, ssh, sftp,
quickConnect, connect, batchStartup, ssh, telnet, sftp,
newChat, newHost, newGroup, newPackage, newFolder, newSnippet, saveAsSnippet,
newIdentity, generateKey, generateCommand,
importItem, download, export, upload,
+2 -2
View File
@@ -190,7 +190,7 @@ enum HostMenuEntries {
app.open([host], as: .sshSession, in: window)
},
NativeMenuEntry(
title: String(localized: "with Telnet"), symbol: "terminal",
title: String(localized: "with Telnet"), symbol: MenuSymbol.telnet,
isEnabled: host.telnetEnabled
) {
app.open([host], as: .telnetSession, in: window)
@@ -231,7 +231,7 @@ struct HostConnectMenu: View {
app.open(hosts, as: .sshSession, in: window)
}
.disabled(!hosts.allSatisfy(\.sshEnabled))
Button("with Telnet", systemImage: "terminal") {
Button("with Telnet", systemImage: MenuSymbol.telnet) {
app.open(hosts, as: .telnetSession, in: window)
}
.disabled(!hosts.allSatisfy(\.telnetEnabled))
+1 -1
View File
@@ -162,7 +162,7 @@ final class Pane: Identifiable {
var symbol: String {
switch content {
case .sshSession: "apple.terminal"
case .telnetSession: "terminal"
case .telnetSession: MenuSymbol.telnet
case .sftpChannel: "folder"
case .serialSession: "cable.connector"
case .empty: "rectangle.dashed"
+8
View File
@@ -15,6 +15,14 @@ import struct TermindDomain.Host
@Suite
@MainActor
struct ConnectionHistoryTests {
@Test
func connectionProtocolSymbolsAreDistinct() {
#expect(ConnectionHistoryEntry.Kind.ssh.symbol == "terminal")
#expect(ConnectionHistoryEntry.Kind.telnet.symbol == "text.rectangle")
#expect(ConnectionHistoryEntry.Kind.sftp.symbol == "folder")
#expect(Set(ConnectionHistoryEntry.Kind.allCases.map(\.symbol)).count == 3)
}
@Test
func schemaV5MigratesWithAnEmptyConnectionTimeline() throws {
let directory = FileManager.default.temporaryDirectory
+11 -1
View File
@@ -3,17 +3,27 @@ import TermindApplication
import TermindDomain
import TermindInfrastructure
import TermindPersistence
import TermindPresentation
import TermindRemoteInfrastructure
import Testing
import struct TermindDomain.Host
@testable import Termind
@testable import TermindPresentation
@Suite
@MainActor
struct ConnectionJourneyTests {
@Test
func telnetUsesItsOwnSymbolThroughoutTheConnectionJourney() {
#expect(ConnectionPurpose.telnetSession.symbol(for: .header) == "text.rectangle.fill")
#expect(ConnectionPurpose.telnetSession.symbol(for: .routeDestination) == "text.rectangle.fill")
#expect(ConnectionPurpose.sshSession.symbol(for: .header) == "apple.terminal.fill")
#expect(ConnectionPurpose.sshSession.symbol(for: .routeDestination) == "apple.terminal.fill")
#expect(ConnectionPurpose.sftpChannel.symbol(for: .header) == "folder.fill.badge.gearshape")
#expect(ConnectionPurpose.sftpChannel.symbol(for: .routeDestination) == "folder.fill")
}
@Test
func routeStartsAtBlueLocalEndpointAndKeepsHostsPending() {
let jump = Host(name: "Bastion", host: "jump.example")
+23
View File
@@ -15,6 +15,29 @@ import struct TermindDomain.Host
@Suite
@MainActor
struct QuickOpenTests {
@Test
func telnetUsesItsOwnSymbolInQuickOpenAndNativeHostMenus() throws {
let host = Host(
name: "Legacy Console", host: "console.example.invalid",
telnetEnabled: true)
let store = HostLibraryModel(hosts: [host])
let app = AppModel(hosts: store)
let window = WindowModel()
let commands = app.commands.commands(app: app, window: window)
let ssh = try #require(commands.first { $0.target == .connectHost(host.id, .sshSession) })
let telnet = try #require(commands.first { $0.target == .connectHost(host.id, .telnetSession) })
#expect(ssh.symbol == MenuSymbol.ssh)
#expect(telnet.symbol == MenuSymbol.telnet)
#expect(ssh.symbol != telnet.symbol)
let entries = HostMenuEntries.entries(for: host, app: app, window: window)
let connect = try #require(entries.first { $0.title == String(localized: "Connect") })
let telnetEntry = try #require(
connect.children.first { $0.title == String(localized: "with Telnet") })
#expect(telnetEntry.symbol == MenuSymbol.telnet)
}
@Test
func registryCombinesManagementWorkspacesHostsAndActions() {
let host = Host(name: "Production", host: "prod.example", tags: ["critical"])
+11
View File
@@ -15,6 +15,17 @@ import struct TermindDomain.Host
@Suite
@MainActor
struct WindowStateTests {
@Test
func sshAndTelnetPanesUseDistinctProtocolSymbols() {
let host = Host(
name: "Console", host: "console.example.invalid",
telnetEnabled: true)
#expect(Pane.sshSession(host: host).symbol == MenuSymbol.ssh)
#expect(Pane.telnetSession(host: host).symbol == MenuSymbol.telnet)
#expect(MenuSymbol.ssh != MenuSymbol.telnet)
}
@Test
func assistantManualOrderMovesAcrossPinnedBoundaryAndStaysStableAfterActivity() throws {
let first = ConversationModel(updatedAt: Date(timeIntervalSinceReferenceDate: 10))