mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-02-04 23:39:07 +07:00
[space] SPACE-12112 Migrate automation to idea-specific forward-compatible API
IJ-MR-4336 GitOrigin-RevId: 0e500207c8e4cca11c7596cf97ea14da70bb3d34
This commit is contained in:
committed by
intellij-monorepo-bot
parent
40d8d32c02
commit
1017302e0f
4
.idea/libraries/space_idea_sdk.xml
generated
4
.idea/libraries/space_idea_sdk.xml
generated
@@ -1,6 +1,6 @@
|
||||
<component name="libraryTable">
|
||||
<library name="space-idea-sdk" type="repository">
|
||||
<properties maven-id="com.jetbrains:space-idea-sdk:1.1.59855">
|
||||
<properties maven-id="com.jetbrains:space-idea-sdk:1.1.60200">
|
||||
<exclude>
|
||||
<dependency maven-id="org.jetbrains.kotlin:kotlin-stdlib" />
|
||||
<dependency maven-id="org.jetbrains.kotlin:kotlin-reflect" />
|
||||
@@ -32,7 +32,7 @@
|
||||
</exclude>
|
||||
</properties>
|
||||
<CLASSES>
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/jetbrains/space-idea-sdk/1.1.59855/space-idea-sdk-1.1.59855.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/com/jetbrains/space-idea-sdk/1.1.60200/space-idea-sdk-1.1.60200.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/reactivex/rxkotlin/0.55.0/rxkotlin-0.55.0.jar!/" />
|
||||
<root url="jar://$MAVEN_REPOSITORY$/io/reactivex/rxjava/1.1.1/rxjava-1.1.1.jar!/" />
|
||||
</CLASSES>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
task setupSpaceAutomationDefinitions {
|
||||
def version = "1.0.59855"
|
||||
def version = "1.0.60200"
|
||||
def artifact = file("$buildDir/space/space-idea-script-definition.jar")
|
||||
outputs.file(artifact)
|
||||
doLast {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.space.plugins.pipelines.services
|
||||
|
||||
import circlet.pipelines.config.api.ScriptConfig
|
||||
import circlet.automation.bootstrap.AutomationDslEvaluationBootstrap
|
||||
import circlet.pipelines.config.api.parseProjectConfig
|
||||
import circlet.pipelines.config.api.printJson
|
||||
import circlet.pipelines.config.idea.api.IdeaScriptConfig
|
||||
import circlet.pipelines.config.utils.AutomationCompilerConfiguration
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.getProjectCachePath
|
||||
import com.intellij.util.io.safeOutputStream
|
||||
@@ -20,7 +21,7 @@ private val log = logger<ScriptKtsPersistentState>()
|
||||
class ScriptKtsPersistentState(val project: Project) {
|
||||
|
||||
// not for load failure
|
||||
fun load(): ScriptConfig? {
|
||||
fun load(): IdeaScriptConfig? {
|
||||
|
||||
val path = getCacheFile(project)
|
||||
|
||||
@@ -37,7 +38,12 @@ class ScriptKtsPersistentState(val project: Project) {
|
||||
|
||||
return try {
|
||||
Files.newBufferedReader(path, Charsets.UTF_8).use { reader ->
|
||||
reader.readLine().parseProjectConfig()
|
||||
val evalService = AutomationDslEvaluationBootstrap(log, automationConfiguration()).loadEvaluatorForIdea()
|
||||
if (evalService == null) {
|
||||
log.error("DSL evaluation service not found, cannot deserialize automation DSL model")
|
||||
return null
|
||||
}
|
||||
evalService.deserializeJsonConfig(reader.readLine())
|
||||
}
|
||||
}
|
||||
catch (e: NoSuchFileException) {
|
||||
@@ -53,7 +59,7 @@ class ScriptKtsPersistentState(val project: Project) {
|
||||
return project.getProjectCachePath("space_automation").resolve(".space.kts.dat")
|
||||
}
|
||||
|
||||
fun save(config: ScriptConfig) {
|
||||
fun save(config: IdeaScriptConfig) {
|
||||
val path = getCacheFile(project)
|
||||
path.safeOutputStream().use {
|
||||
it.write(config.printJson().toByteArray(Charsets.UTF_8))
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
package com.intellij.space.plugins.pipelines.services
|
||||
|
||||
import circlet.automation.bootstrap.AutomationCompilerBootstrap
|
||||
import circlet.automation.bootstrap.AutomationDslEvaluationBootstrap
|
||||
import circlet.automation.bootstrap.embeddedMavenServer
|
||||
import circlet.automation.bootstrap.publicMavenServer
|
||||
import circlet.pipelines.config.api.ScriptConfig
|
||||
import circlet.pipelines.config.dsl.script.exec.common.ProjectConfigValidationResult
|
||||
import circlet.pipelines.config.dsl.script.exec.common.evaluateModel
|
||||
import circlet.pipelines.config.dsl.script.exec.common.validate
|
||||
import circlet.pipelines.config.idea.api.IdeaScriptConfig
|
||||
import circlet.pipelines.config.utils.AutomationCompilerConfiguration
|
||||
import circlet.platform.client.backgroundDispatcher
|
||||
import com.intellij.openapi.components.Service
|
||||
@@ -35,9 +33,8 @@ import org.slf4j.event.SubstituteLoggingEvent
|
||||
import org.slf4j.helpers.SubstituteLogger
|
||||
import runtime.Ui
|
||||
import runtime.reactive.*
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.io.*
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
|
||||
private val log = logger<SpaceKtsModelBuilder>()
|
||||
@@ -86,7 +83,7 @@ class SpaceKtsModelBuilder(val project: Project) : LifetimedDisposable by Lifeti
|
||||
private inner class ScriptModelHolder(val lifetime: Lifetime,
|
||||
val scriptFile: VirtualFile,
|
||||
modelBuildIsRequested: Property<Boolean>,
|
||||
loadedConfig: ScriptConfig?) : ScriptModel {
|
||||
loadedConfig: IdeaScriptConfig?) : ScriptModel {
|
||||
|
||||
val sync = Any()
|
||||
|
||||
@@ -94,11 +91,11 @@ class SpaceKtsModelBuilder(val project: Project) : LifetimedDisposable by Lifeti
|
||||
private val _error = mutableProperty<String?>(null)
|
||||
private val _state = mutableProperty(if (loadedConfig == null) ScriptState.NotInitialised else ScriptState.Ready)
|
||||
|
||||
override val config: Property<ScriptConfig?> get() = _config
|
||||
override val config: Property<IdeaScriptConfig?> get() = _config
|
||||
override val error: Property<String?> get() = _error
|
||||
override val state: Property<ScriptState> get() = _state
|
||||
|
||||
val logBuildData = mutableProperty<LogData?>(null)
|
||||
private val logBuildData = mutableProperty<LogData?>(null)
|
||||
|
||||
init {
|
||||
|
||||
@@ -144,86 +141,56 @@ class SpaceKtsModelBuilder(val project: Project) : LifetimedDisposable by Lifeti
|
||||
|
||||
private fun build(logData: LogData) {
|
||||
lifetime.using { lt ->
|
||||
val events = ObservableQueue.mutable<SubstituteLoggingEvent>()
|
||||
|
||||
events.change.forEach(lt) {
|
||||
val ev = it.index
|
||||
when (ev.level) {
|
||||
Level.INFO -> {
|
||||
logData.message(ev.message)
|
||||
}
|
||||
Level.DEBUG -> {
|
||||
logData.message(ev.message)
|
||||
}
|
||||
Level.WARN -> {
|
||||
logData.message(ev.message)
|
||||
}
|
||||
Level.ERROR -> {
|
||||
logData.error(ev.message)
|
||||
}
|
||||
Level.TRACE -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val eventLogger = KLogger(
|
||||
JVMLogger(
|
||||
SubstituteLogger("ScriptModelBuilderLogger", events, false)
|
||||
)
|
||||
)
|
||||
val eventLogger = logData.asLogger(lt)
|
||||
|
||||
val outputDir = createTempDir("space-automation-temp")
|
||||
try {
|
||||
val tempDir = createTempDir()
|
||||
val outputDirPath = outputDir.toPath()
|
||||
val compiledJarPath = outputDirPath.resolve("compiledJar.jar")
|
||||
val scriptRuntimePath = outputDirPath.resolve("space-automation-runtime.jar")
|
||||
|
||||
val outputFolder = tempDir.absolutePath + "/"
|
||||
val jarFile = File(outputFolder, "compiledJar.jar")
|
||||
val configuration = automationConfiguration()
|
||||
val compiler = AutomationCompilerBootstrap(log = eventLogger, configuration = configuration)
|
||||
|
||||
// Primary option is to download from currently connected server, fallback on the public maven
|
||||
val server = SpaceWorkspaceComponent.getInstance().workspace.value?.client?.server?.let { embeddedMavenServer(it) } ?: publicMavenServer
|
||||
val compileResultCode = compiler.compile(script = Paths.get(scriptFile.path), jar = compiledJarPath)
|
||||
|
||||
val configuration = AutomationCompilerConfiguration.Remote(server = server)
|
||||
|
||||
val compile = AutomationCompilerBootstrap(eventLogger, configuration = configuration).compile(
|
||||
Paths.get(scriptFile.path),
|
||||
jarFile.toPath()
|
||||
)
|
||||
|
||||
if (compile != 0) {
|
||||
if (compileResultCode != 0) {
|
||||
_config.value = null
|
||||
_error.value = "Compilation failed, $compile"
|
||||
_error.value = "Compilation failed, $compileResultCode"
|
||||
return@using
|
||||
}
|
||||
|
||||
if (!jarFile.exists() || !jarFile.isFile) {
|
||||
if (!Files.isRegularFile(compiledJarPath)) {
|
||||
_config.value = null
|
||||
_error.value = "Compilation failed: can't find output file ${jarFile.absolutePath}"
|
||||
_error.value = "Compilation failed: can't find output file ${compiledJarPath}"
|
||||
return@using
|
||||
}
|
||||
|
||||
val scriptRuntimePath = "$tempDir/space-automation-runtime.jar"
|
||||
// See AutomationCompiler.kt's where we copy the runtime jar into the output folder for all resolver types
|
||||
if (!File(scriptRuntimePath).exists()) {
|
||||
// See AutomationCompiler.kt (in space project) where we copy the runtime jar into the output folder for all resolver types
|
||||
if (!Files.exists(scriptRuntimePath)) {
|
||||
_config.value = null
|
||||
_error.value = "script-automation-runtime.jar is missing after script compilation."
|
||||
return@using
|
||||
}
|
||||
|
||||
val config = evaluateModel(jarFile.absolutePath, scriptRuntimePath)
|
||||
val scriptConfig = config.config()
|
||||
val evaluator = AutomationDslEvaluationBootstrap(log = eventLogger, configuration = configuration).loadEvaluatorForIdea()
|
||||
if (evaluator == null) {
|
||||
_config.value = null
|
||||
_error.value = "DSL evaluation service not found."
|
||||
return@using
|
||||
}
|
||||
val evalResult = evaluator.evaluateAndValidate(compiledJarPath, scriptRuntimePath)
|
||||
|
||||
val validationResult = scriptConfig.validate()
|
||||
|
||||
if (validationResult is ProjectConfigValidationResult.Failed) {
|
||||
val message = validationResult.errorMessage() // NON-NLS
|
||||
if (evalResult.validationErrors.any()) {
|
||||
val message = evalResult.validationErrors.joinToString("\n", prefix = "Validation errors:\n")
|
||||
logData.error(message)
|
||||
_config.value = null
|
||||
_error.value = message
|
||||
return@using
|
||||
}
|
||||
|
||||
_config.value = evalResult.config
|
||||
_error.value = null
|
||||
_config.value = scriptConfig
|
||||
|
||||
}
|
||||
catch (th: Throwable) {
|
||||
val errors = StringWriter()
|
||||
@@ -233,7 +200,35 @@ class SpaceKtsModelBuilder(val project: Project) : LifetimedDisposable by Lifeti
|
||||
// do not touch last config, just update the error state.
|
||||
_error.value = errors.toString()
|
||||
}
|
||||
finally {
|
||||
outputDir.deleteRecursively()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun automationConfiguration(): AutomationCompilerConfiguration {
|
||||
val spaceClient = SpaceWorkspaceComponent.getInstance().workspace.value?.client
|
||||
// Primary option is to download from currently connected server, fallback to the public maven
|
||||
val server = spaceClient?.server?.let { embeddedMavenServer(it) } ?: publicMavenServer
|
||||
return AutomationCompilerConfiguration.Remote(server = server)
|
||||
}
|
||||
|
||||
private fun LogData.asLogger(lifetime: Lifetime): KLogger {
|
||||
val queue = ObservableQueue.mutable<SubstituteLoggingEvent>()
|
||||
|
||||
queue.change.forEach(lifetime) {
|
||||
val ev = it.index
|
||||
when (ev.level) {
|
||||
Level.INFO -> message(ev.message)
|
||||
Level.DEBUG -> message(ev.message)
|
||||
Level.WARN -> message(ev.message)
|
||||
Level.ERROR -> error(ev.message)
|
||||
Level.TRACE -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
// slf4j's SubstituteLogger mechanism allows us to put logs as events in a queue (even though not initially made for this)
|
||||
return KLogger(JVMLogger(SubstituteLogger("ScriptModelBuilderLogger", queue, false)))
|
||||
}
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
package com.intellij.space.plugins.pipelines.ui
|
||||
|
||||
import circlet.pipelines.DefaultDslFileName
|
||||
import circlet.pipelines.config.api.ScriptConfig
|
||||
import circlet.pipelines.config.api.ScriptStep
|
||||
import circlet.pipelines.config.api.ScriptStep.*
|
||||
import circlet.pipelines.config.api.ScriptStep.ProcessExecutable.*
|
||||
import circlet.pipelines.config.idea.api.*
|
||||
import circlet.pipelines.config.idea.api.ScriptStep.*
|
||||
import circlet.pipelines.config.idea.api.ProcessExecutable.*
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ide.BrowserUtil
|
||||
import com.intellij.ide.IdeBundle
|
||||
@@ -50,6 +49,9 @@ import javax.swing.JPanel
|
||||
import javax.swing.tree.DefaultMutableTreeNode
|
||||
import javax.swing.tree.DefaultTreeModel
|
||||
import javax.swing.tree.TreeSelectionModel
|
||||
import kotlin.reflect.full.isSubtypeOf
|
||||
import kotlin.reflect.jvm.javaType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
class SpaceToolWindowViewModel(val lifetime: Lifetime) {
|
||||
val taskIsRunning = mutableProperty(false)
|
||||
@@ -221,7 +223,7 @@ class SpaceToolWindowService(val project: Project) : LifetimedDisposable by Life
|
||||
}
|
||||
|
||||
private fun resetNodes(root: DefaultMutableTreeNode,
|
||||
config: ScriptConfig?,
|
||||
config: IdeaScriptConfig?,
|
||||
error: String?,
|
||||
state: ScriptState,
|
||||
extendedViewModeEnabled: Boolean) {
|
||||
@@ -238,12 +240,12 @@ class SpaceToolWindowService(val project: Project) : LifetimedDisposable by Life
|
||||
return
|
||||
}
|
||||
|
||||
val tasks = config.jobs
|
||||
val jobs = config.jobs
|
||||
val targets = config.targets
|
||||
val pipelines = config.pipelines
|
||||
|
||||
var jobsTypesCount = 0
|
||||
if (tasks.any()) {
|
||||
if (jobs.any()) {
|
||||
jobsTypesCount++
|
||||
}
|
||||
if (targets.any()) {
|
||||
@@ -253,29 +255,11 @@ class SpaceToolWindowService(val project: Project) : LifetimedDisposable by Life
|
||||
jobsTypesCount++
|
||||
}
|
||||
val shouldAddGroupingNodes = jobsTypesCount > 1
|
||||
if (tasks.any()) {
|
||||
val tasksCollectionNode = getGroupingNode(root, "tasks", shouldAddGroupingNodes)
|
||||
config.jobs.forEach {
|
||||
val taskNode = SpaceModelTreeNode(it.name, true)
|
||||
if (extendedViewModeEnabled) {
|
||||
val triggers = it.triggers
|
||||
if (triggers.any()) {
|
||||
val triggersNode = SpaceModelTreeNode("triggers")
|
||||
triggers.forEach { trigger ->
|
||||
triggersNode.add(SpaceModelTreeNode(trigger::class.java.simpleName))
|
||||
}
|
||||
|
||||
taskNode.add(triggersNode)
|
||||
}
|
||||
|
||||
val jobsNode = SpaceModelTreeNode("jobs")
|
||||
it.steps.forEach { step ->
|
||||
jobsNode.add(step.toTreeNode())
|
||||
}
|
||||
taskNode.add(jobsNode)
|
||||
}
|
||||
|
||||
tasksCollectionNode.add(taskNode)
|
||||
if (jobs.any()) {
|
||||
val jobsCollectionNode = getGroupingNode(root, "jobs", shouldAddGroupingNodes)
|
||||
config.jobs.forEach { job ->
|
||||
val jobNode = job.toTreeNode(showChildren = extendedViewModeEnabled)
|
||||
jobsCollectionNode.add(jobNode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,22 +334,52 @@ class SpaceToolWindowService(val project: Project) : LifetimedDisposable by Life
|
||||
}
|
||||
}
|
||||
|
||||
private fun ScriptStep.toTreeNode(): SpaceModelTreeNode = when (val job = this) {
|
||||
is CompositeStep -> SpaceModelTreeNode(job::class.java.simpleName).apply {
|
||||
job.children.forEach { child ->
|
||||
add(child.toTreeNode())
|
||||
private fun ScriptJob.toTreeNode(showChildren: Boolean) = SpaceModelTreeNode(name, true).apply {
|
||||
if (showChildren) {
|
||||
if (triggers.any()) {
|
||||
add(triggers.toTreeNode())
|
||||
}
|
||||
add(steps.toTreeNode())
|
||||
}
|
||||
is SimpleStep.Process.Container -> SpaceModelTreeNode("container: ${job.image}").apply {
|
||||
add(job.data.exec.toTreeNode())
|
||||
}
|
||||
is SimpleStep.Process.VM -> SpaceModelTreeNode("vm: ${job.image}")
|
||||
is SimpleStep.DockerComposeStep -> SpaceModelTreeNode("compose: ${job.mainService}")
|
||||
}
|
||||
|
||||
private fun ProcessExecutable<*>.toTreeNode() = DefaultMutableTreeNode(treeNodeText)
|
||||
private fun List<Trigger>.toTreeNode() = SpaceModelTreeNode("triggers").apply {
|
||||
forEach { trigger ->
|
||||
add(trigger.toTreeNode())
|
||||
}
|
||||
}
|
||||
|
||||
private val ProcessExecutable<*>.treeNodeText: String
|
||||
private fun Trigger.toTreeNode() = SpaceModelTreeNode(usefulSubTypeName() ?: "other trigger")
|
||||
|
||||
private fun StepSequence.toTreeNode() = SpaceModelTreeNode("steps").apply {
|
||||
forEach { step ->
|
||||
add(step.toTreeNode())
|
||||
}
|
||||
}
|
||||
|
||||
private fun ScriptStep.toTreeNode(): SpaceModelTreeNode = when (val step = this) {
|
||||
is CompositeStep -> SpaceModelTreeNode(step.treeNodeText).apply {
|
||||
step.children.forEach { subStep ->
|
||||
add(subStep.toTreeNode())
|
||||
}
|
||||
}
|
||||
is SimpleStep.Process.Container -> SpaceModelTreeNode("container: ${step.image}").apply {
|
||||
add(step.data.exec.toTreeNode())
|
||||
}
|
||||
is SimpleStep.Process.VM -> SpaceModelTreeNode("vm: ${step.image}")
|
||||
is SimpleStep.DockerComposeStep -> SpaceModelTreeNode("compose: ${step.mainService}")
|
||||
else -> SpaceModelTreeNode(step::class.simpleName)
|
||||
}
|
||||
|
||||
private val CompositeStep.treeNodeText: String get() = when(this) {
|
||||
is CompositeStep.Fork -> "parallel"
|
||||
is CompositeStep.Sequence -> "sequence"
|
||||
else -> usefulSubTypeName() ?: "composite step"
|
||||
}
|
||||
|
||||
private fun ProcessExecutable.toTreeNode() = DefaultMutableTreeNode(treeNodeText)
|
||||
|
||||
private val ProcessExecutable.treeNodeText: String
|
||||
get() = when (this) {
|
||||
is ContainerExecutable.DefaultCommand -> "exec: defaultCommand${args.presentArgs()}"
|
||||
is ContainerExecutable.OverrideEntryPoint -> "exec: overrideEntryPoint: $entryPoint${args.presentArgs()}"
|
||||
@@ -373,8 +387,32 @@ private val ProcessExecutable<*>.treeNodeText: String
|
||||
is KotlinScript -> "exec: kts script"
|
||||
is ShellScript -> "exec: shell script"
|
||||
is VMExecutable -> "exec: VM executable"
|
||||
else -> "exec: ${this::class.simpleName}"
|
||||
}
|
||||
|
||||
private fun List<String>.presentArgs(): String {
|
||||
return if (this.any()) ". args: ${this.joinToString()}" else ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this object's dynamic type (which is a subtype of its static type [T]).
|
||||
* If this object is of an anonymous type, this method falls back to the name of the closest supertype of the runtime type of this object
|
||||
* that implements/extends its static type [T].
|
||||
* If this object is a direct anonymous implementation of the static type [T], this method returns `null` to allow other fallbacks.
|
||||
*
|
||||
* Most instances of the interfaces are anonymous classes at the moment in the space project.
|
||||
* For instance, the [Trigger] interface may have subinterfaces that we don't know of at compile time here, but could be added in the
|
||||
* future.
|
||||
* Since the object is of an anonymous class, we should use the name of the closest supertype that implements [Trigger], e.g. GitPush.
|
||||
*/
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private inline fun <reified T : Any> T.usefulSubTypeName(): String? {
|
||||
val simpleClassName = this::class.simpleName
|
||||
if (simpleClassName != null) { // false for anonymous classes
|
||||
return simpleClassName
|
||||
}
|
||||
// There is always at least one supertype (T), because we know this is an anonymous class that is also an instance of T
|
||||
val subTypeOfT = this::class.supertypes.first { it.isSubtypeOf(typeOf<T>()) }
|
||||
val simpleSubtypeName = subTypeOfT.javaType.typeName.substringAfterLast('.')
|
||||
return simpleSubtypeName.takeIf { it != T::class.simpleName }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.space.plugins.pipelines.viewmodel
|
||||
|
||||
import circlet.pipelines.config.api.ScriptConfig
|
||||
import circlet.pipelines.config.idea.api.IdeaScriptConfig
|
||||
import com.intellij.build.events.BuildEvent
|
||||
import com.intellij.build.events.BuildEventsNls
|
||||
import com.intellij.build.events.impl.OutputBuildEventImpl
|
||||
@@ -12,11 +12,10 @@ import runtime.reactive.ObservableList
|
||||
import runtime.reactive.Property
|
||||
import javax.swing.tree.DefaultMutableTreeNode
|
||||
|
||||
|
||||
enum class ScriptState { NotInitialised, Building, Ready }
|
||||
|
||||
interface ScriptModel {
|
||||
val config: Property<ScriptConfig?>
|
||||
val config: Property<IdeaScriptConfig?>
|
||||
val error: Property<String?>
|
||||
val state: Property<ScriptState>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user