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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 48 additions & 33 deletions
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

Lines changed: 9 additions & 2 deletions
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

Lines changed: 6 additions & 2 deletions
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

Lines changed: 4 additions & 1 deletion
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy