This commit is contained in:
Alexander Nozik 2023-07-22 18:25:11 +03:00
parent b3f68d879f
commit ed491bdae0
4 changed files with 44 additions and 37 deletions

View File

@ -31,9 +31,10 @@ public class VFNotebookClient : AbstractPlugin() {
init { init {
console.info("Loading VisionForge global hooks")
//register VisionForge in the browser window //register VisionForge in the browser window
window.asDynamic().vf = this window.parent.asDynamic().vf = this
window.asDynamic().VisionForge = this window.parent.asDynamic().VisionForge = this
} }
@Suppress("NON_EXPORTABLE_TYPE") @Suppress("NON_EXPORTABLE_TYPE")

View File

@ -10,9 +10,7 @@ import io.ktor.server.websocket.WebSockets
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.html.* import kotlinx.html.*
import kotlinx.html.stream.createHTML import kotlinx.html.stream.createHTML
import org.jetbrains.kotlinx.jupyter.api.HTML import org.jetbrains.kotlinx.jupyter.api.*
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelHost
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.ContextAware import space.kscience.dataforge.context.ContextAware
import space.kscience.dataforge.context.info import space.kscience.dataforge.context.info
@ -21,7 +19,8 @@ import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.visionforge.Vision import space.kscience.visionforge.Vision
import space.kscience.visionforge.VisionManager import space.kscience.visionforge.VisionManager
import space.kscience.visionforge.html.* import space.kscience.visionforge.html.HtmlVisionFragment
import space.kscience.visionforge.html.visionFragment
import space.kscience.visionforge.server.VisionRoute import space.kscience.visionforge.server.VisionRoute
import space.kscience.visionforge.server.serveVisionData import space.kscience.visionforge.server.serveVisionData
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -50,6 +49,7 @@ public enum class VisionForgeCompatibility {
@Suppress("ExtractKtorModule") @Suppress("ExtractKtorModule")
public class VisionForge( public class VisionForge(
public val visionManager: VisionManager, public val visionManager: VisionManager,
public val notebook: Notebook,
meta: Meta = Meta.EMPTY, meta: Meta = Meta.EMPTY,
) : ContextAware, CoroutineScope { ) : ContextAware, CoroutineScope {
@ -61,8 +61,6 @@ public class VisionForge(
private var engine: ApplicationEngine? = null private var engine: ApplicationEngine? = null
public var notebookMode: VisionForgeCompatibility = VisionForgeCompatibility.IDEA
override val coroutineContext: CoroutineContext get() = context.coroutineContext override val coroutineContext: CoroutineContext get() = context.coroutineContext
@ -75,19 +73,19 @@ public class VisionForge(
host: String = getProperty("visionforge.host").string ?: "localhost", host: String = getProperty("visionforge.host").string ?: "localhost",
port: Int = getProperty("visionforge.port").int ?: VisionRoute.DEFAULT_PORT, port: Int = getProperty("visionforge.port").int ?: VisionRoute.DEFAULT_PORT,
) { ) {
if (engine != null) { engine?.let {
kernel.displayHtml { kernel.displayHtml {
p { p {
style = "color: red;" style = "color: red;"
+"Stopping current VisionForge server" +"Stopping current VisionForge server"
} }
} }
it.stop(1000, 2000)
} }
//val connector: EngineConnectorConfig = EngineConnectorConfig(host, port) //val connector: EngineConnectorConfig = EngineConnectorConfig(host, port)
engine?.stop(1000, 2000)
engine = context.embeddedServer(CIO, port, host) { engine = context.embeddedServer(CIO, port, host) {
install(WebSockets) install(WebSockets)
}.start(false) }.start(false)
@ -115,16 +113,11 @@ public class VisionForge(
} }
} }
internal fun TagConsumer<*>.renderScriptForId(id: String, iframeIsolation: Boolean = false) { internal fun TagConsumer<*>.renderScriptForId(id: String) {
script { script {
type = "text/javascript" type = "text/javascript"
if (iframeIsolation) { //language=JavaScript
//language=JavaScript unsafe { +"parent.VisionForge.renderAllVisionsById(document, \"$id\");" }
unsafe { +"parent.VisionForge.renderAllVisionsById(document, \"$id\");" }
} else {
//language=JavaScript
unsafe { +"VisionForge.renderAllVisionsById(document, \"$id\");" }
}
} }
} }
@ -133,8 +126,10 @@ public class VisionForge(
isolated: Boolean? = null, isolated: Boolean? = null,
fragment: HtmlVisionFragment, fragment: HtmlVisionFragment,
): MimeTypedResult { ): MimeTypedResult {
val iframeIsolation = isolated val iframeIsolation = isolated ?: when (notebook.jupyterClientType) {
?: (notebookMode == VisionForgeCompatibility.JUPYTER || notebookMode == VisionForgeCompatibility.DATALORE) JupyterClientType.DATALORE, JupyterClientType.JUPYTER_NOTEBOOK -> true
else -> false
}
return HTML( return HTML(
iframeIsolation iframeIsolation
) { ) {
@ -172,7 +167,7 @@ public class VisionForge(
visionFragment(visionManager, fragment = fragment) visionFragment(visionManager, fragment = fragment)
} }
} }
renderScriptForId(id, iframeIsolation = iframeIsolation) renderScriptForId(id)
} }
} }

