@@ -26,6 +26,11 @@ import java.io.IOException
2626import java.util.concurrent.CancellationException
2727import kotlin.time.Duration.Companion.seconds
2828
29+ data class DevWorkspaceListResult (
30+ val items : List <DevWorkspace >,
31+ val resourceVersion : String?
32+ )
33+
2934class DevWorkspaces (private val client : ApiClient ) {
3035 private val customApi = CustomObjectsApi (client)
3136
@@ -41,8 +46,8 @@ class DevWorkspaces(private val client: ApiClient) {
4146 }
4247
4348 @Throws(ApiException ::class )
44- fun list (namespace : String ): List < DevWorkspace > {
45- try {
49+ fun listWithResult (namespace : String ): DevWorkspaceListResult {
50+ try {
4651 val response = customApi.listNamespacedCustomObject(
4752 " workspace.devfile.io" ,
4853 " v1alpha2" ,
@@ -52,12 +57,12 @@ class DevWorkspaces(private val client: ApiClient) {
5257
5358 val devWorkspaceTemplateMap = getDevWorkspaceTemplateMap(namespace)
5459 val dwItems = Utils .getValue(response, arrayOf(" items" )) as List <* >
55- return dwItems
56- .stream()
60+ val dwList = dwItems
5761 .map { dwItem -> DevWorkspace .from(dwItem) }
5862 .filter { isIdeaEditorBased(it, devWorkspaceTemplateMap) }
59- .toList( )
63+ val lastResourceVersion = ( Utils .getValue(response, arrayOf( " metadata " , " resourceVersion " )) as String? )
6064
65+ return DevWorkspaceListResult (dwList, lastResourceVersion)
6166 } catch (e: ApiException ) {
6267 thisLogger().info(e.message)
6368
@@ -67,7 +72,7 @@ class DevWorkspaces(private val client: ApiClient) {
6772 // It doesn't make sense to show an error to the user in such cases,
6873 // so let's skip it silently.
6974 if ((response[" code" ] as Double ) == 403.0 ) {
70- return emptyList()
75+ return DevWorkspaceListResult ( emptyList(), null )
7176 } else {
7277 // The error will be shown in the Gateway UI.
7378 thisLogger().error(e.message)
@@ -76,6 +81,11 @@ class DevWorkspaces(private val client: ApiClient) {
7681 }
7782 }
7883
84+ @Throws(ApiException ::class )
85+ fun list (namespace : String ): List <DevWorkspace > {
86+ return listWithResult(namespace).items
87+ }
88+
7989 fun isIdeaEditorBased (devWorkspace : DevWorkspace , devWorkspaceTemplateMap : Map <String , List <DevWorkspaceTemplate >>): Boolean {
8090 // Quick editor ID check
8191 val segment = devWorkspace.cheEditor?.split(" /" )?.getOrNull(1 )
@@ -98,6 +108,16 @@ class DevWorkspaces(private val client: ApiClient) {
98108 }
99109 }
100110
111+ // Creates a filter for the Idea-based DevWorkspaces
112+ fun createFilter (
113+ namespace : String
114+ ): (DevWorkspace ) -> Boolean {
115+ val templateMap = getDevWorkspaceTemplateMap(namespace)
116+ return { dw: DevWorkspace ->
117+ isIdeaEditorBased(dw, templateMap)
118+ }
119+ }
120+
101121 fun get (namespace : String , name : String ): DevWorkspace {
102122 val dwObj = customApi.getNamespacedCustomObject(
103123 " workspace.devfile.io" ,
@@ -155,7 +175,7 @@ class DevWorkspaces(private val client: ApiClient) {
155175 return withTimeoutOrNull(timeout.seconds) {
156176 while (true ) {
157177 checkCancelled?.invoke()
158- val watcher = createWatcher(namespace, " metadata.name=$name " )
178+ val watcher = createWatcher(namespace, " metadata.name=$name " , latestResourceVersion = null )
159179 try {
160180 while (true ) {
161181 checkCancelled?.invoke()
@@ -178,7 +198,7 @@ class DevWorkspaces(private val client: ApiClient) {
178198 watcher.close()
179199 }
180200
181- // Watch ended because server closed the stream → retry a new watch
201+ // Watch ended because server closed the stream - retry a new watch
182202 delay(200 )
183203 }
184204
@@ -199,7 +219,7 @@ class DevWorkspaces(private val client: ApiClient) {
199219 return withTimeoutOrNull(timeout.seconds) {
200220 while (true ) {
201221 checkCancelled?.invoke()
202- val watcher = createWatcher(namespace, " metadata.name=$name " )
222+ val watcher = createWatcher(namespace, " metadata.name=$name " , latestResourceVersion = null )
203223 try {
204224 while (true ) {
205225 checkCancelled?.invoke()
@@ -218,7 +238,7 @@ class DevWorkspaces(private val client: ApiClient) {
218238 watcher.close()
219239 }
220240
221- // Watch ended because server closed the stream → retry a new watch
241+ // Watch ended because server closed the stream - retry a new watch
222242 delay(200 )
223243 }
224244
@@ -250,7 +270,7 @@ class DevWorkspaces(private val client: ApiClient) {
250270
251271 // Example:
252272 // https://github.com/kubernetes-client/java/blob/master/examples/examples-release-20/src/main/java/io/kubernetes/client/examples/WatchExample.java
253- private fun createWatcher (namespace : String , fieldSelector : String = "", labelSelector : String = ""): Watch <Any > {
273+ fun createWatcher (namespace : String , fieldSelector : String = "", labelSelector : String = "", latestResourceVersion : String? = null ): Watch <Any > {
254274 return Watch .createWatch(
255275 client,
256276 customApi.listNamespacedCustomObject(
@@ -260,6 +280,7 @@ class DevWorkspaces(private val client: ApiClient) {
260280 " devworkspaces"
261281 ).fieldSelector(fieldSelector)
262282 .labelSelector(labelSelector)
283+ .resourceVersion(latestResourceVersion)
263284 .watch(true )
264285 .buildCall(null ),
265286 object : TypeToken <Watch .Response <Any >>() {}.type
0 commit comments