RDCT-1444 Add TaskInfoEntity

This entity is going to represent running progress in Rhizome DB.
The data is mostly copied from `PlatformTaskSupport.ProgressStartedEvent` structure.

Few differences here:
- No `CoroutineContext` in the entity

It's not possible to put the actual coroutine context to `SharedEntity` because it's not serializable.
The context is used mostly for cancellation of a job. The possibility to cancel a job will be provided through a different API.

- New `TaskStatus` field

The status represents the actual status of a task, whether it's running, paused or canceled.

Also:

- Added utils which should make working with `TasksInfoEntity` easier

The utils are queries, which allow avoiding writing the same `asQuery().getOne` in every place where tasks info needs to be retrieved.

- Marked classes used in `TaskInfoEntity` as `@Serializable`

All data used in `SharedEntities` have to be serializable, otherwise it won't be possible to put entity to shared DB

- Add `kotlinx/serialization/KSerializer` to `ideaProjectStructure/exposed-third-party`

With Rhizome `KSerializer` is going to be exposed in more places. Therefore, it makes sense to add this class to default `exposed-third-party-api`, so the tests won't fail because of the added `@Serializable` annotation.

GitOrigin-RevId: 1a1b979b7660d41879a40a4d28b6487b3205e743
This commit is contained in:
Kate Botsman
2024-08-19 16:48:43 +02:00
committed by intellij-monorepo-bot
parent 09bc5c940b
commit 35f17aa034
15 changed files with 220 additions and 3 deletions

View File

@@ -1,5 +1,4 @@
kotlin/jvm/internal/DefaultConstructorMarker
kotlinx/serialization/KSerializer
kotlinx/serialization/descriptors/SerialDescriptor
kotlinx/serialization/encoding/Decoder
kotlinx/serialization/encoding/Encoder

View File

@@ -37,7 +37,6 @@ javax/xml/stream/XMLStreamReader
kotlin/jvm/internal/DefaultConstructorMarker
kotlin/reflect/KMutableProperty0
kotlin/reflect/KProperty
kotlinx/serialization/KSerializer
kotlinx/serialization/descriptors/SerialDescriptor
kotlinx/serialization/encoding/Decoder
kotlinx/serialization/encoding/Encoder

View File

@@ -8,13 +8,20 @@ com.intellij.platform.ide.progress.TaskCancellation
- s:nonCancellable():com.intellij.platform.ide.progress.TaskCancellation$NonCancellable
com.intellij.platform.ide.progress.TaskCancellation$Cancellable
- com.intellij.platform.ide.progress.TaskCancellation
- sf:Companion:com.intellij.platform.ide.progress.TaskCancellation$Cancellable$Companion
- a:withButtonText(java.lang.String):com.intellij.platform.ide.progress.TaskCancellation$Cancellable
- a:withTooltipText(java.lang.String):com.intellij.platform.ide.progress.TaskCancellation$Cancellable
f:com.intellij.platform.ide.progress.TaskCancellation$Cancellable$Companion
- f:serializer():kotlinx.serialization.KSerializer
f:com.intellij.platform.ide.progress.TaskCancellation$Companion
- f:cancellable():com.intellij.platform.ide.progress.TaskCancellation$Cancellable
- f:nonCancellable():com.intellij.platform.ide.progress.TaskCancellation$NonCancellable
- f:serializer():kotlinx.serialization.KSerializer
com.intellij.platform.ide.progress.TaskCancellation$NonCancellable
- com.intellij.platform.ide.progress.TaskCancellation
- sf:Companion:com.intellij.platform.ide.progress.TaskCancellation$NonCancellable$Companion
f:com.intellij.platform.ide.progress.TaskCancellation$NonCancellable$Companion
- f:serializer():kotlinx.serialization.KSerializer
f:com.intellij.platform.ide.progress.TasksKt
- sf:runWithModalProgressBlocking(com.intellij.openapi.project.Project,java.lang.String,kotlin.jvm.functions.Function2):java.lang.Object
- sf:runWithModalProgressBlocking(com.intellij.platform.ide.progress.ModalTaskOwner,java.lang.String,com.intellij.platform.ide.progress.TaskCancellation,kotlin.jvm.functions.Function2):java.lang.Object

View File

@@ -1,5 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="5" platform="JVM 17" allPlatforms="JVM [17]" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-Xjvm-default=all" />
</compilerSettings>
<compilerArguments>
<stringArguments>
<stringArg name="jvmTarget" arg="17" />
<stringArg name="apiVersion" arg="1.9" />
<stringArg name="languageVersion" arg="1.9" />
</stringArguments>
<arrayArguments>
<arrayArg name="pluginClasspaths">
<args>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</args>
</arrayArg>
</arrayArguments>
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
@@ -13,5 +34,8 @@
<orderEntry type="module" module-name="intellij.platform.util.progress" />
<orderEntry type="module" module-name="intellij.platform.core" />
<orderEntry type="module" module-name="intellij.platform.serviceContainer" />
<orderEntry type="module" module-name="intellij.platform.kernel" />
<orderEntry type="library" name="kotlinx-serialization-core" level="project" />
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
</component>
</module>