View File

@ -1,6 +1,7 @@
package space.kscience.visionforge.jupyter package space.kscience.visionforge.jupyter
import kotlinx.html.* import kotlinx.html.*
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelHost
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
import org.jetbrains.kotlinx.jupyter.api.declare import org.jetbrains.kotlinx.jupyter.api.declare
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
@ -22,20 +23,30 @@ public abstract class VisionForgeIntegration(
) : JupyterIntegration(), ContextAware { ) : JupyterIntegration(), ContextAware {
override val context: Context get() = visionManager.context override val context: Context get() = visionManager.context
protected val handler: VisionForge = VisionForge(visionManager)
protected abstract fun Builder.afterLoaded() protected abstract fun Builder.afterLoaded(vf: VisionForge)
final override fun Builder.onLoaded() { final override fun Builder.onLoaded() {
val vf: VisionForge = VisionForge(visionManager, notebook)
onLoaded { onLoaded {
declare("VisionForge" to handler, "vf" to handler) val kernel: KotlinKernelHost = this
handler.startServer(this) declare("VisionForge" to vf, "vf" to vf)
vf.startServer(kernel)
vf.configuration.onChange(this) { name ->
if (name.toString() == "visionforge.port") {
kernel.displayHtml {
p { +"Property 'visionforge.port' changed. Restarting server" }
}
vf.startServer(kernel)
}
}
} }
onShutdown { onShutdown {
handler.stopServer(this) vf.stopServer(this)
} }
import( import(
@ -53,7 +64,7 @@ public abstract class VisionForgeIntegration(
// } // }
render<Vision> { vision -> render<Vision> { vision ->
handler.produceHtml { vf.produceHtml {
vision(vision) vision(vision)
} }
} }
@ -74,16 +85,16 @@ public abstract class VisionForgeIntegration(
this.id = id this.id = id
visionFragment(visionManager, fragment = page.content) visionFragment(visionManager, fragment = page.content)
} }
with(handler) { with(vf) {
renderScriptForId(id, true) renderScriptForId(id)
} }
} }
} }
} }
render<HtmlFormFragment> { fragment -> render<HtmlFormFragment> { fragment ->
handler.produceHtml { vf.produceHtml {
if (!handler.isServerRunning()) { if (!vf.isServerRunning()) {
p { p {
style = "color: red;" style = "color: red;"
+"The server is not running. Forms are not interactive. Start server with `VisionForge.startServer()." +"The server is not running. Forms are not interactive. Start server with `VisionForge.startServer()."
@ -94,7 +105,7 @@ public abstract class VisionForgeIntegration(
} }
} }
afterLoaded() afterLoaded(vf)
} }
} }

View File

@ -24,7 +24,7 @@ import space.kscience.visionforge.visionManager
@DFExperimental @DFExperimental
public class JupyterCommonIntegration : VisionForgeIntegration(CONTEXT.visionManager) { public class JupyterCommonIntegration : VisionForgeIntegration(CONTEXT.visionManager) {
override fun Builder.afterLoaded() { override fun Builder.afterLoaded(vf: VisionForge) {
resources { resources {
js("visionforge-common") { js("visionforge-common") {
@ -43,19 +43,19 @@ public class JupyterCommonIntegration : VisionForgeIntegration(CONTEXT.visionMan
) )
render<Gdml> { gdmlModel -> render<Gdml> { gdmlModel ->
handler.produceHtml { vf.produceHtml {
vision { gdmlModel.toVision() } vision { gdmlModel.toVision() }
} }
} }
render<Table<*>> { table -> render<Table<*>> { table ->
handler.produceHtml { vf.produceHtml {
vision { table.toVision() } vision { table.toVision() }
} }
} }
render<Plot> { plot -> render<Plot> { plot ->
handler.produceHtml { vf.produceHtml {
vision { plot.asVision() } vision { plot.asVision() }
} }
} }