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 2022/03/24 11:10:06 UTC

[isis] branch ISIS-2957 updated (16be0bc -> a019c2f)

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

joergrade pushed a change to branch ISIS-2957
in repository https://gitbox.apache.org/repos/asf/isis.git.


    from 16be0bc  ISIS-2957 add legend to EventBubbleChart
     new b393710  ISIS-2957 upgrade to gradle 7.4, js functions in companion object
     new 8ddcee4  ISIS-2957 functions nested
     new a019c2f  ISIS-2957 determineLegendLabel as extension function

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../client/kroviz/ui/panel/EventBubbleChart.kt     | 255 ++++++++++++---------
 2 files changed, 143 insertions(+), 114 deletions(-)

[isis] 01/03: ISIS-2957 upgrade to gradle 7.4, js functions in companion object

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit b393710c1a2e257ace582eb4aaf096752c549a4f
Author: Jörg Rade <jo...@kuehne-nagel.com>
AuthorDate: Wed Mar 23 09:14:30 2022 +0100

    ISIS-2957 upgrade to gradle 7.4, js functions in companion object
---
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../client/kroviz/ui/panel/EventBubbleChart.kt     | 109 ++++++++++++---------
 2 files changed, 64 insertions(+), 47 deletions(-)

diff --git a/incubator/clients/kroviz/gradle/wrapper/gradle-wrapper.properties b/incubator/clients/kroviz/gradle/wrapper/gradle-wrapper.properties
index 69a9715..41dfb87 100644
--- a/incubator/clients/kroviz/gradle/wrapper/gradle-wrapper.properties
+++ b/incubator/clients/kroviz/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt
index a400cbe..441df86 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt
@@ -26,8 +26,8 @@ import io.kvision.core.UNIT
 import io.kvision.panel.SimplePanel
 import io.kvision.utils.obj
 import org.apache.isis.client.kroviz.core.event.LogEntry
-import org.apache.isis.client.kroviz.ui.dialog.EventLogDetail
 import org.apache.isis.client.kroviz.ui.core.SessionManager
+import org.apache.isis.client.kroviz.ui.dialog.EventLogDetail
 import kotlin.math.pow
 
 @OptIn(kotlin.js.ExperimentalJsExport::class)
@@ -63,26 +63,34 @@ class EventBubbleChart() : SimplePanel() {
         )
     }
 