View File

@@ -2,9 +2,11 @@
package com.intellij.platform.ide.progress
import com.intellij.openapi.util.NlsContexts
import kotlinx.serialization.Serializable
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
@Serializable
class CancellableTaskCancellation private constructor(
val buttonText: @NlsContexts.Button String?,
val tooltipText: @NlsContexts.Tooltip String?

View File

@@ -1,7 +1,9 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.ide.progress
import kotlinx.serialization.Serializable
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
@Serializable
data object NonCancellableTaskCancellation: TaskCancellation.NonCancellable

View File

@@ -2,12 +2,16 @@
package com.intellij.platform.ide.progress
import com.intellij.openapi.util.NlsContexts
import kotlinx.serialization.Serializable
import org.jetbrains.annotations.Contract
@Serializable
sealed interface TaskCancellation {
@Serializable
sealed interface NonCancellable : TaskCancellation
@Serializable
sealed interface Cancellable : TaskCancellation {
@Contract(value = "_ -> new", pure = true)
fun withButtonText(buttonText: @NlsContexts.Button String): Cancellable

View File

@@ -0,0 +1,34 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.ide.progress
import kotlinx.serialization.Serializable
import org.jetbrains.annotations.ApiStatus
/**
* Represents the status of a task
*/
@ApiStatus.Internal
@Serializable
enum class TaskStatus {
/**
* Indicates that a task is currently in progress.
* The task can be suspended ([PAUSED]), canceled ([CANCELED]) or finish without status change
*/
RUNNING,
/**
* Indicates that a task has been temporarily paused.
*
* A task in this state may be resumed ([RUNNING]) or canceled ([CANCELED]).
* It implies that the task has been running before suspension.
*/
PAUSED,
/**
* Indicates that a task has been requested to stop.
*
* A canceled task does not change its status anymore.
* Although the status is [CANCELED], the task might still be running until it can be safely aborted.
*/
CANCELED
}

View File

@@ -0,0 +1,74 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.ide.progress
import com.intellij.platform.util.progress.ProgressState
import com.jetbrains.rhizomedb.EID
import com.jetbrains.rhizomedb.Entity
import fleet.kernel.DurableEntityType
import kotlinx.serialization.builtins.serializer
import org.jetbrains.annotations.ApiStatus
/**
* Represents the information of a task in the system.
*/
@ApiStatus.Internal
data class TaskInfoEntity(override val eid: EID) : Entity {
/**
* Human-readable title of a task, which is used to display the task in UI
*/
val title: String by Title
/**
* Specifies whether the task can be canceled.
*
* Possible values are:
*
* - [TaskCancellation.NonCancellable]: The task cannot be canceled, and no cancel button should be displayed in the UI.
* - [TaskCancellation.Cancellable]: The task can be canceled, and an optional cancel button can be displayed with
* customizable button and tooltip text.
*/
val cancellation: TaskCancellation by TaskCancellationType
/**
* Represents the current progress state of the task.
*
* This state includes:
* - [ProgressState.fraction]: The fraction of the task that has been completed, where `1.0` means 100% complete.
* - [ProgressState.text]: The primary text associated with the progress state (e.g., a brief description or title).
* - [ProgressState.details]: The detailed text associated with the progress state (e.g., additional information or steps).
*
* To subscribe on the progress updates use [updates]
* Initially, the progress state may be `null`.
*/
val progressState: ProgressState? by ProgressStateType
/**
* Indicates the current status of the task.
*
* The task can have one of the following statuses defined by [TaskStatus]:
* - [TaskStatus.RUNNING]: The task is currently in progress.
* - [TaskStatus.PAUSED]: The task has been temporarily paused.
* - [TaskStatus.CANCELED]: The task has been requested to stop, though it might still be running until it can be safely aborted.
*
* The status can be changed based on certain conditions:
* - A running task can be suspended or canceled.
* - A suspended task can be resumed or canceled.
* - A canceled task does not change its status anymore.
*
* The status is managed by user through [TaskManager]
* The status updates can be subscribed using [statuses]
*/
var taskStatus: TaskStatus by TaskStatusType
companion object : DurableEntityType<TaskInfoEntity>(
TaskInfoEntity::class.java.name,
"com.intellij.platform.ide.progress",
::TaskInfoEntity
) {
var Title = requiredValue("title", String.serializer())
var TaskCancellationType = requiredValue("taskCancellation", TaskCancellation.serializer())
var ProgressStateType = optionalValue("progressState", ProgressState.serializer())
var TaskStatusType = requiredValue("taskStatus", TaskStatus.serializer())
}
}

View File

@@ -0,0 +1,57 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.ide.progress
import com.intellij.platform.util.progress.ProgressState
import fleet.kernel.onDispose
import fleet.kernel.rete.*
import kotlinx.coroutines.flow.*
import org.jetbrains.annotations.ApiStatus
/**
* Represents a query for retrieving all active tasks in the system.
* To receive task updates, use [updates]
*
* @see TaskSupport for more info about how tasks are started
*/
val activeTasks: Query<TaskInfoEntity>
@ApiStatus.Internal
get() = TaskInfoEntity.each()
/**
* Returns a query that provides updates to the progress state of a task.
* For more info about progress state see [TaskInfoEntity.progressState]
*
* For a finite flow use [asFiniteFlow] extension
*/
val TaskInfoEntity.updates: Query<ProgressState>
@ApiStatus.Internal
get() = asQuery()[TaskInfoEntity.ProgressStateType]
/**
* Returns a query to retrieve the statuses of a task.
* For more info about task status see [TaskInfoEntity.taskStatus]
*
* For a finite flow use [asFiniteFlow] extension
*/
val TaskInfoEntity.statuses: Query<TaskStatus>
@ApiStatus.Internal
get() = asQuery()[TaskInfoEntity.TaskStatusType]
/**
* Converts a query result into a finite flow that emits results as long as the specified entity is alive.
* The flow will terminate when the entity is disposed
*
* @param T the type of the query result.
* @param entity the task information entity associated with the query. It will determine the lifespan of the flow.
* @return a finite flow of query results that will complete when the entity is disposed.
*/
@ApiStatus.Internal
fun <T> Query<T>.asFiniteFlow(entity: TaskInfoEntity, rete: Rete): Flow<T> {
val entityIsAlive = MutableStateFlow(true)
entity.onDispose(rete) { entityIsAlive.value = false }
return this.matchesFlow()
.combine(entityIsAlive) { state, isAlive -> state.takeIf { isAlive } }
.takeWhile { it != null }
.mapNotNull { it?.value }
}

View File

@@ -16,9 +16,12 @@ com.intellij.platform.util.progress.ProgressReporter
- a:sizedStep(I,java.lang.String,kotlin.jvm.functions.Function2,kotlin.coroutines.Continuation):java.lang.Object
- bs:sizedStep$default(com.intellij.platform.util.progress.ProgressReporter,I,java.lang.String,kotlin.jvm.functions.Function2,kotlin.coroutines.Continuation,I,java.lang.Object):java.lang.Object
com.intellij.platform.util.progress.ProgressState
- sf:Companion:com.intellij.platform.util.progress.ProgressState$Companion
- a:getDetails():java.lang.String
- a:getFraction():java.lang.Double
- a:getText():java.lang.String
f:com.intellij.platform.util.progress.ProgressState$Companion
- f:serializer():kotlinx.serialization.KSerializer
*:com.intellij.platform.util.progress.RawProgressReporter
- details(java.lang.String):V
- fraction(java.lang.Double):V

View File

@@ -12,6 +12,12 @@
<stringArg name="apiVersion" arg="2.0" />
<stringArg name="languageVersion" arg="2.0" />
</stringArguments>
<arrayArguments>
<arrayArg name="pluginClasspaths">
<args>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</args>
</arrayArg>
<arrayArg name="pluginOptions" />
</arrayArguments>
</compilerArguments>
</configuration>
</facet>
@@ -31,5 +37,7 @@
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="module" module-name="intellij.platform.util.coroutines" />
<orderEntry type="library" name="fastutil-min" level="project" />
<orderEntry type="library" name="kotlinx-serialization-core" level="project" />
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
</component>
</module>

View File

@@ -2,7 +2,9 @@
package com.intellij.platform.util.progress
import com.intellij.platform.util.progress.impl.ProgressText
import kotlinx.serialization.Serializable
@Serializable
sealed interface ProgressState {
val fraction: Double?

View File

@@ -2,7 +2,9 @@
package com.intellij.platform.util.progress;
import com.intellij.platform.util.progress.impl.ProgressText
import kotlinx.serialization.Serializable
@Serializable
internal data class StepState(
override val fraction: Double?,
override val text: ProgressText?,

View File

@@ -20,6 +20,6 @@ internal fun Flow<StepState>.pushTextToDetails(text: ProgressText): Flow<StepSta
)
}
internal typealias ProgressText = @com.intellij.openapi.util.NlsContexts.ProgressText String
typealias ProgressText = @com.intellij.openapi.util.NlsContexts.ProgressText String
internal typealias ScopedLambda<T> = suspend CoroutineScope.() -> T