From 203db883ae2c87d9b23312287ac6083af893af2d Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Wed, 21 May 2025 23:56:27 +0300 Subject: [PATCH 1/2] impl: workspace status reporting (color and icons) There were a couple of discrepancies in the status reporting especially around icons and colors: - offline workspaces are marked by a new "offline" icon and a gray color (instead of a half pie icon with a red color) - stopping state now has a gray progress spinner - same for deleting state which previously used the offline icon instead of the spinner. - there was no progress while establishing the SSH connection. Now we have a "SSHing" label with a circular progress bar while connecting to the SSH. --- CHANGELOG.md | 5 +++++ .../coder/toolbox/CoderRemoteEnvironment.kt | 5 +++++ .../toolbox/models/WorkspaceAndAgentStatus.kt | 20 +++++++++++++++---- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f04c9e..e9906ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +### Changed + +- improved workspace status reporting (icon and colors) when it is stopping, deleting, stopped or when we are + establishing the SSH connection. + ## 0.2.2 - 2025-05-21 ### Added diff --git a/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt b/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt index 9effe19..e6118c3 100644 --- a/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt +++ b/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt @@ -157,6 +157,11 @@ class CoderRemoteEnvironment( override fun beforeConnection() { context.logger.info("Connecting to $id...") + context.cs.launch { + state.update { + wsRawStatus.toSshConnectingEnvState(context) + } + } isConnected.update { true } pollJob = pollNetworkMetrics() } diff --git a/src/main/kotlin/com/coder/toolbox/models/WorkspaceAndAgentStatus.kt b/src/main/kotlin/com/coder/toolbox/models/WorkspaceAndAgentStatus.kt index 7a67b36..5d3d4a0 100644 --- a/src/main/kotlin/com/coder/toolbox/models/WorkspaceAndAgentStatus.kt +++ b/src/main/kotlin/com/coder/toolbox/models/WorkspaceAndAgentStatus.kt @@ -11,6 +11,9 @@ import com.jetbrains.toolbox.api.remoteDev.states.CustomRemoteEnvironmentState import com.jetbrains.toolbox.api.remoteDev.states.EnvironmentStateIcons import com.jetbrains.toolbox.api.remoteDev.states.StandardRemoteEnvironmentState + +private val CircularSpinner: EnvironmentStateIcons = EnvironmentStateIcons.Connecting + /** * WorkspaceAndAgentStatus represents the combined status of a single agent and * its workspace (or just the workspace if there are no agents). @@ -71,7 +74,7 @@ enum class WorkspaceAndAgentStatus(val label: String, val description: String) { private fun getStateColor(context: CoderToolboxContext): StateColor { return if (ready()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Active) else if (unhealthy()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Unhealthy) - else if (canStart()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Failed) + else if (canStart() || this == STOPPING) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Hibernating) else if (pending()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Activating) else if (this == DELETING) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Deleting) else if (this == DELETED) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Deleted) @@ -80,12 +83,21 @@ enum class WorkspaceAndAgentStatus(val label: String, val description: String) { private fun getStateIcon(): EnvironmentStateIcons { return if (ready() || unhealthy()) EnvironmentStateIcons.Active - else if (canStart()) EnvironmentStateIcons.Hibernated - else if (pending()) EnvironmentStateIcons.Connecting - else if (this == DELETING || this == DELETED) EnvironmentStateIcons.Offline + else if (canStart()) EnvironmentStateIcons.Offline + else if (pending() || this == DELETING || this == DELETED || this == STOPPING) CircularSpinner else EnvironmentStateIcons.NoIcon } + fun toSshConnectingEnvState(context: CoderToolboxContext): CustomRemoteEnvironmentState { + val existingState = toRemoteEnvironmentState(context) + return CustomRemoteEnvironmentState( + "SSHing", + existingState.color, + existingState.isReachable, + EnvironmentStateIcons.Connecting + ) + } + /** * Return true if the agent is in a connectable state. */ From 74dcd39e9ecc3bccefa9a35d1025e5e6c08ff6ff Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Thu, 22 May 2025 21:27:02 +0300 Subject: [PATCH 2/2] fix: show a red warning icon for failed workspaces Failed workspaces used a gray offline icons. Instead, we now render a red warning icon (exclamation mark). --- CHANGELOG.md | 2 +- .../coder/toolbox/models/WorkspaceAndAgentStatus.kt | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9906ee..9637c92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Changed -- improved workspace status reporting (icon and colors) when it is stopping, deleting, stopped or when we are +- improved workspace status reporting (icon and colors) when it is failed, stopping, deleting, stopped or when we are establishing the SSH connection. ## 0.2.2 - 2025-05-21 diff --git a/src/main/kotlin/com/coder/toolbox/models/WorkspaceAndAgentStatus.kt b/src/main/kotlin/com/coder/toolbox/models/WorkspaceAndAgentStatus.kt index 5d3d4a0..3c9ad5f 100644 --- a/src/main/kotlin/com/coder/toolbox/models/WorkspaceAndAgentStatus.kt +++ b/src/main/kotlin/com/coder/toolbox/models/WorkspaceAndAgentStatus.kt @@ -72,19 +72,21 @@ enum class WorkspaceAndAgentStatus(val label: String, val description: String) { } private fun getStateColor(context: CoderToolboxContext): StateColor { - return if (ready()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Active) + return if (this == FAILED) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.FailedToStart) + else if (this == DELETING) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Deleting) + else if (this == DELETED) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Deleted) + else if (ready()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Active) else if (unhealthy()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Unhealthy) else if (canStart() || this == STOPPING) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Hibernating) else if (pending()) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Activating) - else if (this == DELETING) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Deleting) - else if (this == DELETED) context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Deleted) else context.envStateColorPalette.getColor(StandardRemoteEnvironmentState.Unreachable) } private fun getStateIcon(): EnvironmentStateIcons { - return if (ready() || unhealthy()) EnvironmentStateIcons.Active - else if (canStart()) EnvironmentStateIcons.Offline + return if (this == FAILED) EnvironmentStateIcons.Error else if (pending() || this == DELETING || this == DELETED || this == STOPPING) CircularSpinner + else if (ready() || unhealthy()) EnvironmentStateIcons.Active + else if (canStart()) EnvironmentStateIcons.Offline else EnvironmentStateIcons.NoIcon }