forked from kscience/visionforge
Jupyter renderers are working for lab and Idea
This commit is contained in:
parent
a49a4f1a7f
commit
b3f68d879f
@ -13,7 +13,7 @@ val fxVersion by extra("11")
|
|||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
group = "space.kscience"
|
group = "space.kscience"
|
||||||
version = "0.3.0-dev-11"
|
version = "0.3.0-dev-12"
|
||||||
}
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
|
@ -51,7 +51,7 @@ kotlin {
|
|||||||
implementation(projects.visionforgeMarkdown)
|
implementation(projects.visionforgeMarkdown)
|
||||||
implementation(projects.visionforgeTables)
|
implementation(projects.visionforgeTables)
|
||||||
implementation(projects.cernRootLoader)
|
implementation(projects.cernRootLoader)
|
||||||
implementation(projects.visionforgeJupyter.visionforgeJupyterCommon)
|
api(projects.visionforgeJupyter.visionforgeJupyterCommon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,77 +2,31 @@
|
|||||||
"cells": [
|
"cells": [
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 2,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"tags": []
|
||||||
"end_time": "2023-07-20T06:12:13.305060400Z",
|
|
||||||
"start_time": "2023-07-20T06:12:13.011273800Z"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"@file:Repository(\"*mavenLocal\")\n",
|
"@file:Repository(\"*mavenLocal\")\n",
|
||||||
"@file:Repository(\"https://repo.kotlin.link\")\n",
|
"@file:Repository(\"https://repo.kotlin.link\")\n",
|
||||||
"@file:Repository(\"https://maven.pkg.jetbrains.space/spc/p/sci/dev\")\n",
|
"@file:Repository(\"https://maven.pkg.jetbrains.space/spc/p/sci/dev\")\n",
|
||||||
"@file:DependsOn(\"space.kscience:visionforge-jupyter-common-jvm:0.3.0-dev-11\")"
|
"@file:DependsOn(\"space.kscience:visionforge-jupyter-common-jvm:0.3.0-dev-12\")\n",
|
||||||
|
"//import space.kscience.visionforge.jupyter.JupyterCommonIntegration\n",
|
||||||
|
"//\n",
|
||||||
|
"//val integration = JupyterCommonIntegration()\n",
|
||||||
|
"//USE(integration.getDefinitions(notebook).first())"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 3,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"collapsed": false,
|
"tags": []
|
||||||
"jupyter": {
|
|
||||||
"outputs_hidden": false
|
|
||||||
},
|
|
||||||
"ExecuteTime": {
|
|
||||||
"end_time": "2023-07-20T06:12:19.603077Z",
|
|
||||||
"start_time": "2023-07-20T06:12:19.419504300Z"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"outputs": [
|
"outputs": [],
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": "<p style=\"color: blue;\">Starting VisionForge server on http://localhost:7777</p>\n"
|
|
||||||
},
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
"source": [
|
||||||
"vf.startServer()"
|
"vf.fragment {\n",
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {
|
|
||||||
"collapsed": false,
|
|
||||||
"jupyter": {
|
|
||||||
"outputs_hidden": false
|
|
||||||
},
|
|
||||||
"ExecuteTime": {
|
|
||||||
"end_time": "2023-07-20T06:12:21.490069100Z",
|
|
||||||
"start_time": "2023-07-20T06:12:20.694188600Z"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": "<div id=\"fragment[1645474043/2315898832]\">\n <h1>AAA</h1>\n <div id=\"output[vision[302766000]]\" class=\"visionforge-output\" data-output-name=\"vision[302766000]\" data-output-connect=\"ws://localhost:7777/content-0/ws\">\n <script type=\"text/json\" class=\"visionforge-output-data\">\n{\n \"type\": \"group.solid\",\n \"children\": {\n \"@ambientLight\": {\n \"type\": \"solid.light.ambient\"\n },\n \"@static[1326263213]\": {\n \"type\": \"solid.box\",\n \"xSize\": 100.0,\n \"ySize\": 100.0,\n \"zSize\": 200.0\n },\n \"@static[1813044036]\": {\n \"type\": \"solid.sphere\",\n \"properties\": {\n \"position\": {\n \"x\": 300\n }\n },\n \"radius\": 100.0\n }\n }\n}\n</script>\n </div>\n <div id=\"output[vision[1326029936]]\" class=\"visionforge-output\" data-output-name=\"vision[1326029936]\" data-output-connect=\"ws://localhost:7777/content-0/ws\">\n <script type=\"text/json\" class=\"visionforge-output-data\">\n{\n \"type\": \"vision.plotly\",\n \"meta\": {\n \"data\": {\n \"type\": \"scatter\",\n \"x\": [\n 1,\n 2,\n 3,\n 1\n ],\n \"y\": [\n 1,\n 2,\n 3,\n 4\n ],\n \"@index\": \"0\"\n }\n }\n}\n</script>\n </div>\n</div>\n<script type=\"text/javascript\">VisionForge.renderAllVisionsById(\"fragment[1645474043/2315898832]\");</script>\n"
|
|
||||||
},
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {
|
|
||||||
"text/html": {
|
|
||||||
"isolated": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"vf.page {\n",
|
|
||||||
" h1 { +\"AAA\" }\n",
|
" h1 { +\"AAA\" }\n",
|
||||||
" vision {\n",
|
" vision {\n",
|
||||||
" solid {\n",
|
" solid {\n",
|
||||||
@ -100,24 +54,27 @@
|
|||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"collapsed": false,
|
|
||||||
"jupyter": {
|
"jupyter": {
|
||||||
"outputs_hidden": false
|
"outputs_hidden": false
|
||||||
}
|
},
|
||||||
|
"tags": []
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"vf.stopServer()"
|
"Plotly.plot { \n",
|
||||||
|
" scatter{\n",
|
||||||
|
" x(1,2,3)\n",
|
||||||
|
" y(1,2,3)\n",
|
||||||
|
" }\n",
|
||||||
|
"}"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [],
|
"source": []
|
||||||
"metadata": {
|
|
||||||
"collapsed": false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
|
@ -2,7 +2,6 @@ package space.kscience.visionforge.react
|
|||||||
|
|
||||||
import kotlinx.css.*
|
import kotlinx.css.*
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import org.w3c.dom.HTMLElement
|
|
||||||
import react.*
|
import react.*
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.request
|
import space.kscience.dataforge.context.request
|
||||||
@ -29,7 +28,7 @@ public val ThreeCanvasComponent: FC<ThreeCanvasProps> = fc("ThreeCanvasComponent
|
|||||||
|
|
||||||
useEffect(props.solid, props.options, elementRef) {
|
useEffect(props.solid, props.options, elementRef) {
|
||||||
if (canvas == null) {
|
if (canvas == null) {
|
||||||
val element = elementRef.current as? HTMLElement ?: error("Canvas element not found")
|
val element = elementRef.current ?: error("Canvas element not found")
|
||||||
canvas = ThreeCanvas(three, element, props.options ?: Canvas3DOptions())
|
canvas = ThreeCanvas(three, element, props.options ?: Canvas3DOptions())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,19 +4,28 @@ import kotlinx.html.FlowContent
|
|||||||
import kotlinx.html.TagConsumer
|
import kotlinx.html.TagConsumer
|
||||||
import kotlinx.html.stream.createHTML
|
import kotlinx.html.stream.createHTML
|
||||||
|
|
||||||
public typealias HtmlFragment = TagConsumer<*>.() -> Unit
|
/**
|
||||||
|
* A standalone HTML fragment
|
||||||
public fun HtmlFragment.renderToString(): String = createHTML().apply(this).finalize()
|
*/
|
||||||
|
public fun interface HtmlFragment {
|
||||||
public fun TagConsumer<*>.fragment(fragment: HtmlFragment) {
|
public fun TagConsumer<*>.append()
|
||||||
fragment()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun FlowContent.fragment(fragment: HtmlFragment) {
|
/**
|
||||||
fragment(consumer)
|
* Convenience method to append fragment to the given [consumer]
|
||||||
}
|
*/
|
||||||
|
public fun HtmlFragment.appendTo(consumer: TagConsumer<*>): Unit = consumer.append()
|
||||||
|
|
||||||
public operator fun HtmlFragment.plus(other: HtmlFragment): HtmlFragment = {
|
/**
|
||||||
this@plus()
|
* Create a string from this [HtmlFragment]
|
||||||
other()
|
*/
|
||||||
|
public fun HtmlFragment.renderToString(): String = createHTML().apply { append() }.finalize()
|
||||||
|
|
||||||
|
public fun TagConsumer<*>.appendFragment(fragment: HtmlFragment): Unit = fragment.appendTo(this)
|
||||||
|
|
||||||
|
public fun FlowContent.appendFragment(fragment: HtmlFragment): Unit = fragment.appendTo(consumer)
|
||||||
|
|
||||||
|
public operator fun HtmlFragment.plus(other: HtmlFragment): HtmlFragment = HtmlFragment {
|
||||||
|
this@plus.appendTo(this)
|
||||||
|
other.appendTo(this)
|
||||||
}
|
}
|
@ -2,18 +2,17 @@ package space.kscience.visionforge.html
|
|||||||
|
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.NameToken
|
import space.kscience.dataforge.names.NameToken
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionManager
|
import space.kscience.visionforge.VisionManager
|
||||||
|
|
||||||
public typealias HtmlVisionFragment = VisionTagConsumer<*>.() -> Unit
|
public fun interface HtmlVisionFragment{
|
||||||
|
public fun VisionTagConsumer<*>.append()
|
||||||
@DFExperimental
|
}
|
||||||
public fun HtmlVisionFragment(content: VisionTagConsumer<*>.() -> Unit): HtmlVisionFragment = content
|
|
||||||
|
|
||||||
|
public fun HtmlVisionFragment.appendTo(consumer: VisionTagConsumer<*>): Unit = consumer.append()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a fragment in the given consumer and return a map of extracted visions
|
* Render a fragment in the given consumer and return a map of extracted visions
|
||||||
@ -84,7 +83,7 @@ public fun TagConsumer<*>.visionFragment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment(consumer)
|
fragment.appendTo(consumer)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun FlowContent.visionFragment(
|
public fun FlowContent.visionFragment(
|
||||||
|
@ -17,7 +17,7 @@ public data class VisionPage(
|
|||||||
/**
|
/**
|
||||||
* Use a script with given [src] as a global header for all pages.
|
* Use a script with given [src] as a global header for all pages.
|
||||||
*/
|
*/
|
||||||
public fun scriptHeader(src: String, block: SCRIPT.() -> Unit = {}): HtmlFragment = {
|
public fun scriptHeader(src: String, block: SCRIPT.() -> Unit = {}): HtmlFragment = HtmlFragment{
|
||||||
script {
|
script {
|
||||||
type = "text/javascript"
|
type = "text/javascript"
|
||||||
this.src = src
|
this.src = src
|
||||||
@ -28,7 +28,7 @@ public data class VisionPage(
|
|||||||
/**
|
/**
|
||||||
* Use css with the given stylesheet link as a global header for all pages.
|
* Use css with the given stylesheet link as a global header for all pages.
|
||||||
*/
|
*/
|
||||||
public fun styleSheetHeader(href: String, block: LINK.() -> Unit = {}): HtmlFragment = {
|
public fun styleSheetHeader(href: String, block: LINK.() -> Unit = {}): HtmlFragment = HtmlFragment{
|
||||||
link {
|
link {
|
||||||
rel = "stylesheet"
|
rel = "stylesheet"
|
||||||
this.href = href
|
this.href = href
|
||||||
@ -36,7 +36,7 @@ public data class VisionPage(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun title(title:String): HtmlFragment = {
|
public fun title(title:String): HtmlFragment = HtmlFragment{
|
||||||
title(title)
|
title(title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ fun FlowContent.renderVisionFragment(
|
|||||||
renderer(name, vision, outputMeta)
|
renderer(name, vision, outputMeta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment(consumer)
|
fragment.appendTo(consumer)
|
||||||
return visionMap
|
return visionMap
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ private fun VisionOutput.base(block: VisionGroup.() -> Unit) = context.visionMan
|
|||||||
@DFExperimental
|
@DFExperimental
|
||||||
class HtmlTagTest {
|
class HtmlTagTest {
|
||||||
|
|
||||||
val fragment: HtmlVisionFragment = {
|
val fragment = HtmlVisionFragment{
|
||||||
div {
|
div {
|
||||||
h1 { +"Head" }
|
h1 { +"Head" }
|
||||||
vision("ddd") {
|
vision("ddd") {
|
||||||
|
@ -286,8 +286,8 @@ public fun VisionClient.renderAllVisionsIn(element: Element) {
|
|||||||
/**
|
/**
|
||||||
* Render all visions in an element with a given [id]
|
* Render all visions in an element with a given [id]
|
||||||
*/
|
*/
|
||||||
public fun VisionClient.renderAllVisionsById(id: String): Unit = whenDocumentLoaded {
|
public fun VisionClient.renderAllVisionsById(document: Document, id: String): Unit {
|
||||||
val element = getElementById(id)
|
val element = document.getElementById(id)
|
||||||
if (element != null) {
|
if (element != null) {
|
||||||
renderAllVisionsIn(element)
|
renderAllVisionsIn(element)
|
||||||
} else {
|
} else {
|
||||||
|
@ -34,10 +34,10 @@ public interface HtmlVisionContext : ContextAware {
|
|||||||
|
|
||||||
public typealias HtmlVisionContextFragment = context(HtmlVisionContext) TagConsumer<*>.() -> Unit
|
public typealias HtmlVisionContextFragment = context(HtmlVisionContext) TagConsumer<*>.() -> Unit
|
||||||
|
|
||||||
context(HtmlVisionContext)
|
//context(HtmlVisionContext)
|
||||||
public fun HtmlVisionFragment(
|
//public fun HtmlVisionFragment(
|
||||||
content: TagConsumer<*>.() -> Unit,
|
// content: TagConsumer<*>.() -> Unit,
|
||||||
): HtmlVisionFragment = content
|
//): HtmlVisionFragment = HtmlVisionFragment { }
|
||||||
|
|
||||||
context(HtmlVisionContext)
|
context(HtmlVisionContext)
|
||||||
private fun <T> TagConsumer<T>.vision(
|
private fun <T> TagConsumer<T>.vision(
|
||||||
|
@ -91,14 +91,14 @@ internal fun checkOrStoreFile(htmlPath: Path, filePath: Path, resource: String,
|
|||||||
*/
|
*/
|
||||||
internal fun fileScriptHeader(
|
internal fun fileScriptHeader(
|
||||||
path: Path,
|
path: Path,
|
||||||
): HtmlFragment = {
|
): HtmlFragment = HtmlFragment{
|
||||||
script {
|
script {
|
||||||
type = "text/javascript"
|
type = "text/javascript"
|
||||||
src = path.toString()
|
src = path.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun embedScriptHeader(resource: String, classLoader: ClassLoader): HtmlFragment = {
|
internal fun embedScriptHeader(resource: String, classLoader: ClassLoader): HtmlFragment = HtmlFragment{
|
||||||
script {
|
script {
|
||||||
type = "text/javascript"
|
type = "text/javascript"
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -113,7 +113,7 @@ internal fun fileCssHeader(
|
|||||||
cssPath: Path,
|
cssPath: Path,
|
||||||
resource: String,
|
resource: String,
|
||||||
classLoader: ClassLoader,
|
classLoader: ClassLoader,
|
||||||
): HtmlFragment = {
|
): HtmlFragment = HtmlFragment{
|
||||||
val relativePath = checkOrStoreFile(basePath, cssPath, resource, classLoader)
|
val relativePath = checkOrStoreFile(basePath, cssPath, resource, classLoader)
|
||||||
link {
|
link {
|
||||||
rel = "stylesheet"
|
rel = "stylesheet"
|
||||||
|
@ -78,7 +78,7 @@ public fun VisionPage.makeFile(
|
|||||||
charset = "utf-8"
|
charset = "utf-8"
|
||||||
}
|
}
|
||||||
actualHeaders.values.forEach {
|
actualHeaders.values.forEach {
|
||||||
fragment(it)
|
appendFragment(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package space.kscience.visionforge.jupyter
|
package space.kscience.visionforge.jupyter
|
||||||
|
|
||||||
import kotlinx.browser.window
|
import kotlinx.browser.window
|
||||||
|
import org.w3c.dom.Document
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import space.kscience.dataforge.context.AbstractPlugin
|
import space.kscience.dataforge.context.AbstractPlugin
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
@ -20,8 +21,8 @@ public class VFNotebookClient : AbstractPlugin() {
|
|||||||
client.renderAllVisionsIn(element)
|
client.renderAllVisionsIn(element)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun renderAllVisionsById(id: String) {
|
public fun renderAllVisionsById(document: Document, id: String) {
|
||||||
client.renderAllVisionsById(id)
|
client.renderAllVisionsById(document, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun renderAllVisions() {
|
public fun renderAllVisions() {
|
||||||
|
@ -11,6 +11,7 @@ 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.HTML
|
||||||
|
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelHost
|
||||||
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
|
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
|
||||||
@ -20,24 +21,33 @@ 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.HtmlVisionFragment
|
import space.kscience.visionforge.html.*
|
||||||
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
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.random.nextUInt
|
import kotlin.random.nextUInt
|
||||||
|
|
||||||
internal fun TagConsumer<*>.renderScriptForId(id: String) {
|
|
||||||
script {
|
@Suppress("FunctionName")
|
||||||
type = "text/javascript"
|
internal inline fun HTML(isolated: Boolean = false, block: TagConsumer<*>.() -> Unit): MimeTypedResult =
|
||||||
unsafe { +"VisionForge.renderAllVisionsById(\"$id\");" }
|
HTML(createHTML().apply(block).finalize(), isolated)
|
||||||
}
|
|
||||||
|
internal fun KotlinKernelHost.displayHtml(block: TagConsumer<*>.() -> Unit) {
|
||||||
|
display(HTML(false, block), null)
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum class VisionForgeCompatibility {
|
||||||
|
JUPYTER,
|
||||||
|
JUPYTER_LAB,
|
||||||
|
DATALORE,
|
||||||
|
IDEA
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A handler class that includes a server and common utilities
|
* A handler class that includes a server and common utilities
|
||||||
*/
|
*/
|
||||||
|
@Suppress("ExtractKtorModule")
|
||||||
public class VisionForge(
|
public class VisionForge(
|
||||||
public val visionManager: VisionManager,
|
public val visionManager: VisionManager,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
@ -51,29 +61,28 @@ public class VisionForge(
|
|||||||
|
|
||||||
private var engine: ApplicationEngine? = null
|
private var engine: ApplicationEngine? = null
|
||||||
|
|
||||||
public var isolateFragments: Boolean = false
|
public var notebookMode: VisionForgeCompatibility = VisionForgeCompatibility.IDEA
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext get() = context.coroutineContext
|
override val coroutineContext: CoroutineContext get() = context.coroutineContext
|
||||||
|
|
||||||
public fun legacyMode() {
|
|
||||||
isolateFragments = true
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun isServerRunning(): Boolean = engine != null
|
public fun isServerRunning(): Boolean = engine != null
|
||||||
|
|
||||||
public fun html(block: TagConsumer<*>.() -> Unit): MimeTypedResult = HTML(createHTML().apply(block).finalize())
|
|
||||||
|
|
||||||
public fun getProperty(name: String): TypedMeta<*>? = configuration[name] ?: context.properties[name]
|
public fun getProperty(name: String): TypedMeta<*>? = configuration[name] ?: context.properties[name]
|
||||||
|
|
||||||
public fun startServer(
|
internal fun startServer(
|
||||||
|
kernel: KotlinKernelHost,
|
||||||
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,
|
||||||
): MimeTypedResult = html {
|
) {
|
||||||
if (engine != null) {
|
if (engine != null) {
|
||||||
p {
|
kernel.displayHtml {
|
||||||
style = "color: red;"
|
p {
|
||||||
+"Stopping current VisionForge server"
|
style = "color: red;"
|
||||||
|
+"Stopping current VisionForge server"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//val connector: EngineConnectorConfig = EngineConnectorConfig(host, port)
|
//val connector: EngineConnectorConfig = EngineConnectorConfig(host, port)
|
||||||
@ -83,66 +92,91 @@ public class VisionForge(
|
|||||||
install(WebSockets)
|
install(WebSockets)
|
||||||
}.start(false)
|
}.start(false)
|
||||||
|
|
||||||
p {
|
kernel.displayHtml {
|
||||||
style = "color: blue;"
|
p {
|
||||||
+"Starting VisionForge server on http://$host:$port"
|
style = "color: blue;"
|
||||||
|
+"Starting VisionForge server on port $port"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun stopServer() {
|
internal fun stopServer(kernel: KotlinKernelHost) {
|
||||||
engine?.apply {
|
engine?.apply {
|
||||||
logger.info { "Stopping VisionForge server" }
|
logger.info { "Stopping VisionForge server" }
|
||||||
stop(1000, 2000)
|
stop(1000, 2000)
|
||||||
engine = null
|
engine = null
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun produceHtmlString(
|
kernel.displayHtml {
|
||||||
fragment: HtmlVisionFragment,
|
p {
|
||||||
): String = createHTML().apply {
|
style = "color: red;"
|
||||||
val id = "fragment[${fragment.hashCode()}/${Random.nextUInt()}]"
|
+"VisionForge server stopped"
|
||||||
div {
|
|
||||||
this.id = id
|
|
||||||
val engine = engine
|
|
||||||
if (engine != null) {
|
|
||||||
//if server exist, serve dynamically
|
|
||||||
//server.serveVisionsFromFragment(consumer, "content-${counter++}", fragment)
|
|
||||||
val cellRoute = "content-${counter++}"
|
|
||||||
|
|
||||||
val collector: MutableMap<Name, Vision> = mutableMapOf()
|
|
||||||
|
|
||||||
val url = engine.environment.connectors.first().let {
|
|
||||||
url {
|
|
||||||
protocol = URLProtocol.WS
|
|
||||||
host = it.host
|
|
||||||
port = it.port
|
|
||||||
pathSegments = listOf(cellRoute, "ws")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
engine.application.serveVisionData(VisionRoute(cellRoute, visionManager), collector)
|
|
||||||
|
|
||||||
visionFragment(
|
|
||||||
visionManager,
|
|
||||||
embedData = true,
|
|
||||||
updatesUrl = url,
|
|
||||||
onVisionRendered = { name, vision -> collector[name] = vision },
|
|
||||||
fragment = fragment
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
//if not, use static rendering
|
|
||||||
visionFragment(visionManager, fragment = fragment)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
renderScriptForId(id)
|
}
|
||||||
}.finalize()
|
|
||||||
|
|
||||||
public fun produceHtml(isolated: Boolean? = null, fragment: HtmlVisionFragment): MimeTypedResult =
|
internal fun TagConsumer<*>.renderScriptForId(id: String, iframeIsolation: Boolean = false) {
|
||||||
HTML(produceHtmlString(fragment), isolated ?: isolateFragments)
|
script {
|
||||||
|
type = "text/javascript"
|
||||||
|
if (iframeIsolation) {
|
||||||
|
//language=JavaScript
|
||||||
|
unsafe { +"parent.VisionForge.renderAllVisionsById(document, \"$id\");" }
|
||||||
|
} else {
|
||||||
|
//language=JavaScript
|
||||||
|
unsafe { +"VisionForge.renderAllVisionsById(document, \"$id\");" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public fun fragment(body: HtmlVisionFragment): MimeTypedResult = produceHtml(fragment = body)
|
|
||||||
public fun page(body: HtmlVisionFragment): MimeTypedResult = produceHtml(true, body)
|
public fun produceHtml(
|
||||||
|
isolated: Boolean? = null,
|
||||||
|
fragment: HtmlVisionFragment,
|
||||||
|
): MimeTypedResult {
|
||||||
|
val iframeIsolation = isolated
|
||||||
|
?: (notebookMode == VisionForgeCompatibility.JUPYTER || notebookMode == VisionForgeCompatibility.DATALORE)
|
||||||
|
return HTML(
|
||||||
|
iframeIsolation
|
||||||
|
) {
|
||||||
|
val id = "fragment[${fragment.hashCode()}/${Random.nextUInt()}]"
|
||||||
|
div {
|
||||||
|
this.id = id
|
||||||
|
val engine = engine
|
||||||
|
if (engine != null) {
|
||||||
|
//if server exist, serve dynamically
|
||||||
|
//server.serveVisionsFromFragment(consumer, "content-${counter++}", fragment)
|
||||||
|
val cellRoute = "content-${counter++}"
|
||||||
|
|
||||||
|
val collector: MutableMap<Name, Vision> = mutableMapOf()
|
||||||
|
|
||||||
|
val url = engine.environment.connectors.first().let {
|
||||||
|
url {
|
||||||
|
protocol = URLProtocol.WS
|
||||||
|
host = it.host
|
||||||
|
port = it.port
|
||||||
|
pathSegments = listOf(cellRoute, "ws")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.application.serveVisionData(VisionRoute(cellRoute, visionManager), collector)
|
||||||
|
|
||||||
|
visionFragment(
|
||||||
|
visionManager,
|
||||||
|
embedData = true,
|
||||||
|
updatesUrl = url,
|
||||||
|
onVisionRendered = { name, vision -> collector[name] = vision },
|
||||||
|
fragment = fragment
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
//if not, use static rendering
|
||||||
|
visionFragment(visionManager, fragment = fragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderScriptForId(id, iframeIsolation = iframeIsolation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public fun form(builder: FORM.() -> Unit): HtmlFormFragment =
|
public fun form(builder: FORM.() -> Unit): HtmlFormFragment =
|
||||||
HtmlFormFragment("form[${counter++}]", builder = builder)
|
HtmlFormFragment("form[${counter++}]", builder = builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package space.kscience.visionforge.jupyter
|
package space.kscience.visionforge.jupyter
|
||||||
|
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlinx.html.stream.createHTML
|
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
|
||||||
import org.jetbrains.kotlinx.jupyter.api.HTML
|
|
||||||
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
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
@ -31,11 +30,12 @@ public abstract class VisionForgeIntegration(
|
|||||||
|
|
||||||
onLoaded {
|
onLoaded {
|
||||||
declare("VisionForge" to handler, "vf" to handler)
|
declare("VisionForge" to handler, "vf" to handler)
|
||||||
|
handler.startServer(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onShutdown {
|
onShutdown {
|
||||||
handler.stopServer()
|
handler.stopServer(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
import(
|
import(
|
||||||
@ -43,14 +43,14 @@ public abstract class VisionForgeIntegration(
|
|||||||
"space.kscience.visionforge.html.*",
|
"space.kscience.visionforge.html.*",
|
||||||
"space.kscience.visionforge.jupyter.*"
|
"space.kscience.visionforge.jupyter.*"
|
||||||
)
|
)
|
||||||
|
//
|
||||||
render<HtmlFragment> { fragment ->
|
// render<HtmlFragment> { fragment ->
|
||||||
handler.produceHtml(fragment = fragment)
|
// HTML(fragment.renderToString())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
render<HtmlVisionFragment> { fragment ->
|
// render<HtmlVisionFragment> { fragment ->
|
||||||
handler.produceHtml(fragment = fragment)
|
// handler.produceHtml(fragment = fragment)
|
||||||
}
|
// }
|
||||||
|
|
||||||
render<Vision> { vision ->
|
render<Vision> { vision ->
|
||||||
handler.produceHtml {
|
handler.produceHtml {
|
||||||
@ -59,13 +59,13 @@ public abstract class VisionForgeIntegration(
|
|||||||
}
|
}
|
||||||
|
|
||||||
render<VisionPage> { page ->
|
render<VisionPage> { page ->
|
||||||
HTML(createHTML().apply {
|
HTML(true) {
|
||||||
head {
|
head {
|
||||||
meta {
|
meta {
|
||||||
charset = "utf-8"
|
charset = "utf-8"
|
||||||
}
|
}
|
||||||
page.pageHeaders.values.forEach {
|
page.pageHeaders.values.forEach {
|
||||||
fragment(it)
|
appendFragment(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
@ -74,9 +74,11 @@ public abstract class VisionForgeIntegration(
|
|||||||
this.id = id
|
this.id = id
|
||||||
visionFragment(visionManager, fragment = page.content)
|
visionFragment(visionManager, fragment = page.content)
|
||||||
}
|
}
|
||||||
renderScriptForId(id)
|
with(handler) {
|
||||||
|
renderScriptForId(id, true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.finalize(), true)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render<HtmlFormFragment> { fragment ->
|
render<HtmlFormFragment> { fragment ->
|
||||||
@ -87,7 +89,7 @@ public abstract class VisionForgeIntegration(
|
|||||||
+"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()."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fragment(fragment.formBody)
|
appendFragment(fragment.formBody)
|
||||||
vision(fragment.vision)
|
vision(fragment.vision)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,10 +98,25 @@ public abstract class VisionForgeIntegration(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a fragment without a head to be embedded in the page
|
||||||
|
*/
|
||||||
|
@Suppress("UnusedReceiverParameter")
|
||||||
|
public fun VisionForge.html(body: TagConsumer<*>.() -> Unit): MimeTypedResult = HTML(false, body)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a fragment without a head to be embedded in the page
|
||||||
|
*/
|
||||||
|
public fun VisionForge.fragment(body: VisionTagConsumer<*>.() -> Unit): MimeTypedResult = produceHtml(false, body)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a standalone page in the notebook
|
* Create a standalone page in the notebook
|
||||||
*/
|
*/
|
||||||
public fun VisionForge.page(
|
public fun VisionForge.page(
|
||||||
pageHeaders: Map<String, HtmlFragment> = emptyMap(),
|
pageHeaders: Map<String, HtmlFragment> = emptyMap(),
|
||||||
content: HtmlVisionFragment
|
body: VisionTagConsumer<*>.() -> Unit,
|
||||||
): VisionPage = VisionPage(visionManager, pageHeaders, content)
|
): VisionPage = VisionPage(visionManager, pageHeaders, body)
|
||||||
|
|
||||||
|
@ -6,8 +6,12 @@ import space.kscience.dataforge.context.Context
|
|||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.gdml.Gdml
|
import space.kscience.gdml.Gdml
|
||||||
import space.kscience.plotly.Plot
|
import space.kscience.plotly.Plot
|
||||||
|
import space.kscience.plotly.PlotlyPage
|
||||||
|
import space.kscience.plotly.StaticPlotlyRenderer
|
||||||
import space.kscience.tables.*
|
import space.kscience.tables.*
|
||||||
import space.kscience.visionforge.gdml.toVision
|
import space.kscience.visionforge.gdml.toVision
|
||||||
|
import space.kscience.visionforge.html.HtmlFragment
|
||||||
|
import space.kscience.visionforge.html.VisionPage
|
||||||
import space.kscience.visionforge.markup.MarkupPlugin
|
import space.kscience.visionforge.markup.MarkupPlugin
|
||||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||||
import space.kscience.visionforge.plotly.asVision
|
import space.kscience.visionforge.plotly.asVision
|
||||||
@ -23,7 +27,7 @@ public class JupyterCommonIntegration : VisionForgeIntegration(CONTEXT.visionMan
|
|||||||
override fun Builder.afterLoaded() {
|
override fun Builder.afterLoaded() {
|
||||||
|
|
||||||
resources {
|
resources {
|
||||||
js("three") {
|
js("visionforge-common") {
|
||||||
classPath("js/visionforge-jupyter-common.js")
|
classPath("js/visionforge-jupyter-common.js")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,6 +59,24 @@ public class JupyterCommonIntegration : VisionForgeIntegration(CONTEXT.visionMan
|
|||||||
vision { plot.asVision() }
|
vision { plot.asVision() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render<PlotlyPage> { plotlyPage ->
|
||||||
|
val headers = plotlyPage.headers.associate { plotlyFragment ->
|
||||||
|
plotlyFragment.hashCode().toString(16) to HtmlFragment {
|
||||||
|
plotlyFragment.visit(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
VisionPage(visionManager, headers) {
|
||||||
|
div{
|
||||||
|
p { +"Plotly page renderer is not recommended in VisionForge, use `vf.page{}`" }
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
plotlyPage.fragment.render.invoke(this, StaticPlotlyRenderer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
@ -3,6 +3,7 @@ package space.kscience.visionforge.three
|
|||||||
import kotlinx.html.stream.createHTML
|
import kotlinx.html.stream.createHTML
|
||||||
import space.kscience.visionforge.html.ResourceLocation
|
import space.kscience.visionforge.html.ResourceLocation
|
||||||
import space.kscience.visionforge.html.VisionPage
|
import space.kscience.visionforge.html.VisionPage
|
||||||
|
import space.kscience.visionforge.html.appendTo
|
||||||
import space.kscience.visionforge.html.importScriptHeader
|
import space.kscience.visionforge.html.importScriptHeader
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ class TestServerExtensions {
|
|||||||
VisionPage.importScriptHeader(
|
VisionPage.importScriptHeader(
|
||||||
"js/visionforge-three.js",
|
"js/visionforge-three.js",
|
||||||
ResourceLocation.SYSTEM
|
ResourceLocation.SYSTEM
|
||||||
).invoke(this)
|
).appendTo(this)
|
||||||
}.finalize()
|
}.finalize()
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user