You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by jo...@apache.org on 2021/12/09 16:34:56 UTC

[isis] branch master updated: ISIS-2913 system icon settable, Command renamed to Controller, preparations for browser and shell

This is an automated email from the ASF dual-hosted git repository.

joergrade pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 7ed85d3  ISIS-2913 system icon settable, Command renamed to Controller, preparations for browser and shell
     new 74ac6e3  Merge remote-tracking branch 'origin/master'
7ed85d3 is described below

commit 7ed85d33efa75cfcdd2b16157c389a91f23c30f8
Author: Jörg Rade <jo...@kuehne-nagel.com>
AuthorDate: Thu Dec 9 17:34:02 2021 +0100

    ISIS-2913 system icon settable, Command renamed to Controller, preparations for browser and shell
---
 incubator/clients/kroviz/build.gradle.kts          |   1 +
 .../{ReplayCommand.kt => ReplayController.kt}      |   4 +-
 .../org/apache/isis/client/kroviz/to/TypeMapper.kt |   1 +
 .../apache/isis/client/kroviz/ui/core/Constants.kt |   1 +
 .../isis/client/kroviz/ui/core/FormPanelFactory.kt |  39 +++++-------
 .../apache/isis/client/kroviz/ui/core/RoDialog.kt  |  12 ++--
 .../apache/isis/client/kroviz/ui/core/RoMenuBar.kt |  69 ++++++++++++++++++---
 .../apache/isis/client/kroviz/ui/dialog/About.kt   |   4 +-
 .../isis/client/kroviz/ui/dialog/ActionPrompt.kt   |   4 +-
 .../isis/client/kroviz/ui/dialog/BrowserWindow.kt  |  28 ++++++---
 .../kroviz/ui/dialog/{Command.kt => Controller.kt} |   2 +-
 .../isis/client/kroviz/ui/dialog/DiagramDialog.kt  |   4 +-
 .../isis/client/kroviz/ui/dialog/DownloadDialog.kt |   6 +-
 .../isis/client/kroviz/ui/dialog/ErrorDialog.kt    |   4 +-
 .../client/kroviz/ui/dialog/EventCompareDialog.kt  |   7 +--
 .../isis/client/kroviz/ui/dialog/EventDialog.kt    |   8 +--
 .../client/kroviz/ui/dialog/EventExportDialog.kt   |   6 +-
 .../client/kroviz/ui/dialog/EventImportDialog.kt   |   6 +-
 .../isis/client/kroviz/ui/dialog/EventLogDetail.kt |   6 +-
 .../client/kroviz/ui/dialog/EventReplayDialog.kt   |   4 +-
 .../isis/client/kroviz/ui/dialog/FileDialog.kt     |   4 +-
 .../isis/client/kroviz/ui/dialog/LoginPrompt.kt    |  13 ++--
 .../client/kroviz/ui/dialog/NotificationDialog.kt  |   4 +-
 .../kroviz/ui/dialog/ResponseComparisonDialog.kt   |   6 +-
 .../{NotificationDialog.kt => ShellWindow.kt}      |  43 +++++++++----
 .../isis/client/kroviz/ui/dialog/SvgInline.kt      |   4 +-
 .../client/kroviz/ui/dialog/UndefinedDialog.kt     |   4 +-
 .../apache/isis/client/kroviz/utils/IconManager.kt |   1 +
 .../dialog/BrowserWindow.kt => utils/js/Xterm.kt}  |  24 +++----
 .../kroviz/src/main/resources/css/kroviz.css       |  25 ++++++++
 .../kroviz/src/main/resources/img/gift_48.png      | Bin 0 -> 7020 bytes
 .../kroviz/src/main/resources/img/incode_org.gif   | Bin 0 -> 6591 bytes
 32 files changed, 218 insertions(+), 126 deletions(-)

