Repository navigation
Clarify Cloud Ports and use the established VPN onboarding page #13239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
143 commits
Select commit
Hold shift + click to select a range
586d493
test: distinguish unreachable Cloud port listeners
austinywang bf35b44
fix: explain Cloud Ports discovery and VPN state
austinywang 45dff08
fix: address Ports status review findings
austinywang 3f540bc
refactor: split Cloud Ports status types
austinywang 86e060a
fix: preserve Cloud Ports interaction and sleep state
austinywang 9d36260
fix: resolve remaining Ports review blockers
austinywang dabb3f9
fix: defer Cloud port scans until requested
austinywang 485ef8e
fix: handle default Ports discovery and status tests
austinywang 2f29512
fix: preserve unsupported ports and refresh route metadata
austinywang 6cf2ed3
fix: fence Cloud port retries and sizing
austinywang fcdf5dd
fix: avoid recursive Ports sizing and fleet retries
austinywang a572257
fix: finish Ports status layout and interaction
austinywang 1a79922
Merge origin/main into Cloud Ports VPN state
austinywang e0deb0e
fix: keep Ports action hit testing direct
austinywang 23897d7
fix: keep unsupported provider state through link warnings
austinywang 6c0afd6
style: keep provider state guard within budget
austinywang 8b87c8b
fix: refresh Cloud metadata before port retry
austinywang 8edc9be
fix: scope metadata retry and style status insets
austinywang 9f10463
fix: align Ports discovery with authenticated browser routing
austinywang 0b4817d
fix: use scoped port refresh from the Ports menu
austinywang b384511
Merge remote-tracking branch 'origin/main' into 13234-cloud-ports-vpn…
austinywang 1d2eb9a
fix: match port classification to in-app loopback route
austinywang f66f4fa
fix: keep Cloud Ports status height type-safe
austinywang 8854ad3
Merge remote-tracking branch 'origin/main' into 13234-cloud-ports-vpn…
austinywang 7badfc1
test: evaluate mutating port discovery assertions
austinywang 7b38e40
ci: retrigger hosted Swift verification
austinywang b1d8dfc
test: match localized no-service guidance
austinywang f371cc0
test: align port identity and native action assertions
austinywang ae087d1
Merge remote-tracking branch 'origin/main' into 13234-cloud-ports-vpn…
austinywang 3aae903
fix: preserve explicit Cloud port discovery demand
austinywang 886e9dd
fix: invalidate Cloud port rows after width changes
austinywang af25072
Merge branch 'main' of https://github.com/manaflow-ai/cmux into 13234…
austinywang 7306395
test: align Cloud tree expectations with current sections
austinywang b495c49
fix: restore Cloud VPN setup affordance in Ports
austinywang ae1f2f5
fix: clarify VPN state in initial Ports status
austinywang a67648b
test: require persistent Ports VPN help and independent discovery
austinywang fbf211c
feat: restore contextual Cloud VPN setup
austinywang 009c4e0
fix: make Cloud VPN setup stateful and shared
austinywang 37282fc
fix: preserve VPN refusal and explain Ports routing
austinywang 254e8c8
test: match initial Ports route guidance
austinywang bd3cc15
Merge remote-tracking branch 'origin/main' into 13234-cloud-ports-vpn…
austinywang d73e290
chore: preserve main test wiring during merge
austinywang 37d101e
chore: preserve main test wiring during merge
austinywang 52df7f0
chore: wire Cloud port regression tests
austinywang e612bed
fix: retain current device surface model after main merge
austinywang 179b8d9
fix: retain Cloud Ports target sources after main merge
austinywang 4a480e0
chore: wire current CLI config validation
austinywang ccbd0c0
fix: merge current main project with Cloud Ports sources
austinywang 7a59839
fix: point merged Cloud source refs at their paths
austinywang 61cb1fb
fix: merge Cloud machine value model with device support
austinywang 51fb7d5
fix: restore task project sources and current test wiring
austinywang f4f9f56
fix: remove stale main source references after merge
austinywang dcbd385
fix: keep Cloud model aligned with task target
austinywang 622d5a2
fix: restore Cloud device target wiring
austinywang 9af2192
test: keep VPN setup visible beside discovered ports
austinywang dc5f6d9
fix: restore visible Cloud VPN guidance for Ports
austinywang c89213c
fix: pass VPN guidance state in initializer order
austinywang a164e98
fix: order Cloud tree guidance arguments
austinywang af21933
merge: integrate origin/main with Cloud VPN Ports guidance
austinywang 35f3cb7
merge: integrate origin/main with Cloud VPN Ports guidance
austinywang 9069c61
fix: wire Cloud port discovery state owner
austinywang 0a965c6
fix: import packaged Cloud port models
austinywang 699053d
fix: import surface catalog model for socket payloads
austinywang 2717e21
fix: import packaged Cloud types in app extensions
austinywang 2ff0e8e
fix: align Cloud port retry with shared link provider
austinywang 0db3b73
fix: import packaged tunnel state in VPN setup model
austinywang 0140292
fix: expose Cloud tree leading geometry to app outline
austinywang 5e11a93
fix: restore explicit Cloud port discovery demand
austinywang 5ca8b63
fix: import packaged tree placeholder in port builder
austinywang a27826a
fix: defer Cloud Ports scans and activate VPN help
austinywang 6c8b90c
merge: integrate origin/main and remove Ports VPN header help
austinywang aad1a85
merge: integrate origin/main into Cloud Ports VPN state
austinywang d387d23
fix: restore Cloud Ports project wiring and VPN setup close shortcut
austinywang eb9fee8
fix: compile Cloud Ports against current main
austinywang b2490f1
merge: integrate origin/main into Cloud Ports VPN state
austinywang ec92fb5
tests: import package modules in Cloud Ports tests
austinywang 988703a
tests: SSH Ports discover over loopback without Cloud VPN guidance
austinywang aad96b5
fix: route SSH Ports discovery over loopback and settle failed scans
austinywang 67c3261
fix: restore Cloud tree row heights lost in the main merge
austinywang a0a97d4
fix: install a retried machine's private route on the shared link
austinywang 78af234
fix: drop another machine's ports from an unavailable scan
austinywang d1124b3
tests: align Ports tests with closed-by-default groups and loopback b…
austinywang cc4198a
Merge main (f39a1e59c6f5) into 13234-cloud-ports-vpn-state
austinywang d7d2b15
tests: a Ports rescan keeps its settled inventory and failed links se…
austinywang c4163e8
fix: fence Ports scans by request so summary polls and cached scans c…
austinywang 36ce5bc
Merge main (5a698502379a) into 13234-cloud-ports-vpn-state
austinywang 20e02ee
tests: a rescan's Ports rows survive a cached refresh that retires it…
austinywang e319940
fix: publish a rescan's Ports rows on its request fence, not the refr…
austinywang 2a7222b
tests: a snapshot that outlives a rescan keeps the rescan's Ports rows
austinywang ffec561
fix: publish the Ports inventory accepted during a refresh's snapshot…
austinywang f678dbf
tests: expect Ports to start collapsed and unchecked in the Cloud tree
austinywang 3383c97
tests: give each Ports recovery fixture its own SSH machine
austinywang 0428218
fix: size the Ports group row like every other Cloud tree group
austinywang dc3e3cc
fix: keep the checklist popover's detach mark through its animated close
austinywang e7da910
Merge main (fb665a08d49a) into 13234-cloud-ports-vpn-state
austinywang 4382462
Merge main (cc9065904a55) into 13234-cloud-ports-vpn-state
austinywang aa44f87
tests: find re-presented popover windows by strong reference
austinywang 9b04bb6
test: Ports actions reach machines under the Cloud Machines section
austinywang 2620606
test: loopback aliases are not other-interface Ports listeners
austinywang 45be5c9
fix: Ports actions find sectioned machines; ignore loopback aliases
austinywang 05e3352
Merge commit '83270f163768380d45fe24e21b1ba5361ffbcee8' into 13234-cl…
austinywang 516caf5
fix: retranslate Cloud VPN setup guidance to match current English copy
austinywang 7db5ff0
test: routine link failure before demand keeps Ports not checked yet
austinywang 94977f2
Merge commit '4c5272e9153eca2033c9f40ac749f0c3a5bcb291' into 13234-cl…
austinywang d53b4cd
test: pin Cloud outline attention test to 100% magnification
austinywang c7af924
Localize Cloud Ports status copy for every catalog locale
austinywang 3cf7f98
test: a requested machine gaining a Ports route scans and stays re-re…
austinywang 79518b6
test: cancelled and SSH Ports refreshes settle without stale loading …
austinywang ad7ffe9
Settle a cancelled Ports request and keep SSH ids out of Cloud metada…
austinywang 80411d8
test: Ports settles after a cancel during display discovery and keeps…
austinywang 9161249
Settle a Ports request cancelled during display discovery without hid…
austinywang c648233
Merge main (3324f6311893) into 13234-cloud-ports-vpn-state
austinywang e88d277
Keep Localizable.xcstrings in main's key order
austinywang 44abc14
Merge main (e28555a2ecdf) into 13234-cloud-ports-vpn-state
austinywang c171271
test: turning Cloud VPN off rebuilds the cached tree with Ports guidance
austinywang cb48d3d
test: Ports and Settings open one Cloud VPN pane instead of a window
austinywang c9a04f1
Open Cloud VPN setup as a pane instead of a window
austinywang cb70bc9
test: Settings brings the main window forward to the Cloud VPN pane
austinywang 3ff7a0d
Bring the main window forward when Settings opens Cloud VPN setup
austinywang 831806c
Merge main (446581e109ef) into 13234-cloud-ports-vpn-state
austinywang 4bac62c
Merge branch 'main' of https://github.com/manaflow-ai/cmux into 13234…
austinywang 875c067
Cover Settings reopening the Cloud VPN pane after it closes
austinywang aec5cdf
Merge main (f8079082fc46) into 13234-cloud-ports-vpn-state
austinywang 3fd1dcd
Merge main (528c5a870dc2) into 13234-cloud-ports-vpn-state
austinywang 26f380b
Merge commit 'a98c560063fc114d1dd11ad9d7fa8f15c3a8ed4b' into 13234-cl…
austinywang b7c156b
Merge main (0ebf8d7f4789) into 13234-cloud-ports-vpn-state
austinywang 95744f3
Merge main (356443354a63) into 13234-cloud-ports-vpn-state
austinywang d453aac
test: Ports status rows fit every wrapped line
austinywang 1289156
Size Ports status rows with the label cell that draws them
austinywang 8883562
Merge main (f7ee3bc64db5) into 13234-cloud-ports-vpn-state
austinywang 7713ad0
test: Ports never pair VPN setup guidance with another status row
austinywang f8cea99
Show Cloud VPN setup guidance only beside a finished scan's ports
austinywang f2be9e6
test: clarify Ports when Cloud VPN is not configured
austinywang 724f164
Make Cloud Ports clear without VPN setup
austinywang 39fe8a9
Merge main (6485102d2e2f) into 13234-cloud-ports-vpn-state
austinywang d89e69d
Update unnamed port tooltip coverage for the no-VPN flow
austinywang ed1a765
test: exclude container runtime listeners from Cloud app ports
austinywang 6e15922
Exclude container runtime management listeners from Cloud Ports
austinywang 60ff6d5
Read root-owned port metadata through existing guest permissions
austinywang 1d4fe79
Use the existing TcpListener import in the discovery regression
austinywang b7f085d
Explain the empty Ports state without VPN jargon
austinywang 260e689
Match Cloud VPN setup with the established onboarding page
austinywang e0e3119
Merge main into Cloud Ports VPN branch
austinywang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
10 changes: 10 additions & 0 deletions
10
Packages/macOS/CmuxCloud/Sources/CmuxCloud/Tree/CloudPortsStatusAction.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import Foundation | ||
|
|
||
| /// The action exposed by an actionable Ports status callout. | ||
| public enum CloudPortsStatusAction: Equatable, Sendable { | ||
| case none | ||
| case refresh | ||
| case setupVPN | ||
| case openMachine | ||
| case openShell | ||
| } |
131 changes: 131 additions & 0 deletions
131
Packages/macOS/CmuxCloud/Sources/CmuxCloud/Tree/CloudPortsStatusPresentation.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| import CmuxSurfaceCatalogModel | ||
| import Foundation | ||
|
|
||
| /// One immutable Ports reason shared by native status rows and their actions. | ||
| public struct CloudPortsStatusPresentation: Equatable, Sendable { | ||
| public let state: CloudPortDiscoveryState | ||
| public let isVPNGuidance: Bool | ||
|
|
||
| public init(state: CloudPortDiscoveryState, isVPNGuidance: Bool = false) { | ||
| self.state = state | ||
| self.isVPNGuidance = isVPNGuidance | ||
| } | ||
|
|
||
| public static var vpnGuidance: Self { | ||
| Self(state: .available, isVPNGuidance: true) | ||
| } | ||
|
|
||
| public static func make(info: SurfaceMachineInfo) -> Self { | ||
| if info.portDiscoveryState == .notRequested { | ||
| switch info.linkState { | ||
| case .asleep: return Self(state: .unavailable(.machineAsleep)) | ||
| case .error: return Self(state: .unavailable(.link)) | ||
| case .unavailable: return Self(state: .unavailable(.transport)) | ||
| default: break | ||
| } | ||
| } | ||
| return Self(state: info.portDiscoveryState) | ||
| } | ||
|
|
||
| public var title: String { | ||
| if isVPNGuidance { | ||
| return String(localized: "cloud.ports.vpnOff.title", defaultValue: "Optional: Cloud VPN") | ||
| } | ||
| switch state { | ||
| case .notRequested: | ||
| return String(localized: "cloudTree.ports.notRequested.title", defaultValue: "Ports not checked yet") | ||
| case .loading: | ||
| return String(localized: "cloudTree.ports.loading", defaultValue: "Discovering ports…") | ||
| case .available: | ||
| return String(localized: "cloudTree.ports.available.title", defaultValue: "Listening services") | ||
| case .loopbackOnly: | ||
| return String(localized: "cloudTree.ports.loopback.title", defaultValue: "Loopback services available") | ||
| case .empty(.noListeningService): | ||
| return String(localized: "cloudTree.ports.empty", defaultValue: "No ports yet") | ||
| case .empty(.otherInterfaceOnly): | ||
| return String(localized: "cloudTree.ports.binding.title", defaultValue: "Services use another interface") | ||
| case .unavailable(.privateAddress): | ||
| return String(localized: "cloudTree.ports.privateAddress", defaultValue: "Private address unavailable") | ||
| case .unavailable(.machineAsleep): | ||
| return String(localized: "cloudTree.ports.asleep", defaultValue: "Open the machine to discover ports") | ||
| case .unavailable(.link): | ||
| return String(localized: "cloudTree.ports.link.title", defaultValue: "Cloud link unavailable") | ||
| case .unavailable: | ||
| return String(localized: "cloudTree.ports.unavailable", defaultValue: "Port discovery unavailable. Refresh to retry.") | ||
| case .stale: | ||
| return String(localized: "cloudTree.ports.stale", defaultValue: "Port list may be out of date") | ||
| case .unsupported: | ||
| return String(localized: "cloudTree.ports.unsupported", defaultValue: "Ports are not supported by this provider.") | ||
| } | ||
| } | ||
|
|
||
| public var message: String { | ||
| if isVPNGuidance { | ||
| return String( | ||
| localized: "cloud.ports.vpnOff.explanation", | ||
| defaultValue: "Ports open in cmux without setup. To use private addresses in other apps, set up Cloud VPN." | ||
| ) | ||
| } | ||
| switch state { | ||
| case .notRequested: | ||
| return Self.routeNote | ||
| case .loading: | ||
| return String(localized: "cloudTree.ports.loading.detail", defaultValue: "Checking services through cmux’s authenticated Cloud link. No system VPN is needed.") | ||
| case .available: | ||
| return Self.routeNote | ||
| case .loopbackOnly: | ||
| return String(localized: "cloudTree.ports.loopback.detail", defaultValue: "These services open in cmux without Cloud VPN. They listen on the machine’s loopback address, so other apps cannot reach them through its private IP, even with VPN connected.") | ||
| case .empty(.noListeningService): | ||
| return String(localized: "cloudTree.ports.empty.noService", defaultValue: "Start a web server on this machine, then refresh.") | ||
| case .empty(.otherInterfaceOnly): | ||
| return String(localized: "cloudTree.ports.binding.detail", defaultValue: "cmux’s browser route connects to 127.0.0.1 on the machine. Bind the service to 127.0.0.1 or 0.0.0.0, then refresh. Turning on Cloud VPN does not change this route.") | ||
| case .unavailable(.privateAddress): | ||
| return String(localized: "cloudTree.ports.privateAddress.detail", defaultValue: "cmux’s authenticated route needs this machine’s private address. Refresh to retrieve it. Turning on Cloud VPN does not assign a missing address.") | ||
| case .unavailable(.machineAsleep): | ||
| return String(localized: "cloudTree.ports.asleep.detail", defaultValue: "Wake the machine to check its services. cmux’s in-app forwarding does not need Cloud VPN.") | ||
| case .unavailable(.link): | ||
| return String(localized: "cloudTree.ports.link.detail", defaultValue: "Port discovery could not connect to this machine. Existing cmux ports may still work. Refresh to reconnect; Cloud VPN is not required.") | ||
| case .unavailable(.transport): | ||
| return String(localized: "cloudTree.ports.unavailable.detail", defaultValue: "The port scan failed; this does not mean no service is listening. Existing cmux ports may still work. Refresh to retry; Cloud VPN is not required.") | ||
| case .unavailable(.hub): | ||
| return String(localized: "cloudTree.ports.hub.detail", defaultValue: "This build cannot start cmux’s authenticated Cloud forward. Update cmux, then retry.") | ||
| case .stale: | ||
| return String(localized: "cloudTree.ports.stale.detail", defaultValue: "The last scan could not be refreshed. Listed services may have changed; refresh to check again. cmux forwarding does not need Cloud VPN.") | ||
| case .unsupported: | ||
| return String(localized: "cloudTree.ports.unsupported.detail", defaultValue: "This provider has no supported in-app port route. Open a shell to access the service inside the machine. Cloud VPN does not add provider support.") | ||
| } | ||
| } | ||
|
|
||
| public static var routeNote: String { | ||
| String(localized: "cloudTree.ports.routeNote", defaultValue: "cmux forwards ports without Cloud VPN. Web browsers and other Mac apps need Cloud VPN to reach services bound to the machine’s private address.") | ||
| } | ||
|
|
||
| public var action: CloudPortsStatusAction { | ||
| if isVPNGuidance { return .setupVPN } | ||
| switch state { | ||
| case .unavailable(.machineAsleep): return .openMachine | ||
| case .unsupported: return .openShell | ||
| case .loading, .available, .loopbackOnly: return .none | ||
| default: return .refresh | ||
| } | ||
| } | ||
|
|
||
| public var actionTitle: String? { | ||
| switch action { | ||
| case .none: return nil | ||
| case .refresh: return String(localized: "cloudTree.menu.refresh", defaultValue: "Refresh") | ||
| case .setupVPN: return String(localized: "cloudTree.ports.setupVPN", defaultValue: "Set Up VPN…") | ||
| case .openMachine: return String(localized: "cloudTree.ports.action.wake", defaultValue: "Wake Machine") | ||
| case .openShell: return String(localized: "machines.menu.openShell", defaultValue: "Open Shell") | ||
| } | ||
| } | ||
|
|
||
| public var style: CloudTreePlaceholder.Style { | ||
| if isVPNGuidance { return .dimmed } | ||
| switch state { | ||
| case .loading: return .connecting | ||
| case .unavailable(.machineAsleep), .notRequested, .available, .loopbackOnly, .empty, .unsupported: return .dimmed | ||
| case .unavailable, .stale: return .error | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
...es/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Environment/CloudMachinesPlanSummary.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| /// Snapshot of the caller's Cloud Machines plan for the settings section. | ||
| public struct CloudMachinesPlanSummary: Equatable, Sendable { | ||
| /// Localized display name of the current plan. | ||
| public let planLabel: String | ||
| /// Number of machines currently counted against the plan. | ||
| public let activeMachines: Int | ||
| /// Active-machine ceiling; nil when the plan has no cap. | ||
| public let maxMachines: Int? | ||
| /// Whether the plan permits paid machine provisioning. | ||
| public let isPaidPlan: Bool | ||
|
|
||
| /// Creates a plan summary. | ||
| /// - Parameters: | ||
| /// - planLabel: Display name of the plan, already localized. | ||
| /// - activeMachines: Machines currently counted against the plan. | ||
| /// - maxMachines: Active-machine ceiling, or nil when the plan has no cap. | ||
| /// - isPaidPlan: Whether the plan is one the backend provisions for. | ||
| public init(planLabel: String, activeMachines: Int, maxMachines: Int?, isPaidPlan: Bool) { | ||
| self.planLabel = planLabel | ||
| self.activeMachines = activeMachines | ||
| self.maxMachines = maxMachines | ||
| self.isPaidPlan = isPaidPlan | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
...uxSurfaceCatalogModel/Sources/CmuxSurfaceCatalogModel/CloudPortDiscoveryEmptyReason.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import Foundation | ||
|
|
||
| /// Why a completed Cloud scan produced no listeners usable by the authenticated browser proxy. | ||
| public enum CloudPortDiscoveryEmptyReason: String, Codable, Hashable, Sendable { | ||
| case noListeningService = "no_listening_service" | ||
| case otherInterfaceOnly = "other_interface_only" | ||
| } |
45 changes: 45 additions & 0 deletions
45
...cOS/CmuxSurfaceCatalogModel/Sources/CmuxSurfaceCatalogModel/CloudPortDiscoveryState.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import Foundation | ||
|
|
||
| /// The authoritative state of a Cloud machine's demand-driven port scan. | ||
| public enum CloudPortDiscoveryState: Hashable, Codable, Sendable { | ||
| /// Ports have not been requested yet; expanding the Ports group starts a scan. | ||
| case notRequested | ||
| /// A scan is in flight. Existing port rows remain visible while it runs. | ||
| case loading | ||
| /// A completed scan found at least one reachable service. | ||
| case available | ||
| /// The proxy can open these services; a system VPN cannot reach their loopback-only bindings. | ||
| case loopbackOnly | ||
| /// A completed scan found no service that cmux can reach. | ||
| case empty(CloudPortDiscoveryEmptyReason) | ||
| /// The scan or the route could not be used to produce a trustworthy result. | ||
| case unavailable(CloudPortDiscoveryUnavailableReason) | ||
| /// The last graph is retained, but a reconnect or refresh no longer proves it current. | ||
| case stale | ||
| /// The provider does not advertise Cloud port discovery or preview support. | ||
| case unsupported | ||
|
|
||
| /// Whether the Ports group should keep a status row after real port rows. | ||
| public var keepsStatusAlongsideRows: Bool { | ||
| switch self { | ||
| case .unavailable, .stale, .unsupported, .loading: | ||
| return true | ||
| case .notRequested, .available, .loopbackOnly, .empty: | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| /// Stable, nonlocalized value used by socket exports and diagnostics. | ||
| public var wireValue: String { | ||
| switch self { | ||
| case .notRequested: return "not_requested" | ||
| case .loading: return "loading" | ||
| case .available: return "available" | ||
| case .loopbackOnly: return "loopback_only" | ||
| case .empty(let reason): return "empty_\(reason.rawValue)" | ||
| case .unavailable(let reason): return "unavailable_\(reason.rawValue)" | ||
| case .stale: return "stale" | ||
| case .unsupported: return "unsupported" | ||
| } | ||
| } | ||
| } |
10 changes: 10 additions & 0 deletions
10
...aceCatalogModel/Sources/CmuxSurfaceCatalogModel/CloudPortDiscoveryUnavailableReason.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import Foundation | ||
|
|
||
| /// Why Cloud port discovery or its in-app route is currently unavailable. | ||
| public enum CloudPortDiscoveryUnavailableReason: String, Codable, Hashable, Sendable { | ||
| case link | ||
| case transport | ||
| case privateAddress = "private_address" | ||
| case machineAsleep = "machine_asleep" | ||
| case hub | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.