docs: update screenshots
This commit is contained in:
1 parent
09e2fd2345
commit
80b4641af2
6 files changed
+103
-12
No files matched your search
@@ -100,7 +100,7 @@ capture() {
|
||||
local_test_pid=$!
|
||||
local ready_payload=""
|
||||
|
||||
for _ in {1..600}; do
|
||||
for _ in {1..2400}; do
|
||||
ready_payload="$(
|
||||
rg -o 'TERMIND_MAC_MARKETING_READY .*' "$test_log" \
|
||||
| tail -n 1 \
|
||||
|
||||
@@ -97,6 +97,18 @@ import TermindApplication
|
||||
}
|
||||
}
|
||||
|
||||
func makeHostLibrary() -> HostLibraryModel {
|
||||
let hosts = HostLibraryModel.demo(language: language, includesConnectionActivity: scene != .hosts)
|
||||
if scene == .hosts {
|
||||
// Seed once at app launch, matching the two workspaces below. Window construction
|
||||
// runs inside SwiftUI rendering and must not mutate the observed host library.
|
||||
for host in hosts.hosts.prefix(2) {
|
||||
hosts.setStatus(.connected, for: host.id)
|
||||
}
|
||||
}
|
||||
return hosts
|
||||
}
|
||||
|
||||
func makeWindow(hosts: HostLibraryModel) -> WindowModel {
|
||||
switch scene {
|
||||
case .workspace:
|
||||
@@ -106,7 +118,7 @@ import TermindApplication
|
||||
case .agent:
|
||||
return agentWindow(hosts: hosts)
|
||||
case .hosts:
|
||||
return hostsWindow()
|
||||
return hostsWindow(hosts: hosts)
|
||||
case .appSettings:
|
||||
let window = WindowModel()
|
||||
window.selectedDestination = .settings
|
||||
@@ -122,8 +134,15 @@ import TermindApplication
|
||||
}
|
||||
}
|
||||
|
||||
private func hostsWindow() -> WindowModel {
|
||||
let window = WindowModel(vaultDestination: .hosts)
|
||||
private func hostsWindow(hosts: HostLibraryModel) -> WindowModel {
|
||||
let workspaces = hosts.hosts.prefix(2).map { host in
|
||||
let session = SSHSessionModel.demo(host: host)
|
||||
let workspace = Workspace(pane: Pane(.sshSession(session)))
|
||||
workspace.customTitle = host.name
|
||||
return workspace
|
||||
}
|
||||
let window = WindowModel(workspaces: workspaces, vaultDestination: .hosts)
|
||||
window.selectedDestination = .vault
|
||||
window.showsSidebar = true
|
||||
window.sidebarMode = .navigation
|
||||
return window
|
||||
|
||||
@@ -37,6 +37,9 @@ struct TermindApp: App {
|
||||
private let modelContainer: ModelContainer
|
||||
@State private var app: AppModel
|
||||
private let launchLanguage: AppLanguage
|
||||
#if DEBUG
|
||||
@State private var screenshotWindow: WindowModel?
|
||||
#endif
|
||||
|
||||
init() {
|
||||
ContextAttachmentOpener.cleanPreviousSession()
|
||||
@@ -58,13 +61,14 @@ struct TermindApp: App {
|
||||
modelContainer = container
|
||||
#if DEBUG
|
||||
if let screenshotDemo {
|
||||
let hosts = HostLibraryModel.demo(language: screenshotDemo.language)
|
||||
let hosts = screenshotDemo.makeHostLibrary()
|
||||
let app = AppModel(
|
||||
hosts: hosts, ai: .demo(), proAccess: .unrestrictedForTesting(),
|
||||
onboarding: OnboardingController(automaticPresentationEnabled: false),
|
||||
serverMetrics: screenshotDemo.makeMetricsModel(hosts: hosts)
|
||||
)
|
||||
_app = State(initialValue: app)
|
||||
_screenshotWindow = State(initialValue: screenshotDemo.makeWindow(hosts: hosts))
|
||||
return
|
||||
}
|
||||
#endif
|
||||
@@ -205,8 +209,8 @@ struct TermindApp: App {
|
||||
|
||||
private func makeWindow(requestID: UUID?) -> WindowModel {
|
||||
#if DEBUG
|
||||
if requestID == nil, let demo = ScreenshotDemoConfiguration.active {
|
||||
return demo.makeWindow(hosts: app.hostLibrary)
|
||||
if requestID == nil, let screenshotWindow {
|
||||
return screenshotWindow
|
||||
}
|
||||
#endif
|
||||
let window = WindowModel()
|
||||
|
||||
@@ -9,7 +9,7 @@ import struct TermindDomain.Host
|
||||
extension HostLibraryModel {
|
||||
/// Seed data for P0, so the sidebar and workspace list can be exercised before any
|
||||
/// persistence or networking exists.
|
||||
static func demo(language: AppLanguage = .english) -> HostLibraryModel {
|
||||
static func demo(language: AppLanguage = .english, includesConnectionActivity: Bool = true) -> HostLibraryModel {
|
||||
func text(_ en: String, _ zhHans: String, _ zhHant: String) -> String {
|
||||
switch language {
|
||||
case .simplifiedChinese: zhHans
|
||||
@@ -233,10 +233,12 @@ extension HostLibraryModel {
|
||||
snippets: snippets,
|
||||
snippetPackages: [diagnostics, webOperations],
|
||||
portForwardings: portForwardings,
|
||||
sftpTransfers: sftpTransfers,
|
||||
sftpTransfers: includesConnectionActivity ? sftpTransfers : [],
|
||||
knownHosts: knownHosts
|
||||
)
|
||||
|
||||
guard includesConnectionActivity else { return store }
|
||||
|
||||
// A spread of connection states so Vault and Welcome Host cards can be
|
||||
// checked against every dot color without a server.
|
||||
store.setStatus(.connected, for: web01.id)
|
||||
|
||||
@@ -32,13 +32,27 @@ import Testing
|
||||
window.makeFirstResponder(nil)
|
||||
}
|
||||
|
||||
for _ in 0..<100 {
|
||||
// Keep real pointer hover out of every capture without changing production row styling.
|
||||
let originalPointer = NSEvent.mouseLocation
|
||||
let desktopTop = try #require(NSScreen.screens.first).frame.maxY
|
||||
func movePointer(to point: NSPoint) {
|
||||
let location = CGPoint(x: point.x, y: desktopTop - point.y)
|
||||
CGWarpMouseCursorPosition(location)
|
||||
CGEvent(
|
||||
mouseEventSource: nil, mouseType: .mouseMoved,
|
||||
mouseCursorPosition: location, mouseButton: .left
|
||||
)?.post(tap: .cghidEventTap)
|
||||
}
|
||||
defer { movePointer(to: originalPointer) }
|
||||
|
||||
for _ in 0..<3600 {
|
||||
NSRunningApplication.current.activate(options: [.activateAllWindows])
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
window.orderFrontRegardless()
|
||||
window.makeMain()
|
||||
window.makeKey()
|
||||
if NSApp.isActive, window.isKeyWindow {
|
||||
movePointer(to: NSPoint(x: window.frame.midX, y: window.frame.maxY + 16))
|
||||
// Activation can be transient while test hosts launch and exit.
|
||||
// Require the focused appearance to stay active through rendering.
|
||||
try await Task.sleep(for: .milliseconds(300))
|
||||
@@ -47,11 +61,25 @@ import Testing
|
||||
try await Task.sleep(for: .milliseconds(50))
|
||||
}
|
||||
guard NSApp.isActive, window.isKeyWindow else {
|
||||
Issue.record("Marketing window could not become the focused key window")
|
||||
let frontmost = NSWorkspace.shared.frontmostApplication
|
||||
let diagnostic =
|
||||
"Marketing window could not become the focused key window: "
|
||||
+ "active=\(NSApp.isActive), key=\(window.isKeyWindow), "
|
||||
+ "frontmost=\(frontmost?.localizedName ?? "none") "
|
||||
+ "pid=\(frontmost?.processIdentifier ?? -1)"
|
||||
Issue.record("\(diagnostic)")
|
||||
return
|
||||
}
|
||||
try #require(NSApp.isActive && window.isKeyWindow)
|
||||
try #require(window.backingScaleFactor == 2)
|
||||
let pointer = NSEvent.mouseLocation
|
||||
let contentFrame = window.convertToScreen(window.contentLayoutRect)
|
||||
try #require(!contentFrame.contains(pointer), "Pointer must be outside the content before capture")
|
||||
// Once hover has cleared, prevent pointer movement during the capture interval
|
||||
// from highlighting a card or file row. Restore normal input after the test.
|
||||
let ignoredMouseEvents = window.ignoresMouseEvents
|
||||
window.ignoresMouseEvents = true
|
||||
defer { window.ignoresMouseEvents = ignoredMouseEvents }
|
||||
|
||||
let token = UUID().uuidString
|
||||
let scene = configuration.scene.rawValue
|
||||
@@ -67,6 +95,7 @@ import Testing
|
||||
// acknowledging files inside another app's container.
|
||||
try await Task.sleep(for: .seconds(5))
|
||||
#expect(NSApp.isActive && window.isKeyWindow, "Capture window lost focus before the capture interval ended")
|
||||
#expect(window.ignoresMouseEvents, "Capture window must not accept hover events")
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,3 +1,4 @@
|
||||
import Foundation
|
||||
import TermindApplication
|
||||
import TermindDomain
|
||||
import TermindInfrastructure
|
||||
@@ -86,7 +87,7 @@ import TermindRemoteInfrastructure
|
||||
let configuration = ScreenshotDemoConfiguration(
|
||||
scene: .hosts, language: .english
|
||||
)
|
||||
let window = configuration.makeWindow(hosts: .demo())
|
||||
let window = configuration.makeWindow(hosts: configuration.makeHostLibrary())
|
||||
|
||||
#expect(window.selectedDestination == .vault)
|
||||
#expect(window.vaultDestination == .hosts)
|
||||
@@ -94,6 +95,42 @@ import TermindRemoteInfrastructure
|
||||
#expect(window.sidebarMode == .navigation)
|
||||
}
|
||||
|
||||
@Test
|
||||
func vaultCaptureStatusesMatchItsTwoWorkspacesInEveryLanguage() throws {
|
||||
for language in [AppLanguage.english, .simplifiedChinese, .traditionalChinese] {
|
||||
let configuration = ScreenshotDemoConfiguration(scene: .hosts, language: language)
|
||||
let hosts = configuration.makeHostLibrary()
|
||||
let window = configuration.makeWindow(hosts: hosts)
|
||||
|
||||
#expect(window.workspaces.count == 2)
|
||||
#expect(hosts.sftpTransfers.isEmpty)
|
||||
#expect(!hosts.hosts.isEmpty)
|
||||
var connectedHostIDs: Set<UUID> = []
|
||||
for workspace in window.workspaces {
|
||||
#expect(workspace.panes.count == 1)
|
||||
let session = try #require(workspace.panes.first?.sshSession)
|
||||
#expect(session.status == .connected)
|
||||
connectedHostIDs.insert(session.hostID)
|
||||
}
|
||||
#expect(connectedHostIDs.count == 2)
|
||||
for host in hosts.hosts {
|
||||
let expectedStatus: ConnectionStatus =
|
||||
connectedHostIDs.contains(host.id) ? .connected : .disconnected
|
||||
#expect(hosts.status(of: host.id) == expectedStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func otherCaptureScenesKeepTheirConnectionActivity() {
|
||||
for scene in ScreenshotDemoConfiguration.Scene.allCases where scene != .hosts {
|
||||
let hosts = ScreenshotDemoConfiguration(scene: scene, language: .english).makeHostLibrary()
|
||||
#expect(!hosts.sftpTransfers.isEmpty)
|
||||
#expect(hosts.hosts.contains { hosts.status(of: $0.id) == .connected })
|
||||
#expect(hosts.hosts.contains { hosts.status(of: $0.id) == .connecting })
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func appSettingsSceneUsesTheProductionSettingsRouteInEveryLanguage() {
|
||||
for language in [AppLanguage.english, .simplifiedChinese, .traditionalChinese] {
|
||||
|
||||
Reference in new issue
Block a user