Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7f9e1b3

Browse files
authored
Fix Coder connect workflows (#2)
- fixes login screen and glitches related jumping to the workspaces pageonce the connection to Coder deployment is estabilished.- support for opening URLs in browser- fixes user agent reporting- fixes connection status rendering
1 parent04f1bd8 commit7f9e1b3

File tree

39 files changed

+325
-170
lines changed

39 files changed

+325
-170
lines changed

‎src/main/kotlin/com/coder/toolbox/CoderGatewayExtension.kt

Lines changed: 0 additions & 28 deletions
This file was deleted.

‎src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
packagecom.coder.toolbox
22

3+
importcom.coder.toolbox.browser.BrowserUtil
34
importcom.coder.toolbox.models.WorkspaceAndAgentStatus
45
importcom.coder.toolbox.sdk.CoderRestClient
56
importcom.coder.toolbox.sdk.v2.models.Workspace
67
importcom.coder.toolbox.sdk.v2.models.WorkspaceAgent
8+
importcom.coder.toolbox.util.withPath
79
importcom.coder.toolbox.views.Action
810
importcom.coder.toolbox.views.EnvironmentView
11+
importcom.jetbrains.toolbox.api.core.ServiceLocator
912
importcom.jetbrains.toolbox.api.remoteDev.AbstractRemoteProviderEnvironment
1013
importcom.jetbrains.toolbox.api.remoteDev.EnvironmentVisibilityState
1114
importcom.jetbrains.toolbox.api.remoteDev.environments.EnvironmentContentsView
1215
importcom.jetbrains.toolbox.api.remoteDev.states.EnvironmentStateConsumer
1316
importcom.jetbrains.toolbox.api.ui.ToolboxUi
17+
importkotlinx.coroutines.CoroutineScope
18+
importkotlinx.coroutines.launch
1419
importjava.util.concurrent.CompletableFuture
1520

1621
/**
@@ -19,32 +24,44 @@ import java.util.concurrent.CompletableFuture
1924
* Used in the environment list view.
2025
*/
2126
classCoderRemoteEnvironment(
27+
privatevalserviceLocator:ServiceLocator,
2228
privatevalclient:CoderRestClient,
2329
privatevarworkspace:Workspace,
2430
privatevaragent:WorkspaceAgent,
25-
privatevalui:ToolboxUi,
31+
privatevarcs:CoroutineScope,
2632
) : AbstractRemoteProviderEnvironment() {
33+
privatevar status=WorkspaceAndAgentStatus.from(workspace, agent)
34+
35+
privateval ui:ToolboxUi= serviceLocator.getService(ToolboxUi::class.java)
2736
overridefungetId():String="${workspace.name}.${agent.name}"
2837
overridefungetName():String="${workspace.name}.${agent.name}"
29-
privatevar status=WorkspaceAndAgentStatus.from(workspace, agent)
3038

3139
init {
3240
actionsList.add(
3341
Action("Open web terminal") {
34-
// TODO - check this later
35-
// ui.openUrl(client.url.withPath("/${workspace.ownerName}/$name/terminal").toString())
42+
cs.launch {
43+
BrowserUtil.browse(client.url.withPath("/${workspace.ownerName}/$name/terminal").toString()) {
44+
ui.showErrorInfoPopup(it)
45+
}
46+
}
3647
},
3748
)
3849
actionsList.add(
3950
Action("Open in dashboard") {
40-
// TODO - check this later
41-
// ui.openUrl(client.url.withPath("/@${workspace.ownerName}/${workspace.name}").toString())
51+
cs.launch {
52+
BrowserUtil.browse(client.url.withPath("/@${workspace.ownerName}/${workspace.name}").toString()) {
53+
ui.showErrorInfoPopup(it)
54+
}
55+
}
4256
},
4357
)
4458
actionsList.add(
4559
Action("View template") {
46-
// TODO - check this later
47-
// ui.openUrl(client.url.withPath("/templates/${workspace.templateName}").toString())
60+
cs.launch {
61+
BrowserUtil.browse(client.url.withPath("/templates/${workspace.templateName}").toString()) {
62+
ui.showErrorInfoPopup(it)
63+
}
64+
}
4865
},
4966
)
5067
actionsList.add(
@@ -79,7 +96,7 @@ class CoderRemoteEnvironment(
7996
val newStatus=WorkspaceAndAgentStatus.from(workspace, agent)
8097
if (newStatus!= status) {
8198
status= newStatus
82-
val state= status.toRemoteEnvironmentState()
99+
val state= status.toRemoteEnvironmentState(serviceLocator)
83100
listenerSet.forEach { it.consume(state) }
84101
}
85102
}
@@ -108,7 +125,7 @@ class CoderRemoteEnvironment(
108125
// connected state can mask the workspace state.
109126
// TODO@JB: You can still press connect if the environment is
110127
// unreachable. Is that expected?
111-
consumer.consume(status.toRemoteEnvironmentState())
128+
consumer.consume(status.toRemoteEnvironmentState(serviceLocator))
112129
returnsuper.addStateListener(consumer)
113130
}
114131

‎src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ import com.coder.toolbox.views.SignInPage
1818
importcom.coder.toolbox.views.TokenPage
1919
importcom.jetbrains.toolbox.api.core.PluginSecretStore
2020
importcom.jetbrains.toolbox.api.core.PluginSettingsStore
21+
importcom.jetbrains.toolbox.api.core.ServiceLocator
2122
importcom.jetbrains.toolbox.api.core.ui.icons.SvgIcon
2223
importcom.jetbrains.toolbox.api.remoteDev.ProviderVisibilityState
2324
importcom.jetbrains.toolbox.api.remoteDev.RemoteEnvironmentConsumer
2425
importcom.jetbrains.toolbox.api.remoteDev.RemoteProvider
26+
importcom.jetbrains.toolbox.api.remoteDev.ui.EnvironmentUiPageManager
2527
importcom.jetbrains.toolbox.api.ui.ToolboxUi
2628
importcom.jetbrains.toolbox.api.ui.actions.RunnableActionDescription
2729
importcom.jetbrains.toolbox.api.ui.components.AccountDropdownField
@@ -39,15 +41,17 @@ import kotlin.coroutines.cancellation.CancellationException
3941
importkotlin.time.Duration.Companion.seconds
4042

4143
classCoderRemoteProvider(
44+
privatevalserviceLocator:ServiceLocator,
4245
privatevalhttpClient:OkHttpClient,
43-
privatevalconsumer:RemoteEnvironmentConsumer,
44-
privatevalcoroutineScope:CoroutineScope,
45-
privatevalui:ToolboxUi,
46-
settingsStore:PluginSettingsStore,
47-
secretsStore:PluginSecretStore,
4846
) : RemoteProvider {
4947
privateval logger=LoggerFactory.getLogger(javaClass)
5048

49+
privateval ui:ToolboxUi= serviceLocator.getService(ToolboxUi::class.java)
50+
privateval consumer:RemoteEnvironmentConsumer= serviceLocator.getService(RemoteEnvironmentConsumer::class.java)
51+
privateval coroutineScope:CoroutineScope= serviceLocator.getService(CoroutineScope::class.java)
52+
privateval settingsStore:PluginSettingsStore= serviceLocator.getService(PluginSettingsStore::class.java)
53+
privateval secretsStore:PluginSecretStore= serviceLocator.getService(PluginSecretStore::class.java)
54+
5155
// Current polling job.
5256
privatevar pollJob:Job?=null
5357
privatevar lastEnvironments:Set<CoderRemoteEnvironment>?=null
@@ -60,7 +64,7 @@ class CoderRemoteProvider(
6064
privateval dialogUi=DialogUi(settings, ui)
6165
privateval linkHandler=LinkHandler(settings, httpClient, dialogUi)
6266

63-
// The REST client, if we are signed in.
67+
// The REST client, if we are signed in
6468
privatevar client:CoderRestClient?=null
6569

6670
// If we have an error in the polling we store it here before going back to
@@ -96,7 +100,7 @@ class CoderRemoteProvider(
96100
it.name
97101
}?.map { agent->
98102
// If we have an environment already, update that.
99-
val env=CoderRemoteEnvironment(client, ws, agent,ui)
103+
val env=CoderRemoteEnvironment(serviceLocator,client, ws, agent,coroutineScope)
100104
lastEnvironments?.firstOrNull { it== env }?.let {
101105
it.update(ws, agent)
102106
it
@@ -146,7 +150,6 @@ class CoderRemoteProvider(
146150
// rememberMe to false so we do not try to automatically log in.
147151
secrets.rememberMe="false"
148152
close()
149-
reset()
150153
}
151154

152155
/**
@@ -182,7 +185,7 @@ class CoderRemoteProvider(
182185
consumer.consumeEnvironments(emptyList(),true)
183186
}
184187

185-
overridefungetName():String="Coder Gateway"
188+
overridefungetName():String="Coder"
186189
overridefungetSvgIcon():SvgIcon=
187190
SvgIcon(this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes()?: byteArrayOf())
188191

@@ -208,7 +211,7 @@ class CoderRemoteProvider(
208211
* Just displays the deployment URL at the moment, but we could use this as
209212
* a form for creating new environments.
210213
*/
211-
overridefungetNewEnvironmentUiPage():UiPage=NewEnvironmentPage(client?.url?.toString())
214+
overridefungetNewEnvironmentUiPage():UiPage=NewEnvironmentPage(getDeploymentURL()?.first)
212215

213216
/**
214217
* We always show a list of environments.
@@ -251,9 +254,8 @@ class CoderRemoteProvider(
251254
* ui.hideUiPage() which stacks and has built-in back navigation, rather
252255
* than using multiple root pages.
253256
*/
254-
privatefunreset() {
255-
// TODO - check this later
256-
// ui.showPluginEnvironmentsPage()
257+
privatefungoToEnvironmentsPage() {
258+
serviceLocator.getService(EnvironmentUiPageManager::class.java).showPluginEnvironmentsPage()
257259
}
258260

259261
/**
@@ -309,7 +311,7 @@ class CoderRemoteProvider(
309311
settings,
310312
httpClient,
311313
coroutineScope,
312-
{ reset() },
314+
::goToEnvironmentsPage,
313315
) { client, cli->
314316
// Store the URL and token for use next time.
315317
secrets.lastDeploymentURL= client.url.toString()
@@ -320,7 +322,7 @@ class CoderRemoteProvider(
320322
pollError=null
321323
pollJob?.cancel()
322324
pollJob= poll(client, cli)
323-
reset()
325+
goToEnvironmentsPage()
324326
}
325327

326328
/**
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
packagecom.coder.toolbox
2+
3+
importcom.jetbrains.toolbox.api.core.ServiceLocator
4+
importcom.jetbrains.toolbox.api.remoteDev.RemoteDevExtension
5+
importcom.jetbrains.toolbox.api.remoteDev.RemoteProvider
6+
importokhttp3.OkHttpClient
7+
8+
/**
9+
* Entry point into the extension.
10+
*/
11+
classCoderToolboxExtension :RemoteDevExtension {
12+
// All services must be passed in here and threaded as necessary.
13+
overridefuncreateRemoteProviderPluginInstance(serviceLocator:ServiceLocator):RemoteProvider {
14+
returnCoderRemoteProvider(
15+
serviceLocator,
16+
OkHttpClient(),
17+
)
18+
}
19+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
packagecom.coder.toolbox.browser
2+
3+
importjava.io.IOException
4+
5+
classBrowserException(msg:String,error:Throwable? =null) : IOException(msg, error)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
packagecom.coder.toolbox.browser
2+
3+
importcom.coder.toolbox.util.OS
4+
importcom.coder.toolbox.util.getOS
5+
importorg.zeroturnaround.exec.ProcessExecutor
6+
7+
classBrowserUtil {
8+
companionobject {
9+
funbrowse(url:String,errorHandler: (BrowserException)->Unit) {
10+
val os= getOS()
11+
if (os==null) {
12+
errorHandler(BrowserException("Failed to open the URL because we can't detect the OS"))
13+
return
14+
}
15+
when (os) {
16+
OS.LINUX-> linuxBrowse(url, errorHandler)
17+
OS.MAC-> macBrowse(url, errorHandler)
18+
OS.WINDOWS-> windowsBrowse(url, errorHandler)
19+
}
20+
}
21+
22+
privatefunlinuxBrowse(url:String,errorHandler: (BrowserException)->Unit) {
23+
try {
24+
if (OS.LINUX.getDesktopEnvironment()?.uppercase()?.contains("GNOME")==true) {
25+
exec("gnome-open", url)
26+
}else {
27+
exec("xdg-open", url)
28+
}
29+
}catch (e:Exception) {
30+
errorHandler(
31+
BrowserException(
32+
"Failed to open URL because an error was encountered. Please make sure xdg-open from package xdg-utils is available!",
33+
e
34+
)
35+
)
36+
}
37+
}
38+
39+
privatefunmacBrowse(url:String,errorHandler: (BrowserException)->Unit) {
40+
try {
41+
exec("open", url)
42+
}catch (e:Exception) {
43+
errorHandler(BrowserException("Failed to open URL because an error was encountered.", e))
44+
}
45+
}
46+
47+
privatefunwindowsBrowse(url:String,errorHandler: (BrowserException)->Unit) {
48+
try {
49+
exec("cmd","start\"$url\"")
50+
}catch (e:Exception) {
51+
errorHandler(BrowserException("Failed to open URL because an error was encountered.", e))
52+
}
53+
}
54+
55+
privatefunexec(varargargs:String):String {
56+
val stdout=
57+
ProcessExecutor()
58+
.command(*args)
59+
.exitValues(0)
60+
.readOutput(true)
61+
.execute()
62+
.outputUTF8()
63+
return stdout
64+
}
65+
}
66+
}

‎src/main/kotlin/com/coder/toolbox/models/WorkspaceAndAgentStatus.kt

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import com.coder.toolbox.sdk.v2.models.WorkspaceAgent
55
importcom.coder.toolbox.sdk.v2.models.WorkspaceAgentLifecycleState
66
importcom.coder.toolbox.sdk.v2.models.WorkspaceAgentStatus
77
importcom.coder.toolbox.sdk.v2.models.WorkspaceStatus
8-
importcom.jetbrains.toolbox.api.core.ui.color.Color
8+
importcom.jetbrains.toolbox.api.core.ServiceLocator
99
importcom.jetbrains.toolbox.api.core.ui.color.StateColor
10-
importcom.jetbrains.toolbox.api.core.ui.color.ThemeColor
1110
importcom.jetbrains.toolbox.api.remoteDev.states.CustomRemoteEnvironmentState
11+
importcom.jetbrains.toolbox.api.remoteDev.states.EnvironmentStateColorPalette
12+
importcom.jetbrains.toolbox.api.remoteDev.states.StandardRemoteEnvironmentState
1213

1314
/**
1415
* WorkspaceAndAgentStatus represents the combined status of a single agent and
@@ -57,27 +58,27 @@ enum class WorkspaceAndAgentStatus(val label: String, val description: String) {
5758
* Note that a reachable environment will always display "connected" or
5859
* "disconnected" regardless of the label we give that status.
5960
*/
60-
funtoRemoteEnvironmentState():CustomRemoteEnvironmentState {
61-
// Use comments; no named arguments for non-Kotlin functions.
62-
// TODO@JB: Is there a set of default colors we could use?
61+
funtoRemoteEnvironmentState(serviceLocator:ServiceLocator):CustomRemoteEnvironmentState {
62+
val stateColor= getStateColor(serviceLocator)
6363
returnCustomRemoteEnvironmentState(
6464
label,
65-
StateColor(
66-
ThemeColor(
67-
Color(0.407f,0.439f,0.502f,1.0f),// lightThemeColor
68-
Color(0.784f,0.784f,0.784f,0.784f),// darkThemeColor
69-
),
70-
ThemeColor(
71-
Color(0.878f,0.878f,0.941f,0.102f),// darkThemeBackgroundColor
72-
Color(0.878f,0.878f,0.961f,0.980f),// lightThemeBackgroundColor
73-
)
74-
),
65+
stateColor,
7566
ready(),// reachable
7667
// TODO@JB: How does this work? Would like a spinner for pending states.
7768
null,// iconId
7869
)
7970
}
8071

72+
privatefungetStateColor(serviceLocator:ServiceLocator):StateColor {
73+
val colorPalette= serviceLocator.getService(EnvironmentStateColorPalette::class.java)
74+
75+
76+
returnif (ready()) colorPalette.getColor(StandardRemoteEnvironmentState.Active)
77+
elseif (canStart()) colorPalette.getColor(StandardRemoteEnvironmentState.Failed)
78+
elseif (pending()) colorPalette.getColor(StandardRemoteEnvironmentState.Activating)
79+
else colorPalette.getColor(StandardRemoteEnvironmentState.Unreachable)
80+
}
81+
8182
/**
8283
* Return true if the agent is in a connectable state.
8384
*/
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
packagecom.coder.toolbox.plugin
2+
3+
importcom.squareup.moshi.Json
4+
importcom.squareup.moshi.JsonClass
5+
6+
/**
7+
* Small subset representation of extension.json
8+
*/
9+
@JsonClass(generateAdapter=true)
10+
data classPluginInfo(
11+
@Json(name="id")valid:String,
12+
@Json(name="version")valversion:String)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp