From e95f73d94d7de7fb5d1031198b20ca7efcb07c4f Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 6 Dec 2022 22:49:02 +0300 Subject: [PATCH] Working on data viewer UI --- build.gradle.kts | 2 +- gradle.properties | 1 + numass-data-server/build.gradle.kts | 10 +- .../ru/inr/mass/data/server/NumassJsPlugin.kt | 4 +- .../data/server/NumassViewerApplication.kt | 27 +++ .../kotlin/ru/inr/mass/data/server/server.kt | 178 ++++++++++-------- settings.gradle.kts | 1 + 7 files changed, 136 insertions(+), 87 deletions(-) create mode 100644 numass-data-server/src/jsMain/kotlin/ru/inr/mass/data/server/NumassViewerApplication.kt diff --git a/build.gradle.kts b/build.gradle.kts index 567d7d0..5ef9974 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,7 @@ allprojects { val dataforgeVersion by extra("0.6.0-dev-15") val tablesVersion: String by extra("0.2.0-dev-3") val kmathVersion by extra("0.3.1-dev-6") -val visionForgeVersion: String by rootProject.extra("0.3.0-dev-4") +val visionForgeVersion: String by rootProject.extra("0.3.0-dev-6") ksciencePublish{ diff --git a/gradle.properties b/gradle.properties index a514121..29eb27f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,3 +13,4 @@ org.gradle.parallel=true org.gradle.jvmargs=-XX:MaxMetaspaceSize=1G toolsVersion=0.13.3-kotlin-1.7.20 +compose.version=1.2.1 diff --git a/numass-data-server/build.gradle.kts b/numass-data-server/build.gradle.kts index b57adf7..670453e 100644 --- a/numass-data-server/build.gradle.kts +++ b/numass-data-server/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("space.kscience.gradle.mpp") + id("org.jetbrains.compose") `maven-publish` } @@ -28,7 +29,14 @@ kotlin { jvmMain { dependencies { implementation(project(":numass-data-proto")) - implementation("space.kscience:visionforge-server:$visionForgeVersion") + implementation("io.ktor:ktor-server-cio:2.1.3") + implementation("io.ktor:ktor-server-html-builder-jvm:2.1.3") + implementation("space.kscience:visionforge-plotly:$visionForgeVersion") + } + } + jsMain{ + dependencies{ + implementation(compose.web.core) } } diff --git a/numass-data-server/src/jsMain/kotlin/ru/inr/mass/data/server/NumassJsPlugin.kt b/numass-data-server/src/jsMain/kotlin/ru/inr/mass/data/server/NumassJsPlugin.kt index 3536c61..c30acb6 100644 --- a/numass-data-server/src/jsMain/kotlin/ru/inr/mass/data/server/NumassJsPlugin.kt +++ b/numass-data-server/src/jsMain/kotlin/ru/inr/mass/data/server/NumassJsPlugin.kt @@ -37,7 +37,7 @@ public class NumassJsPlugin : AbstractPlugin(), ElementVisionRenderer { else -> super.content(target) } - override fun render(element: Element, vision: Vision, meta: Meta) { + override fun render(element: Element, name: Name, vision: Vision, meta: Meta) { when (vision) { is VisionOfNumassHv -> element.append { h1 { +"HV" } @@ -64,7 +64,7 @@ public class NumassJsPlugin : AbstractPlugin(), ElementVisionRenderer { vision.spectra.forEach { (channel, spectrum) -> val pairs = spectrum.entries.sortedBy { it.key } scatter { - name = channel + this.name = channel mode = ScatterMode.lines line { shape = LineShape.hv diff --git a/numass-data-server/src/jsMain/kotlin/ru/inr/mass/data/server/NumassViewerApplication.kt b/numass-data-server/src/jsMain/kotlin/ru/inr/mass/data/server/NumassViewerApplication.kt new file mode 100644 index 0000000..b228c17 --- /dev/null +++ b/numass-data-server/src/jsMain/kotlin/ru/inr/mass/data/server/NumassViewerApplication.kt @@ -0,0 +1,27 @@ +package ru.inr.mass.data.server + +import org.jetbrains.compose.web.dom.Div +import org.jetbrains.compose.web.renderComposable +import org.w3c.dom.Document +import space.kscience.dataforge.context.Context +import space.kscience.visionforge.Application + +public class NumassViewerApplication : Application { + private val context = Context("NumassViewer") { + plugin(NumassJsPlugin) + } + + override fun start(document: Document, state: Map) { + renderComposable(rootElementId = "application") { + Div({ classes("container") }) { + Div({ classes("row") }) + Div({ classes("col-md-3") }) { + + } + Div({ classes("col-md-9") }) { + + } + } + } + } +} \ No newline at end of file diff --git a/numass-data-server/src/jvmMain/kotlin/ru/inr/mass/data/server/server.kt b/numass-data-server/src/jvmMain/kotlin/ru/inr/mass/data/server/server.kt index c6d089c..eb2aad0 100644 --- a/numass-data-server/src/jvmMain/kotlin/ru/inr/mass/data/server/server.kt +++ b/numass-data-server/src/jvmMain/kotlin/ru/inr/mass/data/server/server.kt @@ -1,15 +1,19 @@ package ru.inr.mass.data.server import io.ktor.http.HttpStatusCode -import io.ktor.http.URLBuilder +import io.ktor.server.application.Application import io.ktor.server.application.call import io.ktor.server.cio.CIO import io.ktor.server.engine.embeddedServer +import io.ktor.server.html.respondHtml +import io.ktor.server.http.content.resources import io.ktor.server.response.respondText import io.ktor.server.routing.get import io.ktor.server.routing.routing import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext +import kotlinx.html.* import ru.inr.mass.data.api.NumassPoint import ru.inr.mass.data.proto.NumassDirectorySet import ru.inr.mass.data.proto.NumassProtoPlugin @@ -22,12 +26,15 @@ import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.cutLast import space.kscience.dataforge.names.lastOrNull -import space.kscience.visionforge.server.close -import space.kscience.visionforge.server.openInBrowser -import space.kscience.visionforge.server.visionServer -public suspend fun main() { +public fun main() { + val port = 7777 + val host = "localhost" + embeddedServer(CIO, port, host, module = Application::numassModule).start() +} + +public fun Application.numassModule() { val context = Context("Numass") { plugin(NumassProtoPlugin) plugin(NumassCommonPlugin) @@ -40,93 +47,98 @@ public suspend fun main() { val repositroyName = "D:\\Work\\Numass\\data\\test" - val port = 7777 - val host = "localhost" + val repository: DataTree = runBlocking { numassProto.readRepository(repositroyName) } - val url = URLBuilder(host = host, port = port).build() + routing { + resources() - val repository: DataTree = numassProto.readRepository(repositroyName) - - val visionOfNumassRepository = VisionOfNumassRepository(Name.EMPTY, repository) - - val server = context.embeddedServer(CIO, port, host) { - routing { - get("/repository") { - call.respondText { - visionManager.encodeToString(visionOfNumassRepository) + get("/") { + call.respondHtml { + head { + meta { charset = "utf-8" } + meta { + name = "viewport" + content = "width=device-width, initial-scale=1" + } + title("Numass Data Viewer") + link { + href = "https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" + rel = "stylesheet" + attributes["integrity"] = + "sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" + attributes["crossorigin"] = "anonymous" + } } - } - - get("/sets/{name...}") { - val setName: Name? = call.parameters.getAll("name") - ?.map { NameToken.parse(it) }?.let(::Name) - - if (setName == null) { - call.respondText(status = HttpStatusCode.BadRequest) { "Set name is empty" } - return@get - } - - val set: NumassDirectorySet? = withContext(Dispatchers.IO) { repository[setName]?.await() } - if (set == null) { - call.respondText(status = HttpStatusCode.NotFound) { "A set with name $setName not found in the repository" } - return@get - } - - call.respondText { - visionManager.encodeToString(VisionOfNumassSet(setName, set)) - } - } - get("/points/{name...}") { - val fullName: Name? = call.parameters.getAll("name") - ?.map { NameToken.parse(it) }?.let(::Name) - - if (fullName == null) { - call.respondText(status = HttpStatusCode.BadRequest) { "Point name is empty" } - return@get - } - - val setName = fullName.cutLast() - - val set: NumassDirectorySet? = withContext(Dispatchers.IO) { repository[setName]?.await() } - if (set == null) { - call.respondText(status = HttpStatusCode.NotFound) { "A set with name $setName not found in the repository" } - return@get - } - - val pointIndex: Int? = fullName.lastOrNull()?.body?.toIntOrNull() - - val point: NumassPoint? = set.points.find { it.index == pointIndex } - - if (point == null) { - call.respondText(status = HttpStatusCode.NotFound) { "A point with name $setName/$pointIndex not found in the repository" } - return@get - } - call.respondText { - visionManager.encodeToString(point.toVision()) + body { + div { + id = "application" + } + script { + src = "js/numass-web.js" + } + script { + src = "https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" + integrity = "sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" + attributes["crossorigin"] = "anonymous" + } } } } - visionServer(numassCommon.visionManager, url) - }.start() -// val server = context.visionManager.serve { -// header("numass", VisionPage.scriptHeader("js/numass-web.js")) -// page { -// div("flex-column") { -// h1 { +"Visionforge file demo" } -// vision { visionOfNumass } -// } -// } -// } + get("/repository") { + call.respondText { + visionManager.encodeToString(VisionOfNumassRepository(Name.EMPTY, repository)) + } + } - server.openInBrowser() + get("/sets/{name...}") { + val setName: Name? = call.parameters.getAll("name") + ?.map { NameToken.parse(it) }?.let(::Name) + if (setName == null) { + call.respondText(status = HttpStatusCode.BadRequest) { "Set name is empty" } + return@get + } - println("Enter 'exit' to close server") - while (readLine() != "exit") { - // + val set: NumassDirectorySet? = withContext(Dispatchers.IO) { repository[setName]?.await() } + if (set == null) { + call.respondText(status = HttpStatusCode.NotFound) { "A set with name $setName not found in the repository" } + return@get + } + + call.respondText { + visionManager.encodeToString(VisionOfNumassSet(setName, set)) + } + } + get("/points/{name...}") { + val fullName: Name? = call.parameters.getAll("name") + ?.map { NameToken.parse(it) }?.let(::Name) + + if (fullName == null) { + call.respondText(status = HttpStatusCode.BadRequest) { "Point name is empty" } + return@get + } + + val setName = fullName.cutLast() + + val set: NumassDirectorySet? = withContext(Dispatchers.IO) { repository[setName]?.await() } + if (set == null) { + call.respondText(status = HttpStatusCode.NotFound) { "A set with name $setName not found in the repository" } + return@get + } + + val pointIndex: Int? = fullName.lastOrNull()?.body?.toIntOrNull() + + val point: NumassPoint? = set.points.find { it.index == pointIndex } + + if (point == null) { + call.respondText(status = HttpStatusCode.NotFound) { "A point with name $setName/$pointIndex not found in the repository" } + return@get + } + call.respondText { + visionManager.encodeToString(point.toVision()) + } + } } - - server.close() - + //serveVisionData(VisionRoute("/visions", visionManager)) } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 67bdd00..70e2d4b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,6 +15,7 @@ pluginManagement { } plugins { + id("org.jetbrains.compose").version(extra["compose.version"] as String) id("space.kscience.gradle.project") version toolsVersion id("space.kscience.gradle.mpp") version toolsVersion id("space.kscience.gradle.jvm") version toolsVersion