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 {
console.info("Loading VisionForge global hooks")
//register VisionForge in the browser window
window.asDynamic().vf = this
window.asDynamic().VisionForge = this
window.parent.asDynamic().vf = this
window.parent.asDynamic().VisionForge = this
}
@Suppress("NON_EXPORTABLE_TYPE")

View File

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

View File

@ -1,6 +1,7 @@
package space.kscience.visionforge.jupyter
import kotlinx.html.*
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelHost
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
import org.jetbrains.kotlinx.jupyter.api.declare
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
@ -22,20 +23,30 @@ public abstract class VisionForgeIntegration(
) : JupyterIntegration(), ContextAware {
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() {
val vf: VisionForge = VisionForge(visionManager, notebook)
onLoaded {
declare("VisionForge" to handler, "vf" to handler)
handler.startServer(this)
val kernel: KotlinKernelHost = 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 {
handler.stopServer(this)
vf.stopServer(this)
}
import(
@ -53,7 +64,7 @@ public abstract class VisionForgeIntegration(
// }
render<Vision> { vision ->
handler.produceHtml {
vf.produceHtml {
vision(vision)
}
}
@ -74,16 +85,16 @@ public abstract class VisionForgeIntegration(
this.id = id
visionFragment(visionManager, fragment = page.content)
}
with(handler) {
renderScriptForId(id, true)
with(vf) {
renderScriptForId(id)
}
}
}
}
render<HtmlFormFragment> { fragment ->
handler.produceHtml {
if (!handler.isServerRunning()) {
vf.produceHtml {
if (!vf.isServerRunning()) {
p {
style = "color: red;"
+"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
public class JupyterCommonIntegration : VisionForgeIntegration(CONTEXT.visionManager) {
override fun Builder.afterLoaded() {
override fun Builder.afterLoaded(vf: VisionForge) {
resources {
js("visionforge-common") {
@ -43,19 +43,19 @@ public class JupyterCommonIntegration : VisionForgeIntegration(CONTEXT.visionMan
)
render<Gdml> { gdmlModel ->
handler.produceHtml {
vf.produceHtml {
vision { gdmlModel.toVision() }
}
}
render<Table<*>> { table ->
handler.produceHtml {
vf.produceHtml {
vision { table.toVision() }
}
}
render<Plot> { plot ->
handler.produceHtml {
vf.produceHtml {
vision { plot.asVision() }
}
}