diff --git a/incubator/clients/kroviz/build.gradle.kts b/incubator/clients/kroviz/build.gradle.kts
index b689db5..a6e1dc8 100644
--- a/incubator/clients/kroviz/build.gradle.kts
+++ b/incubator/clients/kroviz/build.gradle.kts
@@ -105,6 +105,7 @@ kotlin {
         implementation(npm("diff", "5.0.0", false))
         implementation(npm("diff2html", "3.4.13", false))
         implementation(npm("xml-beautify", "1.1.2", false))
+        implementation(npm("xterm", "4.15.0", false))
     }
     sourceSets["test"].dependencies {
         implementation(kotlin("test-js"))
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/core/event/ReplayCommand.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/core/event/ReplayController.kt
similarity index 97%
rename from incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/core/event/ReplayCommand.kt
rename to incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/core/event/ReplayController.kt
index 3cc1997..b10daf9 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/core/event/ReplayCommand.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/core/event/ReplayController.kt
@@ -29,12 +29,12 @@ import org.apache.isis.client.kroviz.to.Represention
 import org.apache.isis.client.kroviz.to.TObject
 import org.apache.isis.client.kroviz.ui.core.Constants
 import org.apache.isis.client.kroviz.ui.core.UiManager
-import org.apache.isis.client.kroviz.ui.dialog.Command
+import org.apache.isis.client.kroviz.ui.dialog.Controller
 import org.apache.isis.client.kroviz.ui.dialog.EventReplayDialog
 
 val AppScope = CoroutineScope(window.asCoroutineDispatcher())
 
-class ReplayCommand : Command() {
+class ReplayController : Controller() {
     private val eventStore = UiManager.getEventStore()
     private val oldBaseUrl = UiManager.getBaseUrl()
     private var urlUnderTest: String = Constants.demoUrlRemote
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/to/TypeMapper.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/to/TypeMapper.kt
index 130207f..3a923b8 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/to/TypeMapper.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/to/TypeMapper.kt
@@ -33,6 +33,7 @@ enum class ValueType(val type: String) {
     TIME("Time"),
     SIMPLE_SELECT("SimpleSelect"),
     SLIDER("Slider"),
+    SHELL("Shell"),
     SVG_MAPPED("Map"),
     SVG_INLINE("Inline"),
     IFRAME("IFrame")
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/Constants.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/Constants.kt
index 53505fd..b546274 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/Constants.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/Constants.kt
@@ -39,6 +39,7 @@ object Constants {
     const val demoUser = "sven"
     const val demoPass = "pass"
     const val demoUrlRemote = "https://demo-wicket.jdo.isis.incode.work/"
+    const val domoxUrl = "http://localhost:8081/"
 
     const val spacing = 10
 }
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/FormPanelFactory.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/FormPanelFactory.kt
index 9c0a852..6070a1f 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/FormPanelFactory.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/FormPanelFactory.kt
@@ -19,7 +19,6 @@
 package org.apache.isis.client.kroviz.ui.core
 
 import io.kvision.core.Component
-import io.kvision.core.Overflow
 import io.kvision.core.StringPair
 import io.kvision.core.onEvent
 import io.kvision.form.FormPanel
@@ -36,14 +35,13 @@ import io.kvision.form.time.dateTime
 import io.kvision.html.Button
 import io.kvision.html.Div
 import io.kvision.html.Iframe
-import io.kvision.html.Image
 import io.kvision.panel.VPanel
 import io.kvision.panel.vPanel
 import io.kvision.utils.auto
 import io.kvision.utils.perc
 import io.kvision.utils.px
 import org.apache.isis.client.kroviz.to.ValueType
-import org.apache.isis.client.kroviz.ui.dialog.Command
+import org.apache.isis.client.kroviz.ui.dialog.Controller
 import org.apache.isis.client.kroviz.ui.panel.SvgPanel
 import org.apache.isis.client.kroviz.utils.DateHelper
 import org.apache.isis.client.kroviz.utils.IconManager
@@ -71,7 +69,8 @@ class FormPanelFactory(items: List<FormItem>) : VPanel() {
                     ValueType.IMAGE -> add(createImage(fi))
                     ValueType.SLIDER -> add(createSlider(fi))
                     ValueType.IFRAME -> add(createIFrame(fi))
-                    ValueType.SVG_INLINE -> add(createSvgInline(fi))
+                    ValueType.SHELL -> add(createInline(fi))
+                    ValueType.SVG_INLINE -> add(createInline(fi))
                     ValueType.SVG_MAPPED -> add(createSvgMap(fi))
                     ValueType.BUTTON -> add(createButton(fi))
                 }
@@ -81,7 +80,7 @@ class FormPanelFactory(items: List<FormItem>) : VPanel() {
 
     private fun createButton(fi: FormItem): Button {
         val item = Button(text = fi.label, icon = IconManager.find(fi.label))
-        val obj = fi.callBack!! as Command
+        val obj = fi.callBack!! as Controller
         val action = fi.callBackAction
         item.onClick {
             obj.execute(action)
@@ -106,9 +105,9 @@ class FormPanelFactory(items: List<FormItem>) : VPanel() {
     private fun createDate(fi: FormItem): DateTime {
         val date = DateHelper.toDate(fi.content)
         return dateTime(
-                format = "YYYY-MM-DD",
-                label = fi.label,
-                value = date
+            format = "YYYY-MM-DD",
+            label = fi.label,
+            value = date
         )
     }
 
@@ -182,13 +181,12 @@ class FormPanelFactory(items: List<FormItem>) : VPanel() {
                 }
             }
         }
-        panel.height = auto
-        panel.width = auto
-        panel.overflow = Overflow.AUTO
+        panel.addCssClass("form-panel")
         return panel
     }
 
-    private fun createSvgInline(fi: FormItem): VPanel {
+    // used eg. for SVG placement
+    private fun createInline(fi: FormItem): VPanel {
         val panel = VPanel {
             when (val fcb = fi.callBack) {
                 is UUID -> {
@@ -201,17 +199,13 @@ class FormPanelFactory(items: List<FormItem>) : VPanel() {
                 }
             }
         }
-        panel.height = auto
-        panel.width = auto
-        panel.overflow = Overflow.AUTO
+        panel.addCssClass("form-panel")
         return panel
     }
 
     private fun createSvgMap(fi: FormItem): SvgPanel {
         val panel = SvgPanel()
-        panel.height = auto
-        panel.width = auto
-        panel.overflow = Overflow.AUTO
+        panel.addCssClass("form-panel")
         fi.callBack = panel
         return panel
     }
@@ -228,18 +222,15 @@ class FormPanelFactory(items: List<FormItem>) : VPanel() {
         return item
     }
 
+    // https://www.w3schools.com/howto/howto_css_responsive_iframes.asp
     private fun createIFrame(fi: FormItem): VPanel {
         val item = VPanel {
             val url = fi.content as String
             val iframe = Iframe(url)
-            iframe.height = 100.perc
-            iframe.width = 100.perc
-            iframe.overflow = Overflow.INHERIT
+            iframe.addCssClass("responsive-iframe")
             add(iframe)
         }
-        item.height = 100.perc
-        item.width = 100.perc
-        item.overflow = Overflow.INHERIT
+        item.addCssClass("container")
         return item
     }
 
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/RoDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/RoDialog.kt
index 5c86aaf..eaafbe7 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/RoDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/RoDialog.kt
@@ -27,7 +27,7 @@ import io.kvision.html.ButtonStyle
 import io.kvision.panel.HPanel
 import io.kvision.panel.vPanel
 import org.apache.isis.client.kroviz.to.ValueType
-import org.apache.isis.client.kroviz.ui.dialog.Command
+import org.apache.isis.client.kroviz.ui.dialog.Controller
 import org.apache.isis.client.kroviz.ui.dialog.DiagramDialog
 import org.apache.isis.client.kroviz.ui.kv.override.RoWindow
 import org.apache.isis.client.kroviz.utils.Direction
@@ -38,7 +38,7 @@ import io.kvision.html.Link as KvisionHtmlLink
 class RoDialog(
     caption: String,
     val items: List<FormItem>,
-    val command: Command,
+    val controller: Controller,
     defaultAction: String = "OK",
     widthPerc: Int = 30,
     heightPerc: Int = 100,
@@ -72,7 +72,7 @@ class RoDialog(
         ButtonStyle.OUTLINEINFO
     )
         .onClick {
-            (command as DiagramDialog).scale(Direction.UP)
+            (controller as DiagramDialog).scale(Direction.UP)
         }
 
     @Deprecated("remove once leaflet/svg is fully operational")
@@ -82,7 +82,7 @@ class RoDialog(
         ButtonStyle.OUTLINEINFO
     )
         .onClick {
-            (command as DiagramDialog).scale(Direction.DOWN)
+            (controller as DiagramDialog).scale(Direction.DOWN)
         }
 
     var formPanel: FormPanel<String>? = null
@@ -125,7 +125,7 @@ class RoDialog(
     }
 
     private fun execute() {
-        command.execute()
+        controller.execute()
         close()
     }
 
@@ -162,7 +162,7 @@ class RoDialog(
 
     private fun createButton(fi: FormItem): Button {
         val item = Button(text = fi.label, icon = IconManager.find(fi.label))
-        val obj = fi.callBack!! as Command
+        val obj = fi.callBack!! as Controller
         val action = fi.callBackAction
         item.onClick {
             obj.execute(action)
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/RoMenuBar.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/RoMenuBar.kt
index d6870ba..90932d5 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/RoMenuBar.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/core/RoMenuBar.kt
@@ -19,27 +19,34 @@
 package org.apache.isis.client.kroviz.ui.core
 
 import io.kvision.core.CssSize
+import io.kvision.core.ResString
 import io.kvision.core.UNIT
+import io.kvision.core.style
 import io.kvision.dropdown.DropDown
+import io.kvision.dropdown.separator
 import io.kvision.html.ButtonStyle
 import io.kvision.html.Link
+import io.kvision.html.image
 import io.kvision.navbar.*
 import io.kvision.panel.SimplePanel
 import io.kvision.panel.vPanel
+import io.kvision.require
+import io.kvision.utils.px
 import org.apache.isis.client.kroviz.to.mb.Menubars
 import org.apache.isis.client.kroviz.ui.chart.SampleChartModel
-import org.apache.isis.client.kroviz.ui.dialog.About
-import org.apache.isis.client.kroviz.ui.dialog.EventDialog
-import org.apache.isis.client.kroviz.ui.dialog.LoginPrompt
-import org.apache.isis.client.kroviz.ui.dialog.SvgInline
-import org.apache.isis.client.kroviz.ui.panel.*
+import org.apache.isis.client.kroviz.ui.dialog.*
+import org.apache.isis.client.kroviz.ui.panel.EventChart
+import org.apache.isis.client.kroviz.ui.panel.GeoMap
+import org.apache.isis.client.kroviz.ui.panel.ImageSample
+import org.apache.isis.client.kroviz.ui.panel.SvgMap
 import org.apache.isis.client.kroviz.utils.IconManager
 import org.apache.isis.client.kroviz.utils.Point
-import org.apache.isis.client.kroviz.utils.TestUtils
 
 class RoMenuBar : SimplePanel() {
     lateinit var navbar: Navbar
     private lateinit var nav: Nav
+    private lateinit var mainEntry: DropDown
+    private lateinit var mainMenu: DropDown
 
     init {
         vPanel {
@@ -48,12 +55,48 @@ class RoMenuBar : SimplePanel() {
                 marginLeft = CssSize(-32, UNIT.px)
                 height = CssSize(40, UNIT.px)
                 nav = nav()
-                val mainEntry = buildMainMenu()
+                mainEntry = buildMainMenu()
                 nav.add(mainEntry)
             }
         }
     }
 
+    fun updateMainIcon() {
+        val resString = require("img/gift_48.png")
+        mainEntry.image = resString
+        mainEntry.icon = null
+        mainEntry.image.apply { systemIconStyle }
+        insertConnection()
+    }
+
+    fun insertConnection() {
+        mainEntry.separator()
+        val resString = require("img/gift_48.png")
+        val menuEntry = buildMenuEntryWithImage("Connection 1", image = resString, { LoginPrompt().open() })
+        mainEntry.add(menuEntry)
+    }
+
+    private fun buildMenuEntryWithImage(label: String, image: ResString?, action: dynamic): Link {
+        val link = Link(label, image = image, className = "dropdown-item").apply { appIconStyle }
+        link.onClick { e ->
+            val at = Point(e.pageX.toInt(), e.pageY.toInt())
+            UiManager.position = at
+            action()
+        }
+        return link
+    }
+
+    val systemIconStyle = style(".dropdown-toggle") {
+        style("img") {
+            height = 20.px
+        }
+    }
+    val appIconStyle = style(".dropdown-item") {
+        style("img") {
+            height = 20.px
+        }
+    }
+
     private fun buildMenuEntry(label: String, iconName: String, action: dynamic): Link {
         val icon = IconManager.find(iconName)
         val link = Link(label, icon = icon, className = "dropdown-item").onClick { e ->
@@ -65,7 +108,7 @@ class RoMenuBar : SimplePanel() {
     }
 
     private fun buildMainMenu(): DropDown {
-        val mainMenu = DropDown(
+        mainMenu = DropDown(
             "",
             icon = IconManager.find("Burger"),
             forNavbar = false,
@@ -115,7 +158,15 @@ class RoMenuBar : SimplePanel() {
 
         val testTitle = "Test"
         mainMenu.add(
-            buildMenuEntry(testTitle, "Test", { TestUtils.execute() })
+            buildMenuEntry(testTitle, "Test", { this.updateMainIcon() })
+        )
+
+        mainMenu.add(
+            buildMenuEntry("Browser in IFrame", "Wikipedia", { BrowserWindow("https://isis.apache.org/").open() })
+        )
+
+        mainMenu.add(
+            buildMenuEntry("SSH", "Terminal", { ShellWindow("localhost:8080").open() })
         )
 
         return mainMenu
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/About.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/About.kt
index 7f8bc70..489e8e8 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/About.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/About.kt
@@ -23,7 +23,7 @@ import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 import org.apache.isis.client.kroviz.utils.UUID
 
-class About : Command() {
+class About : Controller() {
     private val formItems = mutableListOf<FormItem>()
     private val _LI = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
 
@@ -44,7 +44,7 @@ class About : Command() {
                 widthPerc = 50,
                 caption = "About",
                 items = formItems,
-                command = this)
+                controller = this)
     }
 
 }
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ActionPrompt.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ActionPrompt.kt
index 5d8fbd5..1168b7f 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ActionPrompt.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ActionPrompt.kt
@@ -30,14 +30,14 @@ import io.kvision.form.select.SimpleSelect
 import io.kvision.form.text.TextArea
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 
-class ActionPrompt(val action: Action) : Command() {
+class ActionPrompt(val action: Action) : Controller() {
 
     fun open(at: Point) {
         val formItems = buildFormItems()
         dialog = RoDialog(
                 caption = buildLabel(),
                 items = formItems,
-                command = this)
+                controller = this)
         dialog.open(at)
     }
 
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/BrowserWindow.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/BrowserWindow.kt
index 8910240..93560fb 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/BrowserWindow.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/BrowserWindow.kt
@@ -18,20 +18,34 @@
  */
 package org.apache.isis.client.kroviz.ui.dialog
 
+import io.kvision.panel.SimplePanel
 import org.apache.isis.client.kroviz.to.ValueType
 import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
+import org.apache.isis.client.kroviz.ui.core.UiManager
 
-class BrowserWindow(val url: String) : Command() {
+class BrowserWindow(val url: String) : Controller() {
 
-    override fun open() {
+    init {
         val formItems = mutableListOf<FormItem>()
         formItems.add(FormItem("URL", ValueType.IFRAME, url))
-        RoDialog(
-                caption = url,
-                items = formItems,
-                command = this,
-                defaultAction = "Visualize").open()
+        dialog = RoDialog(
+            caption = url,
+            items = formItems,
+            controller = this,
+            widthPerc = 70,
+            heightPerc = 70,
+            defaultAction = "Pin"
+        )
+    }
+
+    fun execute() {
+        pin()
+    }
+
+    private fun pin() {
+        UiManager.add(url, dialog.formPanel as SimplePanel)
+        dialog.close()
     }
 
 }
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/Command.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/Controller.kt
similarity index 98%
rename from incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/Command.kt
rename to incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/Controller.kt
index 168c8dc..f5b4ec3 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/Command.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/Controller.kt
@@ -23,7 +23,7 @@ import org.apache.isis.client.kroviz.core.event.ResourceProxy
 import org.apache.isis.client.kroviz.to.Link
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 
-abstract class Command {
+abstract class Controller {
     lateinit var dialog: RoDialog
 
     open fun execute(action: String? = null) {
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/DiagramDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/DiagramDialog.kt
index 7252338..78df630 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/DiagramDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/DiagramDialog.kt
@@ -29,7 +29,7 @@ import io.kvision.html.Link as KvisionHtmlLink
 class DiagramDialog(
         var label: String,
         private var pumlCode: String
-) : Command() {
+) : Controller() {
 
     private var callBack: Any = UUID()
     private val formItems = mutableListOf<FormItem>()
@@ -48,7 +48,7 @@ class DiagramDialog(
                 heightPerc = 80,
                 caption = label,
                 items = formItems,
-                command = this,
+                controller = this,
                 defaultAction = "Pin",
                 menu = buildMenu()
         )
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/DownloadDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/DownloadDialog.kt
index 1d824b0..59eec70 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/DownloadDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/DownloadDialog.kt
@@ -24,14 +24,14 @@ import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 import org.apache.isis.client.kroviz.utils.DomUtil
 
-class DownloadDialog(val fileName:String, val content:String) : Command() {
+class DownloadDialog(val fileName:String, val content:String) : Controller() {
 
     val formItems = mutableListOf<FormItem>()
 
     override fun open() {
         formItems.add(FormItem("Preview", ValueType.TEXT_AREA, content, 15))
-        dialog = RoDialog(caption = "Download: $fileName", items = formItems, command = this)
-        dialog.open()
+        dialog = RoDialog(caption = "Download: $fileName", items = formItems, controller = this)
+        super.open()
     }
 
     override fun execute(action:String?) {
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ErrorDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ErrorDialog.kt
index 0c6a77f..1eb91eb 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ErrorDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ErrorDialog.kt
@@ -24,7 +24,7 @@ import org.apache.isis.client.kroviz.to.ValueType
 import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 
-class ErrorDialog(val logEntry: LogEntry) : Command() {
+class ErrorDialog(val logEntry: LogEntry) : Controller() {
 
     override fun open() {
         val error = logEntry.getTransferObject() as HttpErrorResponse
@@ -40,7 +40,7 @@ class ErrorDialog(val logEntry: LogEntry) : Command() {
         RoDialog(
             caption = label,
             items = formItems,
-            command = this,
+            controller = this,
             widthPerc = 80,
             heightPerc = 70
         ).open()
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventCompareDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventCompareDialog.kt
index 9547c12..ba3da6a 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventCompareDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventCompareDialog.kt
@@ -19,17 +19,14 @@
 package org.apache.isis.client.kroviz.ui.dialog
 
 import io.kvision.core.CssSize
-import io.kvision.core.FlexDirection
 import io.kvision.core.UNIT
-import io.kvision.html.table
 import io.kvision.panel.VPanel
-import io.kvision.tabulator.tabulator
 import org.apache.isis.client.kroviz.core.event.LogEntryComparison
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 import org.apache.isis.client.kroviz.ui.core.UiManager
 import org.apache.isis.client.kroviz.ui.panel.EventComparisonTable
 
-class EventCompareDialog(val data: List<LogEntryComparison>) : Command() {
+class EventCompareDialog(val data: List<LogEntryComparison>) : Controller() {
     private val title = "Event Comparison"
     private var table: EventComparisonTable
 
@@ -41,7 +38,7 @@ class EventCompareDialog(val data: List<LogEntryComparison>) : Command() {
         dialog = RoDialog(
             caption = title,
             items = mutableListOf(),
-            command = this,
+            controller = this,
             defaultAction = "Pin",
             widthPerc = 60,
             heightPerc = 70,
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventDialog.kt
index 49b172b..eb0535f 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventDialog.kt
@@ -23,14 +23,14 @@ import io.kvision.core.CssSize
 import io.kvision.core.FlexDirection
 import io.kvision.core.UNIT
 import io.kvision.panel.VPanel
-import org.apache.isis.client.kroviz.core.event.ReplayCommand
+import org.apache.isis.client.kroviz.core.event.ReplayController
 import org.apache.isis.client.kroviz.to.ValueType
 import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 import org.apache.isis.client.kroviz.ui.core.UiManager
 import org.apache.isis.client.kroviz.ui.panel.EventLogTable
 
-class EventDialog : Command() {
+class EventDialog : Controller() {
 
     private val eventPanel = VPanel(spacing = 3) {
         width = CssSize(100, UNIT.perc)
@@ -51,7 +51,7 @@ class EventDialog : Command() {
         dialog = RoDialog(
             caption = "Event History",
             items = mutableListOf(),
-            command = this,
+            controller = this,
             defaultAction = "Pin",
             widthPerc = 60,
             heightPerc = 70,
@@ -83,7 +83,7 @@ class EventDialog : Command() {
                 dialog.close()
             }
             action == REP -> {
-                LoginPrompt(nextCommand = ReplayCommand()).open()
+                LoginPrompt(nextController = ReplayController()).open()
                 dialog.close()
             }
             else -> {
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventExportDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventExportDialog.kt
index 8eda5b1..e8af8bb 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventExportDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventExportDialog.kt
@@ -28,7 +28,7 @@ import io.kvision.form.select.SimpleSelect
 import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.UiManager
 
-class EventExportDialog : Command() {
+class EventExportDialog : Controller() {
 
     private var output: String = ""
     val formItems = mutableListOf<FormItem>()
@@ -129,8 +129,8 @@ class EventExportDialog : Command() {
         filter.add(StringPair("UNFINISHED", "Unfinished"))
         formItems.add(FormItem("Filter", ValueType.SIMPLE_SELECT, filter))
 
-        dialog = RoDialog(caption = "Export", items = formItems, command = this)
-        dialog.open()
+        dialog = RoDialog(caption = "Export", items = formItems, controller = this)
+        super.open()
     }
 
     private fun asCsv(events: MutableList<ReplayEvent>): String {
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventImportDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventImportDialog.kt
index b41085e..42fa7ff 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventImportDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventImportDialog.kt
@@ -28,7 +28,7 @@ import io.kvision.form.select.SimpleSelect
 import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.UiManager
 
-class EventImportDialog : Command() {
+class EventImportDialog : Controller() {
 
     private var output: String = ""
     val formItems = mutableListOf<FormItem>()
@@ -129,8 +129,8 @@ class EventImportDialog : Command() {
         filter.add(StringPair("UNFINISHED", "Unfinished"))
         formItems.add(FormItem("Filter", ValueType.SIMPLE_SELECT, filter))
 
-        dialog = RoDialog(caption = "Export", items = formItems, command = this)
-        dialog.open()
+        dialog = RoDialog(caption = "Export", items = formItems, controller = this)
+        super.open()
     }
 
     private fun asCsv(events: MutableList<ReplayEvent>): String {
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventLogDetail.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventLogDetail.kt
index 8ee6e4d..22f6f0f 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventLogDetail.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventLogDetail.kt
@@ -33,7 +33,7 @@ import org.apache.isis.client.kroviz.utils.js.Flatted
 import org.apache.isis.client.kroviz.utils.StringUtils
 import org.apache.isis.client.kroviz.utils.XmlHelper
 
-class EventLogDetail(logEntryFromTabulator: LogEntry) : Command() {
+class EventLogDetail(logEntryFromTabulator: LogEntry) : Controller() {
     private var logEntry: LogEntry
 
     init {
@@ -68,11 +68,11 @@ class EventLogDetail(logEntryFromTabulator: LogEntry) : Command() {
         dialog = RoDialog(
                 caption = "Details :" + logEntry.title,
                 items = formItems,
-                command = this,
+                controller = this,
                 defaultAction = "Response Diagram",
                 widthPerc = 60,
                 customButtons = customButtons)
-        dialog.open()
+        super.open()
     }
 
     override fun execute(action: String?) {
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventReplayDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventReplayDialog.kt
index 3a1fdc9..748cf16 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventReplayDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/EventReplayDialog.kt
@@ -37,7 +37,7 @@ import org.apache.isis.client.kroviz.utils.StringUtils
 class EventReplayDialog(
     private val expectedEvents: List<LogEntry>,
     title: String
-) : Command() {
+) : Controller() {
 
     private val expectedPanel = VPanel(spacing = 3) {
         width = CssSize(20, UNIT.perc)
@@ -50,7 +50,7 @@ class EventReplayDialog(
         dialog = RoDialog(
             caption = title,
             items = mutableListOf(),
-            command = this,
+            controller = this,
             defaultAction = "Compare",
             widthPerc = 60,
             heightPerc = 70,
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/FileDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/FileDialog.kt
index 5f4bb3a..9d9b58f 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/FileDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/FileDialog.kt
@@ -24,7 +24,7 @@ import org.apache.isis.client.kroviz.to.ValueType
 import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 
-class FileDialog(val logEntry: LogEntry) : Command() {
+class FileDialog(val logEntry: LogEntry) : Controller() {
 
     override fun open() {
         val rv = logEntry.getTransferObject() as ResultValue
@@ -38,7 +38,7 @@ class FileDialog(val logEntry: LogEntry) : Command() {
         RoDialog(
                 caption = label,
                 items = formItems,
-                command = this).open()
+                controller = this).open()
     }
 
 }
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/LoginPrompt.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/LoginPrompt.kt
index 081aa52..b7246ca 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/LoginPrompt.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/LoginPrompt.kt
@@ -22,7 +22,7 @@ import io.kvision.core.StringPair
 import io.kvision.form.select.SimpleSelect
 import io.kvision.form.text.Password
 import io.kvision.form.text.Text
-import org.apache.isis.client.kroviz.core.event.ReplayCommand
+import org.apache.isis.client.kroviz.core.event.ReplayController
 import org.apache.isis.client.kroviz.to.Link
 import org.apache.isis.client.kroviz.to.ValueType
 import org.apache.isis.client.kroviz.ui.core.Constants
@@ -30,7 +30,7 @@ import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 import org.apache.isis.client.kroviz.ui.core.UiManager
 
-class LoginPrompt(val nextCommand: Command? = null) : Command() {
+class LoginPrompt(val nextController: Controller? = null) : Controller() {
 
     //Default values
     private var url = Constants.demoUrl
@@ -42,19 +42,20 @@ class LoginPrompt(val nextCommand: Command? = null) : Command() {
         val urlList = mutableListOf<StringPair>()
         urlList.add(StringPair(Constants.demoUrl, Constants.demoUrl))
         urlList.add(StringPair(Constants.demoUrlRemote, Constants.demoUrlRemote))
+        urlList.add(StringPair(Constants.domoxUrl, Constants.domoxUrl))
         formItems.add(FormItem("Url", ValueType.SIMPLE_SELECT, urlList))
         formItems.add(FormItem("User", ValueType.TEXT, username))
         formItems.add(FormItem("Password", ValueType.PASSWORD, password))
-        dialog = RoDialog(caption = "Connect", items = formItems, command = this, heightPerc = 27)
+        dialog = RoDialog(caption = "Connect", items = formItems, controller = this, heightPerc = 27)
         val at = UiManager.position!!
         dialog.open(at)
     }
 
     override fun execute(action: String?) {
         extractUserInput()
-        if (nextCommand is ReplayCommand) {
-            nextCommand.initUnderTest(url, username, password)
-            nextCommand.open()
+        if (nextController is ReplayController) {
+            nextController.initUnderTest(url, username, password)
+            nextController.open()
         } else {
             UiManager.login(url, username, password)
             val link = Link(href = url + Constants.restInfix)
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/NotificationDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/NotificationDialog.kt
index b03f86f..a1dbfb0 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/NotificationDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/NotificationDialog.kt
@@ -23,7 +23,7 @@ import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 import org.apache.isis.client.kroviz.ui.core.UiManager
 
-class NotificationDialog(val message: String) : Command() {
+class NotificationDialog(val message: String) : Controller() {
 
     override fun open() {
         val formItems = mutableListOf<FormItem>()
@@ -34,7 +34,7 @@ class NotificationDialog(val message: String) : Command() {
         RoDialog(
                 caption = label,
                 items = formItems,
-                command = this,
+                controller = this,
                 widthPerc = 80).open()
     }
 
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ResponseComparisonDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ResponseComparisonDialog.kt
index e6c85a8..1c71284 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ResponseComparisonDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ResponseComparisonDialog.kt
@@ -26,7 +26,7 @@ import org.apache.isis.client.kroviz.ui.core.RoDialog
 import org.apache.isis.client.kroviz.utils.js.Diff
 import org.apache.isis.client.kroviz.utils.js.Diff2Html
 
-class ResponseComparisonDialog(obj: LogEntryComparison) : Command() {
+class ResponseComparisonDialog(obj: LogEntryComparison) : Controller() {
 
     init {
         val html = diff2Html(obj)
@@ -38,12 +38,12 @@ class ResponseComparisonDialog(obj: LogEntryComparison) : Command() {
         dialog = RoDialog(
             caption = title,
             items = formItems,
-            command = this,
+            controller = this,
             widthPerc = 80,
             heightPerc = 70,
             customButtons = mutableListOf()
         )
-        dialog.open()
+        super.open()
     }
 
     private fun diff2Html(obj: LogEntryComparison): String {
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/NotificationDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ShellWindow.kt
similarity index 53%
copy from incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/NotificationDialog.kt
copy to incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ShellWindow.kt
index b03f86f..e64cea9 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/NotificationDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/ShellWindow.kt
@@ -18,28 +18,45 @@
  */
 package org.apache.isis.client.kroviz.ui.dialog
 
+import io.kvision.panel.SimplePanel
 import org.apache.isis.client.kroviz.to.ValueType
 import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 import org.apache.isis.client.kroviz.ui.core.UiManager
+import org.apache.isis.client.kroviz.utils.DomUtil
+import org.apache.isis.client.kroviz.utils.UUID
+import org.apache.isis.client.kroviz.utils.js.Xterm
 
-class NotificationDialog(val message: String) : Command() {
+class ShellWindow(val host: String) : Controller() {
+    val uuid = UUID()
 
-    override fun open() {
+    init {
         val formItems = mutableListOf<FormItem>()
-        val fi = FormItem("Message", ValueType.TEXT_AREA, message, size = 5)
-        fi.readOnly = true
-        formItems.add(fi)
-        val label = "Notifications"
-        RoDialog(
-                caption = label,
-                items = formItems,
-                command = this,
-                widthPerc = 80).open()
+        formItems.add(FormItem("SSH", ValueType.SHELL, host, callBack = uuid))
+        dialog = RoDialog(
+            caption = host,
+            items = formItems,
+            controller = this,
+            widthPerc = 70,
+            heightPerc = 70,
+            defaultAction = "Pin"
+        )
+    }
+
+    override fun open() {
+        //https://stackoverflow.com/questions/61607823/how-to-create-interactive-ssh-terminal-and-enter-commands-from-the-browser-using/61632083#61632083
+        super.open()
+        Xterm().open(DomUtil.getById(uuid.toString())!!)
+        Xterm().write("Hello from \\x1B[1;3;31mxterm.js\\x1B[0m $ ")
+    }
+
+    fun execute() {
+        pin()
     }
 
-    override fun execute(action: String?) {
-        UiManager.getRoStatusBar().acknowledge()
+    private fun pin() {
+        UiManager.add(host, dialog.formPanel as SimplePanel)
+        dialog.close()
     }
 
 }
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/SvgInline.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/SvgInline.kt
index 03f142c..1d1f728 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/SvgInline.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/SvgInline.kt
@@ -27,7 +27,7 @@ import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 import org.apache.isis.client.kroviz.utils.UUID
 
-class SvgInline : Command() {
+class SvgInline : Controller() {
     private val formItems = mutableListOf<FormItem>()
 
     init {
@@ -42,7 +42,7 @@ class SvgInline : Command() {
                 heightPerc = 50,
                 caption = "Sample SVG Inline (Non-Interactive)",
                 items = formItems,
-                command = this)
+                controller = this)
         val url = "https://upload.wikimedia.org/wikipedia/commons/6/6c/Trajans-Column-lower-animated.svg"
         val link = Link(href = url, method = Method.GET.operation)
         val agr = SvgDispatcher(callBack)
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/UndefinedDialog.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/UndefinedDialog.kt
index 7621fef..605524a 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/UndefinedDialog.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/UndefinedDialog.kt
@@ -23,7 +23,7 @@ import org.apache.isis.client.kroviz.to.ValueType
 import org.apache.isis.client.kroviz.ui.core.FormItem
 import org.apache.isis.client.kroviz.ui.core.RoDialog
 
-class UndefinedDialog(val logEntry: LogEntry) : Command() {
+class UndefinedDialog(val logEntry: LogEntry) : Controller() {
 
     private val instruction = """1. Create a ResponseClass under test/kotlin/org.ro.urls with
     - url 
@@ -42,7 +42,7 @@ class UndefinedDialog(val logEntry: LogEntry) : Command() {
         RoDialog(
                 caption = label,
                 items = formItems,
-                command = this,
+                controller = this,
                 widthPerc = 80).open()
     }
 
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/utils/IconManager.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/utils/IconManager.kt
index b02958c..95b281c 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/utils/IconManager.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/utils/IconManager.kt
@@ -102,6 +102,7 @@ object IconManager {
         "Switch" to "power-off",
         "Target" to "bullseye",
         "Tab" to "folder",
+        "Terminal" to "terminal",
         "Text" to "font",
         "Times" to "clock",
         "Toast" to "bread-slice", //comment-alt-plus/minus/exclamation
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/BrowserWindow.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/utils/js/Xterm.kt
similarity index 59%
copy from incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/BrowserWindow.kt
copy to incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/utils/js/Xterm.kt
index 8910240..6b3d437 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/dialog/BrowserWindow.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/utils/js/Xterm.kt
@@ -16,22 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.client.kroviz.ui.dialog
+package org.apache.isis.client.kroviz.utils.js
 
-import org.apache.isis.client.kroviz.to.ValueType
-import org.apache.isis.client.kroviz.ui.core.FormItem
-import org.apache.isis.client.kroviz.ui.core.RoDialog
-
-class BrowserWindow(val url: String) : Command() {
-
-    override fun open() {
-        val formItems = mutableListOf<FormItem>()
-        formItems.add(FormItem("URL", ValueType.IFRAME, url))
-        RoDialog(
-                caption = url,
-                items = formItems,
-                command = this,
-                defaultAction = "Visualize").open()
-    }
+import org.w3c.dom.Element
 
+@JsModule("xterm")
+@JsNonModule
+//         //https://stackoverflow.com/questions/61607823/how-to-create-interactive-ssh-terminal-and-enter-commands-from-the-browser-using/61632083#61632083
+external class Xterm {
+    fun open(element: Element)
+    fun write(output: String)
 }
diff --git a/incubator/clients/kroviz/src/main/resources/css/kroviz.css b/incubator/clients/kroviz/src/main/resources/css/kroviz.css
index ee20ceb..8e42416 100644
--- a/incubator/clients/kroviz/src/main/resources/css/kroviz.css
+++ b/incubator/clients/kroviz/src/main/resources/css/kroviz.css
@@ -225,3 +225,28 @@ html {
 .nav .nav-tabs {
     width: 100% !important;
 }
+
+.responsive-iframe {
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    width: 100%;
+    height: 100%;
+}
+
+.container {
+    position: relative;
+    overflow: hidden;
+    width: 100%;
+    padding-top: 56.25%; /* 16:9 Aspect Ratio (divide 9 by 16 = 0.5625) */
+    /* 75% ->  4:3 Aspect Ratio */
+    /* 66.66% ->  3:2 Aspect Ratio */
+}
+
+.form-panel {
+    width: auto;
+    height: auto;
+    overflow: auto;
+}
\ No newline at end of file
diff --git a/incubator/clients/kroviz/src/main/resources/img/gift_48.png b/incubator/clients/kroviz/src/main/resources/img/gift_48.png
new file mode 100644
index 0000000..86154c4
Binary files /dev/null and b/incubator/clients/kroviz/src/main/resources/img/gift_48.png differ
diff --git a/incubator/clients/kroviz/src/main/resources/img/incode_org.gif b/incubator/clients/kroviz/src/main/resources/img/incode_org.gif
new file mode 100644
index 0000000..20ee1d3
Binary files /dev/null and b/incubator/clients/kroviz/src/main/resources/img/incode_org.gif differ