Skip to content

Commit ae718ed

Browse files
authored
Merge pull request coder#112 from coder/impl-image-resolver
Impl: use template icons for workspaces
2 parents 51cffae + 0b42002 commit ae718ed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+288
-76
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
### Added
88
- warning system when plugin might not be compatible with Coder REST API
99
- a `Create workspace` button which links to Coder's templates page
10+
- workspace icons
1011

1112
### Changed
1213
- redesigned the information&warning banner. Messages can now include hyperlinks
1314

1415
### Fixed
1516
- outdated Coder CLI binaries are cleaned up
1617
- workspace status color style: running workspaces are green, failed ones should be red, everything else is gray
18+
- typos in plugin description
1719

1820
## 2.1.2 - 2022-11-23
1921

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Follow](https://img.shields.io/twitter/follow/CoderHQ?label=%40CoderHQ&style=soc
77
[![Coder Gateway Plugin Build](https://github.com/coder/coder-jetbrains/actions/workflows/build.yml/badge.svg)](https://github.com/coder/coder-jetbrains/actions/workflows/build.yml)
88

99
<!-- Plugin description -->
10-
**Coder Gateway** connects your Jetbrains IDE to your [Coder Workspaces](https://coder.com/docs/coder-oss/latest/workspaces) so that you can develop from anywhere.
10+
**Coder Gateway** connects your JetBrains IDE to your [Coder Workspaces](https://coder.com/docs/coder-oss/latest/workspaces) so that you can develop from anywhere.
1111

1212
**Manage less**
1313

src/main/kotlin/com/coder/gateway/icons/CoderIcons.kt

+38-8
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,53 @@ import com.intellij.openapi.util.IconLoader
55
object CoderIcons {
66
val LOGO = IconLoader.getIcon("coder_logo.svg", javaClass)
77
val LOGO_16 = IconLoader.getIcon("coder_logo_16.svg", javaClass)
8-
val LOGO_52 = IconLoader.getIcon("coder_logo_52.svg", javaClass)
98

109
val OPEN_TERMINAL = IconLoader.getIcon("open_terminal.svg", javaClass)
1110

1211
val CREATE = IconLoader.getIcon("create.svg", javaClass)
1312
val RUN = IconLoader.getIcon("run.svg", javaClass)
1413
val STOP = IconLoader.getIcon("stop.svg", javaClass)
1514
val UPDATE = IconLoader.getIcon("update.svg", javaClass)
15+
val DELETE = IconLoader.getIcon("delete.svg", javaClass)
1616

17-
val WINDOWS = IconLoader.getIcon("windows.svg", javaClass)
18-
val MACOS = IconLoader.getIcon("macOS.svg", javaClass)
19-
val LINUX = IconLoader.getIcon("linux.svg", javaClass)
2017
val UNKNOWN = IconLoader.getIcon("unknown.svg", javaClass)
2118

22-
val GREEN_CIRCLE = IconLoader.getIcon("green_circle.svg", javaClass)
23-
val GRAY_CIRCLE = IconLoader.getIcon("gray_circle.svg", javaClass)
24-
val RED_CIRCLE = IconLoader.getIcon("red_circle.svg", javaClass)
19+
val ZERO = IconLoader.getIcon("0.svg", javaClass)
20+
val ONE = IconLoader.getIcon("1.svg", javaClass)
21+
val TWO = IconLoader.getIcon("2.svg", javaClass)
22+
val THREE = IconLoader.getIcon("3.svg", javaClass)
23+
val FOUR = IconLoader.getIcon("4.svg", javaClass)
24+
val FIVE = IconLoader.getIcon("5.svg", javaClass)
25+
val SIX = IconLoader.getIcon("6.svg", javaClass)
26+
val SEVEN = IconLoader.getIcon("7.svg", javaClass)
27+
val EIGHT = IconLoader.getIcon("8.svg", javaClass)
28+
val NINE = IconLoader.getIcon("9.svg", javaClass)
29+
30+
val A = IconLoader.getIcon("a.svg", javaClass)
31+
val B = IconLoader.getIcon("b.svg", javaClass)
32+
val C = IconLoader.getIcon("c.svg", javaClass)
33+
val D = IconLoader.getIcon("d.svg", javaClass)
34+
val E = IconLoader.getIcon("e.svg", javaClass)
35+
val F = IconLoader.getIcon("f.svg", javaClass)
36+
val G = IconLoader.getIcon("g.svg", javaClass)
37+
val H = IconLoader.getIcon("h.svg", javaClass)
38+
val I = IconLoader.getIcon("i.svg", javaClass)
39+
val J = IconLoader.getIcon("j.svg", javaClass)
40+
val K = IconLoader.getIcon("k.svg", javaClass)
41+
val L = IconLoader.getIcon("l.svg", javaClass)
42+
val M = IconLoader.getIcon("m.svg", javaClass)
43+
val N = IconLoader.getIcon("n.svg", javaClass)
44+
val O = IconLoader.getIcon("o.svg", javaClass)
45+
val P = IconLoader.getIcon("p.svg", javaClass)
46+
val Q = IconLoader.getIcon("q.svg", javaClass)
47+
val R = IconLoader.getIcon("r.svg", javaClass)
48+
val S = IconLoader.getIcon("s.svg", javaClass)
49+
val T = IconLoader.getIcon("t.svg", javaClass)
50+
val U = IconLoader.getIcon("u.svg", javaClass)
51+
val V = IconLoader.getIcon("v.svg", javaClass)
52+
val W = IconLoader.getIcon("w.svg", javaClass)
53+
val X = IconLoader.getIcon("x.svg", javaClass)
54+
val Y = IconLoader.getIcon("y.svg", javaClass)
55+
val Z = IconLoader.getIcon("z.svg", javaClass)
2556

26-
val DELETE = IconLoader.getIcon("delete.svg", javaClass)
2757
}

src/main/kotlin/com/coder/gateway/models/WorkspaceAgentModel.kt

+2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import com.coder.gateway.sdk.Arch
44
import com.coder.gateway.sdk.OS
55
import com.coder.gateway.sdk.v2.models.WorkspaceTransition
66
import java.util.UUID
7+
import javax.swing.Icon
78

89
data class WorkspaceAgentModel(
910
val workspaceID: UUID,
1011
val workspaceName: String,
1112
val name: String,
1213
val templateID: UUID,
1314
val templateName: String,
15+
val templateIcon: Icon,
1416
val status: WorkspaceVersionStatus,
1517
val agentStatus: WorkspaceAgentStatus,
1618
val lastBuildTransition: WorkspaceTransition,

src/main/kotlin/com/coder/gateway/sdk/CoderRestClientService.kt

+6-6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import java.util.UUID
2828

2929
@Service(Service.Level.APP)
3030
class CoderRestClientService {
31+
private lateinit var httpClient: OkHttpClient
3132
private lateinit var retroRestClient: CoderV2RestFacade
3233
private lateinit var sessionToken: String
3334
lateinit var coderURL: URL
@@ -43,15 +44,14 @@ class CoderRestClientService {
4344
.registerTypeAdapter(Instant::class.java, InstantConverter())
4445
.setPrettyPrinting()
4546
.create()
47+
httpClient = OkHttpClient.Builder()
48+
.addInterceptor { it.proceed(it.request().newBuilder().addHeader("Coder-Session-Token", token).build()) }
49+
.addInterceptor(HttpLoggingInterceptor().apply { setLevel(HttpLoggingInterceptor.Level.BASIC) })
50+
.build()
4651

4752
retroRestClient = Retrofit.Builder()
4853
.baseUrl(url.toString())
49-
.client(
50-
OkHttpClient.Builder()
51-
.addInterceptor { it.proceed(it.request().newBuilder().addHeader("Coder-Session-Token", token).build()) }
52-
.addInterceptor(HttpLoggingInterceptor().apply { setLevel(HttpLoggingInterceptor.Level.BASIC) })
53-
.build()
54-
)
54+
.client(httpClient)
5555
.addConverterFactory(GsonConverterFactory.create(gson))
5656
.build()
5757
.create(CoderV2RestFacade::class.java)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.coder.gateway.sdk
2+
3+
import com.coder.gateway.icons.CoderIcons
4+
import com.intellij.openapi.components.Service
5+
import com.intellij.openapi.components.service
6+
import com.intellij.ui.scale.ScaleContext
7+
import com.intellij.util.ImageLoader
8+
import com.intellij.util.ui.ImageUtil
9+
import java.net.URL
10+
import javax.swing.Icon
11+
import javax.swing.ImageIcon
12+
13+
@Service(Service.Level.APP)
14+
class TemplateIconDownloader {
15+
private val coderClient: CoderRestClientService = service()
16+
17+
fun load(path: String, templateName: String): Icon {
18+
var url: URL? = null
19+
if (path.startsWith("http")) {
20+
url = path.toURL()
21+
} else if (path.contains(coderClient.coderURL.host)) {
22+
url = coderClient.coderURL.withPath(path)
23+
}
24+
25+
if (url != null) {
26+
var img = ImageLoader.loadFromUrl(url)
27+
if (img != null) {
28+
if (ImageUtil.getRealHeight(img) > 32 && ImageUtil.getRealWidth(img) > 32) {
29+
img = ImageUtil.resize(img, 32, ScaleContext.create())
30+
}
31+
return ImageIcon(img)
32+
}
33+
}
34+
35+
return iconForChar(templateName.lowercase().first())
36+
}
37+
38+
private fun iconForChar(c: Char) = when (c) {
39+
'0' -> CoderIcons.ZERO
40+
'1' -> CoderIcons.ONE
41+
'2' -> CoderIcons.TWO
42+
'3' -> CoderIcons.THREE
43+
'4' -> CoderIcons.FOUR
44+
'5' -> CoderIcons.FIVE
45+
'6' -> CoderIcons.SIX
46+
'7' -> CoderIcons.SEVEN
47+
'8' -> CoderIcons.EIGHT
48+
'9' -> CoderIcons.NINE
49+
50+
'a' -> CoderIcons.A
51+
'b' -> CoderIcons.B
52+
'c' -> CoderIcons.C
53+
'd' -> CoderIcons.D
54+
'e' -> CoderIcons.E
55+
'f' -> CoderIcons.F
56+
'g' -> CoderIcons.G
57+
'h' -> CoderIcons.H
58+
'i' -> CoderIcons.I
59+
'j' -> CoderIcons.J
60+
'k' -> CoderIcons.K
61+
'l' -> CoderIcons.L
62+
'm' -> CoderIcons.M
63+
'n' -> CoderIcons.N
64+
'o' -> CoderIcons.O
65+
'p' -> CoderIcons.P
66+
'q' -> CoderIcons.Q
67+
'r' -> CoderIcons.R
68+
's' -> CoderIcons.S
69+
't' -> CoderIcons.T
70+
'u' -> CoderIcons.U
71+
'v' -> CoderIcons.V
72+
'w' -> CoderIcons.W
73+
'x' -> CoderIcons.X
74+
'y' -> CoderIcons.Y
75+
'z' -> CoderIcons.Z
76+
77+
else -> CoderIcons.UNKNOWN
78+
}
79+
80+
}

src/main/kotlin/com/coder/gateway/views/steps/CoderWorkspacesStepView.kt

+13-6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.coder.gateway.sdk.CoderCLIManager
1515
import com.coder.gateway.sdk.CoderRestClientService
1616
import com.coder.gateway.sdk.CoderSemVer
1717
import com.coder.gateway.sdk.OS
18+
import com.coder.gateway.sdk.TemplateIconDownloader
1819
import com.coder.gateway.sdk.ex.AuthenticationResponseException
1920
import com.coder.gateway.sdk.ex.TemplateResponseException
2021
import com.coder.gateway.sdk.ex.WorkspaceResponseException
@@ -83,6 +84,8 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
8384
private val cs = CoroutineScope(Dispatchers.Main)
8485
private var localWizardModel = CoderWorkspacesWizardModel()
8586
private val coderClient: CoderRestClientService = service()
87+
private val iconDownloader: TemplateIconDownloader = service()
88+
8689
private val appPropertiesService: PropertiesComponent = service()
8790

8891
private var tfUrl: JTextField? = null
@@ -448,6 +451,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
448451
this.name,
449452
this.templateID,
450453
this.templateName,
454+
iconDownloader.load(this@agentModels.templateIcon, this.name),
451455
WorkspaceVersionStatus.from(this),
452456
WorkspaceAgentStatus.from(this),
453457
this.latestBuild.transition,
@@ -466,6 +470,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
466470
workspaceWithAgentName,
467471
this.templateID,
468472
this.templateName,
473+
iconDownloader.load(this@agentModels.templateIcon, workspaceWithAgentName),
469474
WorkspaceVersionStatus.from(this),
470475
WorkspaceAgentStatus.from(this),
471476
this.latestBuild.transition,
@@ -484,6 +489,7 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
484489
this.name,
485490
this.templateID,
486491
this.templateName,
492+
iconDownloader.load(this@agentModels.templateIcon, this.name),
487493
WorkspaceVersionStatus.from(this),
488494
WorkspaceAgentStatus.from(this),
489495
this.latestBuild.transition,
@@ -550,15 +556,16 @@ class CoderWorkspacesStepView(val enableNextButtonCallback: (Boolean) -> Unit) :
550556
}
551557

552558
override fun getIcon(value: String, table: JTable?, row: Int): Icon {
553-
return when (OS.from(value)) {
554-
OS.LINUX -> CoderIcons.LINUX
555-
OS.WINDOWS -> CoderIcons.WINDOWS
556-
OS.MAC -> CoderIcons.MACOS
557-
else -> CoderIcons.UNKNOWN
558-
}
559+
return item?.templateIcon ?: CoderIcons.UNKNOWN
559560
}
560561

561562
override fun isCenterAlignment() = true
563+
564+
override fun getTableCellRendererComponent(table: JTable?, value: Any?, selected: Boolean, focus: Boolean, row: Int, column: Int): Component {
565+
return super.getTableCellRendererComponent(table, value, selected, focus, row, column).apply {
566+
border = JBUI.Borders.empty(10, 10)
567+
}
568+
}
562569
}
563570
}
564571
}

src/main/resources/0.svg

+4
Loading

src/main/resources/1.svg

+4
Loading

src/main/resources/2.svg

+4
Loading

src/main/resources/3.svg

+4
Loading

src/main/resources/4.svg

+4
Loading

src/main/resources/5.svg

+4
Loading

src/main/resources/6.svg

+4
Loading

src/main/resources/7.svg

+4
Loading

src/main/resources/8.svg

+4
Loading

src/main/resources/9.svg

+4
Loading

src/main/resources/META-INF/plugin.xml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
<extensions defaultExtensionNs="com.intellij">
1515
<applicationService serviceImplementation="com.coder.gateway.sdk.CoderRestClientService"></applicationService>
16+
<applicationService serviceImplementation="com.coder.gateway.sdk.TemplateIconDownloader"></applicationService>
1617
<applicationService serviceImplementation="com.coder.gateway.services.CoderRecentWorkspaceConnectionsService"></applicationService>
1718
</extensions>
1819
<extensions defaultExtensionNs="com.jetbrains">

src/main/resources/a.svg

+4
Loading

src/main/resources/b.svg

+4
Loading

src/main/resources/c.svg

+4
Loading

src/main/resources/coder_logo_52.svg

-15
This file was deleted.

0 commit comments

Comments
 (0)