Skip to content

Commit 2b18fe4

Browse files
authored
Impl: icons with support for light&dark themes (#32)
- LAF support in Toolbox is quite primitive, it turns out icon support for light and dark themes is enabled by a masked flag on the icons. - the mask flag controls whether the svg colors are inverted in light&dark themes. Among other things we also fixed and issue with the `Start` button which remained active when a workspace was stopped and outdated. In order to be more consistent with the web client we renamed the button to `Update and start` to reflect that it also starts the workspace. Running and outdated workspaces also received a new action button: `Update and restart`. - resolves #31 ![image](https://github.com/user-attachments/assets/f54a71f4-ca8d-4655-b5ff-e95c52e3ad9a) ![image](https://github.com/user-attachments/assets/a81901ac-b7fe-482d-bf09-13baaa02455b)
1 parent 5fcef9b commit 2b18fe4

File tree

5 files changed

+69
-39
lines changed

5 files changed

+69
-39
lines changed

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
### Added
66

77
- initial support for JetBrains Toolbox 2.6.0.38311 with the possibility to manage the workspaces - i.e. start, stop,
8-
update and delete actions and also quick shortcuts to templates, web terminal and dashboard.
8+
update and delete actions and also quick shortcuts to templates, web terminal and dashboard.
9+
- support for light & dark themes

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

+48-33
Original file line numberDiff line numberDiff line change
@@ -45,44 +45,59 @@ class CoderRemoteEnvironment(
4545

4646
override val actionsList: MutableStateFlow<List<ActionDescription>> = MutableStateFlow(getAvailableActions())
4747

48-
private fun getAvailableActions(): List<ActionDescription> = listOf(
49-
Action(context.i18n.ptrl("Open web terminal")) {
50-
context.cs.launch {
51-
BrowserUtil.browse(client.url.withPath("/${workspace.ownerName}/$name/terminal").toString()) {
52-
context.ui.showErrorInfoPopup(it)
48+
private fun getAvailableActions(): List<ActionDescription> {
49+
val actions = mutableListOf(
50+
Action(context.i18n.ptrl("Open web terminal")) {
51+
context.cs.launch {
52+
BrowserUtil.browse(client.url.withPath("/${workspace.ownerName}/$name/terminal").toString()) {
53+
context.ui.showErrorInfoPopup(it)
54+
}
5355
}
54-
}
55-
},
56-
Action(context.i18n.ptrl("Open in dashboard")) {
57-
context.cs.launch {
58-
BrowserUtil.browse(client.url.withPath("/@${workspace.ownerName}/${workspace.name}").toString()) {
59-
context.ui.showErrorInfoPopup(it)
56+
},
57+
Action(context.i18n.ptrl("Open in dashboard")) {
58+
context.cs.launch {
59+
BrowserUtil.browse(client.url.withPath("/@${workspace.ownerName}/${workspace.name}").toString()) {
60+
context.ui.showErrorInfoPopup(it)
61+
}
6062
}
61-
}
62-
},
63+
},
6364

64-
Action(context.i18n.ptrl("View template")) {
65-
context.cs.launch {
66-
BrowserUtil.browse(client.url.withPath("/templates/${workspace.templateName}").toString()) {
67-
context.ui.showErrorInfoPopup(it)
65+
Action(context.i18n.ptrl("View template")) {
66+
context.cs.launch {
67+
BrowserUtil.browse(client.url.withPath("/templates/${workspace.templateName}").toString()) {
68+
context.ui.showErrorInfoPopup(it)
69+
}
6870
}
71+
})
72+
73+
if (wsRawStatus.canStart()) {
74+
if (workspace.outdated) {
75+
actions.add(Action(context.i18n.ptrl("Update and start")) {
76+
val build = client.updateWorkspace(workspace)
77+
update(workspace.copy(latestBuild = build), agent)
78+
})
79+
} else {
80+
actions.add(Action(context.i18n.ptrl("Start")) {
81+
val build = client.startWorkspace(workspace)
82+
update(workspace.copy(latestBuild = build), agent)
83+
})
6984
}
70-
},
71-
Action(context.i18n.ptrl("Start"), enabled = { wsRawStatus.canStart() }) {
72-
val build = client.startWorkspace(workspace)
73-
workspace = workspace.copy(latestBuild = build)
74-
update(workspace, agent)
75-
},
76-
Action(context.i18n.ptrl("Stop"), enabled = { wsRawStatus.canStop() }) {
77-
val build = client.stopWorkspace(workspace)
78-
workspace = workspace.copy(latestBuild = build)
79-
update(workspace, agent)
80-
},
81-
Action(context.i18n.ptrl("Update"), enabled = { workspace.outdated }) {
82-
val build = client.updateWorkspace(workspace)
83-
workspace = workspace.copy(latestBuild = build)
84-
update(workspace, agent)
85-
})
85+
}
86+
if (wsRawStatus.canStop()) {
87+
if (workspace.outdated) {
88+
actions.add(Action(context.i18n.ptrl("Update and restart")) {
89+
val build = client.updateWorkspace(workspace)
90+
update(workspace.copy(latestBuild = build), agent)
91+
})
92+
} else {
93+
actions.add(Action(context.i18n.ptrl("Stop")) {
94+
val build = client.stopWorkspace(workspace)
95+
update(workspace.copy(latestBuild = build), agent)
96+
})
97+
}
98+
}
99+
return actions
100+
}
86101

87102
/**
88103
* Update the workspace/agent status to the listeners, if it has changed.

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

+9-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.coder.toolbox.views.NewEnvironmentPage
1717
import com.coder.toolbox.views.SignInPage
1818
import com.coder.toolbox.views.TokenPage
1919
import com.jetbrains.toolbox.api.core.ui.icons.SvgIcon
20+
import com.jetbrains.toolbox.api.core.ui.icons.SvgIcon.IconType
2021
import com.jetbrains.toolbox.api.core.util.LoadableState
2122
import com.jetbrains.toolbox.api.remoteDev.ProviderVisibilityState
2223
import com.jetbrains.toolbox.api.remoteDev.RemoteProvider
@@ -181,10 +182,16 @@ class CoderRemoteProvider(
181182
}
182183

183184
override val svgIcon: SvgIcon =
184-
SvgIcon(this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf())
185+
SvgIcon(
186+
this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf(),
187+
type = IconType.Masked
188+
)
185189

186190
override val noEnvironmentsSvgIcon: SvgIcon? =
187-
SvgIcon(this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf())
191+
SvgIcon(
192+
this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf(),
193+
type = IconType.Masked
194+
)
188195

189196
/**
190197
* TODO@JB: It would be nice to show "loading workspaces" at first but it

src/main/kotlin/com/coder/toolbox/views/CoderPage.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.coder.toolbox.views
22

33
import com.coder.toolbox.CoderToolboxContext
44
import com.jetbrains.toolbox.api.core.ui.icons.SvgIcon
5+
import com.jetbrains.toolbox.api.core.ui.icons.SvgIcon.IconType
56
import com.jetbrains.toolbox.api.localization.LocalizableString
67
import com.jetbrains.toolbox.api.ui.actions.RunnableActionDescription
78
import com.jetbrains.toolbox.api.ui.components.UiField
@@ -46,9 +47,12 @@ abstract class CoderPage(
4647
* This seems to only work on the first page.
4748
*/
4849
override val svgIcon: SvgIcon? = if (showIcon) {
49-
SvgIcon(this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf())
50+
SvgIcon(
51+
this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf(),
52+
type = IconType.Masked
53+
)
5054
} else {
51-
SvgIcon(byteArrayOf())
55+
SvgIcon(byteArrayOf(), type = IconType.Masked)
5256
}
5357

5458
/**

src/main/resources/localization/defaultMessages.po

+4-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ msgstr ""
7373
msgid "Stop"
7474
msgstr ""
7575

76-
msgid "Update"
76+
msgid "Update and start"
77+
msgstr ""
78+
79+
msgid "Update and restart"
7780
msgstr ""
7881

7982
msgid "Settings"

0 commit comments

Comments
 (0)