+    private fun buildLabelsNew(): List<String> {
+        val legendLabels = mutableListOf<String>()
+        legendLabels.add("0 .. 4")
+        legendLabels.add("5 .. 8")
+        legendLabels.add("9 .. 16")
+        legendLabels.add("17 .. 32")
+        legendLabels.add("33 .. 64")
+        legendLabels.add("65 .. 128")
+        legendLabels.add(">= 129")
+        return legendLabels
+    }
+
     // https://stackoverflow.com/questions/45249779/chart-js-bubble-chart-changing-dataset-labels
     private fun buildChartOptions(dataSetsList: List<DataSets>): ChartOptions {
-        val chartOptions = ChartOptions(
+        return ChartOptions(
             plugins = PluginsOptions(
                 title = TitleOptions(
                     text = listOf<String>("Request Duration over Time by Request Density and Response Size"),
                     display = true
                 ),
-                tooltip = TooltipOptions(callbacks = toolTipCallback()),
+                tooltip = TooltipOptions(
+                    callbacks = TooltipCallback(
+                        footer = tooltipCallbackFooterJsFunction()
+                    )
+                ),
                 legend = buildLegend()
             ),
-            onClick = js(
-                "function(e) {"
-                        + "var element = e.chart.getElementsAtEventForMode(e, 'nearest', {intersect: true}, true);"
-                        + "if (element.length > 0) {"
-                        + "var i = element[0].index;"
-                        + "kroviz.org.apache.isis.client.kroviz.ui.panel.openLogEntry(i);"
-                        + "}"
-                        + "}"
-            ),
+            onClick = onClickJsFunction(),
             showLine = true,
             scales = mapOf(
                 "x" to ChartScales(
@@ -96,25 +104,6 @@ class EventBubbleChart() : SimplePanel() {
                 )
             )
         )
-        return chartOptions
-    }
-
-    // https://www.youtube.com/watch?v=UxJ5d-HGhJA
-    // https://en.wikipedia.org/wiki/Clarke%27s_three_laws -> #2
-    // I would have appreciated a real API.
-    private fun toolTipCallback(): TooltipCallback {
-        return TooltipCallback(
-            footer = js(
-                "function(context) {"
-                        + "var ctx = context[0];"
-                        + "var chart = ctx.chart;"
-                        + "var ccc = chart.config._config;"
-                        + "var data = ccc.data;"
-                        + "var i = ctx.dataIndex;"
-                        + "return data.labels[i];"
-                        + "}"
-            )
-        )
     }
 
     private fun LogEntry.toLabel(index: Int): String {
@@ -167,13 +156,13 @@ class EventBubbleChart() : SimplePanel() {
     private fun LogEntry.calculateBubbleColor(): Color {
         val i = runningAtStart
         return when {
-            (i >= 0) && (i <= 4) -> EventBubbleChart.LIGHT_BLUE
-            (i > 4) && (i <= 8) -> EventBubbleChart.DARK_BLUE
-            (i > 8) && (i <= 16) -> EventBubbleChart.GREEN
-            (i > 16) && (i <= 32) -> EventBubbleChart.YELLOW
-            (i > 32) && (i <= 64) -> EventBubbleChart.RED
-            (i > 64) && (i <= 128) -> EventBubbleChart.RED_VIOLET
-            else -> EventBubbleChart.VIOLET
+            (i >= 0) && (i <= 4) -> LIGHT_BLUE
+            (i > 4) && (i <= 8) -> DARK_BLUE
+            (i > 8) && (i <= 16) -> GREEN
+            (i > 16) && (i <= 32) -> YELLOW
+            (i > 32) && (i <= 64) -> RED
+            (i > 64) && (i <= 128) -> RED_VIOLET
+            else -> VIOLET
         }
     }
 
@@ -192,26 +181,29 @@ class EventBubbleChart() : SimplePanel() {
     }
 
     private fun buildLegend(): LegendOptions {
-        val legend = LegendOptions(
+        return LegendOptions(
             display = true,
             position = Position.RIGHT,
             labels = buildLegendLabelOptions(),
-            title = LegendTitleOptions(text = "title here")
+            title = LegendTitleOptions(text = "Parallel Requests", display = true),
         )
-        return legend
     }
 
     private fun buildLegendLabelOptions(): LegendLabelOptions {
         val legendLabelOptions = LegendLabelOptions(
-            color = EventBubbleChart.YELLOW //mutableListOf(DARK_BLUE, LIGHT_BLUE, GREEN, YELLOW, RED, RED_VIOLET, VIOLET)
+ /*           generateLabels = {
+                val legendItemList = mutableListOf<LegendItem>()
+                val li = obj {
+                    text = "0 ..4"
+                }
+                legendItemList.add(li as LegendItem)
+                legendItemList as Array<LegendItem>
+            },*/
+            color = YELLOW
         )
         return legendLabelOptions
     }
 
-    private fun generateLabels(): List<LegendItem> {
-        return mutableListOf<LegendItem>()
-    }
-
     companion object {
         val VIOLET = Color.rgba(0x80, 0x64, 0xA2, 0x80)
         val RED_VIOLET = Color.rgba(0xA0, 0x5A, 0x78, 0x80)
@@ -220,6 +212,31 @@ class EventBubbleChart() : SimplePanel() {
         val GREEN = Color.rgba(0x9B, 0xBB, 0x59, 0x80)
         val LIGHT_BLUE = Color.rgba(0x4B, 0xAC, 0xC6, 0x80)
         val DARK_BLUE = Color.rgba(0x4F, 0x81, 0xBD, 0x80)
+
+        fun onClickJsFunction(): dynamic {
+            return js(
+                """function(e) {
+                        var element = e.chart.getElementsAtEventForMode(e, 'nearest', {intersect: true}, true);
+                        if (element.length > 0) {
+                            var i = element[0].index;
+                            kroviz.org.apache.isis.client.kroviz.ui.panel.openLogEntry(i);
+                            }
+                        }"""
+            )
+        }
+
+        fun tooltipCallbackFooterJsFunction(): dynamic {
+            return js(
+                """function(context) {
+                            var ctx = context[0];
+                            var chart = ctx.chart;
+                            var ccc = chart.config._config;
+                            var data = ccc.data;
+                            var i = ctx.dataIndex;
+                            return data.labels[i];
+                }"""
+            )
+        }
     }
 
 }

[isis] 02/03: ISIS-2957 functions nested

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8ddcee4b97824effa0590fefea0d516129ab91ae
Author: Jörg Rade <jo...@kuehne-nagel.com>
AuthorDate: Wed Mar 23 12:17:51 2022 +0100

    ISIS-2957 functions nested
---
 .../client/kroviz/ui/panel/EventBubbleChart.kt     | 164 +++++++++++----------
 1 file changed, 90 insertions(+), 74 deletions(-)

diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt
index 441df86..d5e9a9c 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt
@@ -19,7 +19,7 @@
 package org.apache.isis.client.kroviz.ui.panel
 
 import io.kvision.chart.*
-import io.kvision.chart.js.LegendItem
+import io.kvision.core.Col
 import io.kvision.core.Color
 import io.kvision.core.CssSize
 import io.kvision.core.UNIT
@@ -37,7 +37,7 @@ fun openLogEntry(i: Int) {
     EventLogDetail(logEntry).open()
 }
 
-class EventBubbleChart() : SimplePanel() {
+class EventBubbleChart : SimplePanel() {
     private val model = SessionManager.getEventStore()
     private val logStart = model.getLogStartMilliSeconds()
     private var chart: Chart
@@ -54,11 +54,20 @@ class EventBubbleChart() : SimplePanel() {
     }
 
     private fun buildConfiguration(): Configuration {
+        fun buildToolTipList(): List<String> {
+            val labelList = mutableListOf<String>()
+            model.log.forEachIndexed { i, it ->
+                val l = it.buildToolTip(i)
+                labelList.add(l)
+            }
+            return labelList
+        }
+
         val dataSetsList = listOf(buildDataSets())
         return Configuration(
             type = ChartType.BUBBLE,
             dataSets = dataSetsList,
-            labels = buildLabels(),
+            labels = buildToolTipList(),
             options = buildChartOptions(dataSetsList)
         )
     }
@@ -77,10 +86,34 @@ class EventBubbleChart() : SimplePanel() {
 
     // https://stackoverflow.com/questions/45249779/chart-js-bubble-chart-changing-dataset-labels
     private fun buildChartOptions(dataSetsList: List<DataSets>): ChartOptions {
+        fun buildLegend(): LegendOptions {
+            fun buildLegendLabelOptions(): LegendLabelOptions {
+                val legendLabelOptions = LegendLabelOptions(
+                    /*           generateLabels = {
+                                   val legendItemList = mutableListOf<LegendItem>()
+                                   val li = obj {
+                                       text = "0 ..4"
+                                   }
+                                   legendItemList.add(li as LegendItem)
+                                   legendItemList as Array<LegendItem>
+                               },*/
+                    color = YELLOW
+                )
+                return legendLabelOptions
+            }
+
+            return LegendOptions(
+                display = true,
+                position = Position.RIGHT,
+                labels = buildLegendLabelOptions(),
+                title = LegendTitleOptions(text = "Parallel Requests", display = true),
+            )
+        }
+
         return ChartOptions(
             plugins = PluginsOptions(
                 title = TitleOptions(
-                    text = listOf<String>("Request Duration over Time by Request Density and Response Size"),
+                    text = listOf<String>("Request Duration over Time by Request Parallelism and Response Size"),
                     display = true
                 ),
                 tooltip = TooltipOptions(
@@ -106,51 +139,61 @@ class EventBubbleChart() : SimplePanel() {
         )
     }
 
-    private fun LogEntry.toLabel(index: Int): String {
-        return this.title +
-                "\nseq.no.: $index" +
-                "\nparallel runs: ${this.runningAtStart}" +
-                "\nrsp.len.: ${this.responseLength}" +
-                "\ntype: ${this.type}"
-    }
-
     private fun buildDataSets(): DataSets {
+        fun buildBgColorList(): List<Color> {
+            val bgColorList = mutableListOf<Color>()
+            model.log.forEach {
+                val c = it.calculateBubbleColor()
+                bgColorList.add(c)
+            }
+            return bgColorList
+        }
+
+        fun buildBorderColorList(): List<Color> {
+            val borderColorList = mutableListOf<Color>()
+            model.log.forEach {
+                when {
+                    it.isError() -> borderColorList.add(Color.name(Col.RED))
+                    it.response.contains("httpStatusCode") -> borderColorList.add(Color.name(Col.RED))
+                    else -> borderColorList.add(Color.name(Col.LIGHTGRAY))
+                }
+            }
+            return borderColorList
+        }
+
+        /**
+         * The term DataSets is severely miss leading:
+         * 1. a plural form is used (where actually a singular would be more appropriate) -> "a DataSets"
+         * 2. datasets are used inside datasets, data inside data
+         */
+        fun buildData(): List<DataSets> {
+            val dataSets = mutableListOf<DataSets>()
+            model.log.forEach {
+                dataSets.add(it.buildData())
+            }
+            return dataSets
+        }
+
         return DataSets(
+//            label = buildLabelList(),
             backgroundColor = buildBgColorList(),
+            borderColor = buildBorderColorList(),
             data = buildData()
         )
-    }
 
-    /**
-     * The term DataSets is severely miss leading:
-     * 1. a plural form is used (where actually a singular would be more appropriate) -> "a DataSets"
-     */
-    private fun buildData(): List<DataSets> {
-        val dataSets = mutableListOf<DataSets>()
-        model.log.forEach {
-            dataSets.add(it.asData())
-        }
-        return dataSets
     }
 
-    private fun LogEntry.asData(): dynamic {
-        val relativeStartTimeMs = createdAt.getTime() - logStart
-        val bubbleSize = calculateBubbleSize()
-        val data = obj {
-            x = relativeStartTimeMs
-            y = duration
-            r = bubbleSize
-        }
-        return data
+    private fun LogEntry.buildToolTip(index: Int): String {
+        return this.title +
+                "\nseq.no.: $index" +
+                "\nparallel runs: ${this.runningAtStart}" +
+                "\nrsp.len.: ${this.responseLength}" +
+                "\ntype: ${this.type}"
     }
 
-    private fun buildBgColorList(): List<Color> {
-        val bgColorList = mutableListOf<Color>()
-        model.log.forEach {
-            val c = it.calculateBubbleColor()
-            bgColorList.add(c)
-        }
-        return bgColorList
+    private fun LogEntry.calculateBubbleSize(): Int {
+        val i = responseLength
+        return i.toDouble().pow(1 / 3.toDouble()).toInt()
     }
 
     private fun LogEntry.calculateBubbleColor(): Color {
@@ -166,42 +209,15 @@ class EventBubbleChart() : SimplePanel() {
         }
     }
 
-    private fun LogEntry.calculateBubbleSize(): Int {
-        val i = responseLength
-        return i.toDouble().pow(1 / 3.toDouble()).toInt()
-    }
-
-    private fun buildLabels(): List<String> {
-        val labelList = mutableListOf<String>()
-        model.log.forEachIndexed { i, it ->
-            val l = it.toLabel(i)
-            labelList.add(l)
+    private fun LogEntry.buildData(): dynamic {
+        val relativeStartTimeMs = createdAt.getTime() - logStart
+        val bubbleSize = calculateBubbleSize()
+        val data = obj {
+            x = relativeStartTimeMs
+            y = duration
+            r = bubbleSize
         }
-        return labelList
-    }
-
-    private fun buildLegend(): LegendOptions {
-        return LegendOptions(
-            display = true,
-            position = Position.RIGHT,
-            labels = buildLegendLabelOptions(),
-            title = LegendTitleOptions(text = "Parallel Requests", display = true),
-        )
-    }
-
-    private fun buildLegendLabelOptions(): LegendLabelOptions {
-        val legendLabelOptions = LegendLabelOptions(
- /*           generateLabels = {
-                val legendItemList = mutableListOf<LegendItem>()
-                val li = obj {
-                    text = "0 ..4"
-                }
-                legendItemList.add(li as LegendItem)
-                legendItemList as Array<LegendItem>
-            },*/
-            color = YELLOW
-        )
-        return legendLabelOptions
+        return data
     }
 
     companion object {

[isis] 03/03: ISIS-2957 determineLegendLabel as extension function

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit a019c2f23a12de294615c8f273b8e4bc08e15e8d
Author: Jörg Rade <jo...@kuehne-nagel.com>
AuthorDate: Thu Mar 24 12:08:54 2022 +0100

    ISIS-2957 determineLegendLabel as extension function
---
 .../client/kroviz/ui/panel/EventBubbleChart.kt     | 72 ++++++++++------------
 1 file changed, 34 insertions(+), 38 deletions(-)

diff --git a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt
index d5e9a9c..77ff49c 100644
--- a/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt
+++ b/incubator/clients/kroviz/src/main/kotlin/org/apache/isis/client/kroviz/ui/panel/EventBubbleChart.kt
@@ -44,12 +44,8 @@ class EventBubbleChart : SimplePanel() {
 
     init {
         width = CssSize(90, UNIT.vw)
-        chart = buildChart()
-    }
-
-    private fun buildChart(): Chart {
-        return chart(
-            configuration = buildConfiguration(),
+        chart = chart(
+            configuration = buildConfiguration()
         )
     }
 
@@ -68,35 +64,15 @@ class EventBubbleChart : SimplePanel() {
             type = ChartType.BUBBLE,
             dataSets = dataSetsList,
             labels = buildToolTipList(),
-            options = buildChartOptions(dataSetsList)
+            options = buildChartOptions(),
         )
     }
 
-    private fun buildLabelsNew(): List<String> {
-        val legendLabels = mutableListOf<String>()
-        legendLabels.add("0 .. 4")
-        legendLabels.add("5 .. 8")
-        legendLabels.add("9 .. 16")
-        legendLabels.add("17 .. 32")
-        legendLabels.add("33 .. 64")
-        legendLabels.add("65 .. 128")
-        legendLabels.add(">= 129")
-        return legendLabels
-    }
-
     // https://stackoverflow.com/questions/45249779/chart-js-bubble-chart-changing-dataset-labels
-    private fun buildChartOptions(dataSetsList: List<DataSets>): ChartOptions {
+    private fun buildChartOptions(): ChartOptions {
         fun buildLegend(): LegendOptions {
             fun buildLegendLabelOptions(): LegendLabelOptions {
                 val legendLabelOptions = LegendLabelOptions(
-                    /*           generateLabels = {
-                                   val legendItemList = mutableListOf<LegendItem>()
-                                   val li = obj {
-                                       text = "0 ..4"
-                                   }
-                                   legendItemList.add(li as LegendItem)
-                                   legendItemList as Array<LegendItem>
-                               },*/
                     color = YELLOW
                 )
                 return legendLabelOptions
@@ -113,7 +89,7 @@ class EventBubbleChart : SimplePanel() {
         return ChartOptions(
             plugins = PluginsOptions(
                 title = TitleOptions(
-                    text = listOf<String>("Request Duration over Time by Request Parallelism and Response Size"),
+                    text = listOf("Request Duration over Time by Request Parallelism and Response Size"),
                     display = true
                 ),
                 tooltip = TooltipOptions(
@@ -143,7 +119,7 @@ class EventBubbleChart : SimplePanel() {
         fun buildBgColorList(): List<Color> {
             val bgColorList = mutableListOf<Color>()
             model.log.forEach {
-                val c = it.calculateBubbleColor()
+                val c = it.determineBubbleColor()
                 bgColorList.add(c)
             }
             return bgColorList
@@ -166,21 +142,28 @@ class EventBubbleChart : SimplePanel() {
          * 1. a plural form is used (where actually a singular would be more appropriate) -> "a DataSets"
          * 2. datasets are used inside datasets, data inside data
          */
-        fun buildData(): List<DataSets> {
-            val dataSets = mutableListOf<DataSets>()
+        fun buildDataSetsList(): List<DataSets> {
+            console.log("[EBC.buildData]")
+            val dataSetsList = mutableListOf<DataSets>()
             model.log.forEach {
-                dataSets.add(it.buildData())
+                val d = it.buildData()
+/*                val l = it.determineLegendLabel()
+                val element = obj {
+                    label = l
+                    data = d
+                }*/
+                dataSetsList.add(d)
             }
-            return dataSets
+            console.log(dataSetsList)
+            return dataSetsList
         }
 
         return DataSets(
-//            label = buildLabelList(),
             backgroundColor = buildBgColorList(),
             borderColor = buildBorderColorList(),
-            data = buildData()
+            data = buildDataSetsList(),
+            label = "test"
         )
-
     }
 
     private fun LogEntry.buildToolTip(index: Int): String {
@@ -196,7 +179,7 @@ class EventBubbleChart : SimplePanel() {
         return i.toDouble().pow(1 / 3.toDouble()).toInt()
     }
 
-    private fun LogEntry.calculateBubbleColor(): Color {
+    private fun LogEntry.determineBubbleColor(): Color {
         val i = runningAtStart
         return when {
             (i >= 0) && (i <= 4) -> LIGHT_BLUE
@@ -209,6 +192,19 @@ class EventBubbleChart : SimplePanel() {
         }
     }
 
+    private fun LogEntry.determineLegendLabel(): String {
+        val i = runningAtStart
+        return when {
+            (i >= 0) && (i <= 4) -> "0 .. 4"
+            (i > 4) && (i <= 8) -> "5 .. 8"
+            (i > 8) && (i <= 16) -> "9 .. 16"
+            (i > 16) && (i <= 32) -> "17 .. 32"
+            (i > 32) && (i <= 64) -> "33 .. 64"
+            (i > 64) && (i <= 128) -> "65 .. 128"
+            else -> ">= 129"
+        }
+    }
+
     private fun LogEntry.buildData(): dynamic {
         val relativeStartTimeMs = createdAt.getTime() - logStart
         val bubbleSize = calculateBubbleSize()