From 4f00bad90858a4c4304cd313889112e23ce2cd27 Mon Sep 17 00:00:00 2001 From: Katarzyna Streich Date: Fri, 19 May 2017 11:31:31 +0100 Subject: [PATCH] Address PR comments. Add links from FlowTriage view to Network and to TransactionView with showing relevant transactions/peers on the map. --- .../client/jfx/model/StateMachineDataModel.kt | 1 - .../formatters/FlowInitiatorFormatter.kt | 20 ++- .../explorer/formatters/FlowNameFormatter.kt | 10 +- .../explorer/identicon/IdenticonRenderer.kt | 1 + .../net/corda/explorer/views/Network.kt | 17 ++- .../explorer/views/StateMachineViewer.kt | 141 +++++++----------- .../corda/explorer/views/TransactionViewer.kt | 22 ++- .../net/corda/explorer/views/Network.fxml | 6 +- .../views/StateMachineDetailsView.fxml | 46 ++---- 9 files changed, 131 insertions(+), 133 deletions(-) diff --git a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/StateMachineDataModel.kt b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/StateMachineDataModel.kt index 24c9dd4c25..ff4ec5a0cf 100644 --- a/client/jfx/src/main/kotlin/net/corda/client/jfx/model/StateMachineDataModel.kt +++ b/client/jfx/src/main/kotlin/net/corda/client/jfx/model/StateMachineDataModel.kt @@ -7,7 +7,6 @@ import javafx.collections.FXCollections import net.corda.client.jfx.utils.LeftOuterJoinedMap import net.corda.client.jfx.utils.fold import net.corda.client.jfx.utils.getObservableValues -import net.corda.client.jfx.utils.lift import net.corda.client.jfx.utils.recordAsAssociation import net.corda.core.ErrorOr import net.corda.core.flows.FlowInitiator diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/FlowInitiatorFormatter.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/FlowInitiatorFormatter.kt index d678ca1ec8..b42c7ae72a 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/FlowInitiatorFormatter.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/FlowInitiatorFormatter.kt @@ -1,14 +1,26 @@ package net.corda.explorer.formatters +import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon import net.corda.core.flows.FlowInitiator object FlowInitiatorFormatter : Formatter { override fun format(value: FlowInitiator): String { return when (value) { - is FlowInitiator.Scheduled -> "Started by scheduled state:: " + value.scheduledState.ref.toString() // TODO How do we want to format that? - is FlowInitiator.Shell -> "Started via shell" - is FlowInitiator.Peer -> "Peer legal name: " + PartyNameFormatter.short.format(value.party.name) - is FlowInitiator.RPC -> "Rpc username: " + value.username + is FlowInitiator.Scheduled -> value.scheduledState.ref.toString() // TODO How do we want to format that? + is FlowInitiator.Shell -> "Shell" // TODO We don't have much information about that user. + is FlowInitiator.Peer -> PartyNameFormatter.short.format(value.party.name) + is FlowInitiator.RPC -> value.username + } + } + + fun withIcon(value: FlowInitiator): Pair { + val text = format(value) + return when (value) { + is FlowInitiator.Scheduled -> Pair(FontAwesomeIcon.CALENDAR, text) + is FlowInitiator.Shell -> Pair(FontAwesomeIcon.TERMINAL, text) + is FlowInitiator.Peer -> Pair(FontAwesomeIcon.GROUP, text) + is FlowInitiator.RPC -> Pair(FontAwesomeIcon.SHARE, text) + } } } diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/FlowNameFormatter.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/FlowNameFormatter.kt index cb45988186..0de07af66b 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/FlowNameFormatter.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/formatters/FlowNameFormatter.kt @@ -1,7 +1,13 @@ package net.corda.explorer.formatters +import org.apache.commons.lang.StringUtils.splitByCharacterTypeCamelCase + object FlowNameFormatter { - val boring = object : Formatter { - override fun format(value: String) = value.split('.').last().replace("$", ": ") // TODO Better handling of names. + val camelCase = object : Formatter { + override fun format(value: String): String { + val flowName = value.split('.', '$').last() + val split = splitByCharacterTypeCamelCase(flowName).filter { it.compareTo("Flow", true) != 0 } .joinToString(" ") + return split + } } } \ No newline at end of file diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt index 11d20caa96..74f6998f93 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/identicon/IdenticonRenderer.kt @@ -195,6 +195,7 @@ fun identicon(secureHash: SecureHash, size: Double): ImageView { return ImageView(IdenticonRenderer.getIdenticon(secureHash)).apply { isPreserveRatio = true fitWidth = size + styleClass += "identicon" } } diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt index a72f452a59..2235d3d267 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/Network.kt @@ -6,6 +6,7 @@ import javafx.animation.FadeTransition import javafx.animation.TranslateTransition import javafx.beans.binding.Bindings import javafx.beans.property.SimpleObjectProperty +import javafx.beans.value.ObservableValue import javafx.collections.FXCollections import javafx.geometry.Bounds import javafx.geometry.Point2D @@ -41,6 +42,9 @@ class Network : CordaView() { val notaries by observableList(NetworkIdentityModel::notaries) val peers by observableList(NetworkIdentityModel::parties) val transactions by observableList(TransactionDataModel::partiallyResolvedTransactions) + var centralPeer: String? = null + private var centralLabel: ObservableValue + // UI components private val myIdentityPane by fxid() private val notaryList by fxid() @@ -114,7 +118,17 @@ class Network : CordaView() { return MapViewComponents(this, button, mapLabel) } + override fun onDock() { + centralLabel = mapLabels.firstOrDefault(myMapLabel, { centralPeer?.contains(it.text, true) ?: false }) + } + + override fun onUndock() { + centralPeer = null + centralLabel = myMapLabel + } + init { + centralLabel = mapLabels.firstOrDefault(myMapLabel, { centralPeer?.contains(it.text, true) ?: false }) myIdentityPane.centerProperty().bind(myButton) Bindings.bindContent(notaryList.children, notaryButtons) Bindings.bindContent(peerList.children, peerButtons) @@ -122,7 +136,7 @@ class Network : CordaView() { // Run once when the screen is ready. // TODO : Find a better way to do this. mapPane.heightProperty().addListener { _, old, _ -> - if (old == 0.0) myMapLabel.value?.let { mapScrollPane.centerLabel(it) } + if (old == 0.0) centralLabel.value?.let { mapScrollPane.centerLabel(it) } } // Listen on zooming gesture, if device has gesture support. mapPane.setOnZoom { zoom(it.zoomFactor, Point2D(it.x, it.y)) } @@ -142,6 +156,7 @@ class Network : CordaView() { } } + // TODO It doesn't work as expected. private fun ScrollPane.centerLabel(label: Label) { this.hvalue = (label.boundsInParent.width / 2 + label.boundsInParent.minX) / mapImageView.layoutBounds.width this.vvalue = (label.boundsInParent.height / 2 + label.boundsInParent.minY) / mapImageView.layoutBounds.height diff --git a/tools/explorer/src/main/kotlin/net/corda/explorer/views/StateMachineViewer.kt b/tools/explorer/src/main/kotlin/net/corda/explorer/views/StateMachineViewer.kt index d583f54bf6..e7c6eaab0e 100644 --- a/tools/explorer/src/main/kotlin/net/corda/explorer/views/StateMachineViewer.kt +++ b/tools/explorer/src/main/kotlin/net/corda/explorer/views/StateMachineViewer.kt @@ -103,43 +103,29 @@ class StateMachineViewer : CordaView("Flow Triage") { minWidth = 100.0 maxWidth = 200.0 }.setCustomCellFactory { - label("$it") { + val toDisplay = it.toString().removeSurrounding("[", "]") + label(toDisplay) { val hash = SecureHash.sha256(it.toString()) graphic = identicon(hash, 15.0) - tooltip = identiconToolTip(hash, it.toString()) + tooltip = identiconToolTip(hash, toDisplay) } } - column("Flow name", StateMachineData::stateMachineName).cellFormat { text = FlowNameFormatter.boring.format(it) } - column("Initiator", StateMachineData::flowInitiator).cellFormat { text = FlowInitiatorFormatter.format(it) } - column("Flow Status", StateMachineData::stateMachineStatus).cellFormat { text = it.status ?: "No progress data" } - column("Result", StateMachineData::addRmStatus).setCustomCellFactory { - if (it is StateMachineStatus.Removed) { - if (it.result.error == null) { - label("Success") { - graphic = FontAwesomeIconView(FontAwesomeIcon.CHECK).apply { - glyphSize = 15.0 - textAlignment = TextAlignment.CENTER - style = "-fx-fill: green" - } - } + column("Flow name", StateMachineData::stateMachineName).cellFormat { text = FlowNameFormatter.camelCase.format(it) } + column("Initiator", StateMachineData::flowInitiator).setCustomCellFactory { + val (initIcon, initText) = FlowInitiatorFormatter.withIcon(it) + label { makeIconLabel(this, initIcon, initText, "-fx-fill: lightgray") } + } + column("Flow Status", StateMachineData::smmStatus).setCustomCellFactory { + val addRm = it.first.value + val progress = it.second.value.status ?: "No progress data" + if (addRm is StateMachineStatus.Removed) { + if (addRm.result.error == null) { + label { makeIconLabel(this, FontAwesomeIcon.CHECK, "Success", "-fx-fill: green") } } else { - label("Error") { - graphic = FontAwesomeIconView(FontAwesomeIcon.BOLT).apply { - glyphSize = 15.0 - textAlignment = TextAlignment.CENTER - style = "-fx-fill: -color-4" - } - } + label { makeIconLabel(this, FontAwesomeIcon.BOLT, progress, "-fx-fill: -color-4") } } } else { - label("In progress") { - graphic = FontAwesomeIconView(FontAwesomeIcon.ROCKET).apply { - // Blazing fast! Try not to blink. - glyphSize = 15.0 - textAlignment = TextAlignment.CENTER - style = "-fx-fill: lightslategrey" - } - } + label { makeIconLabel(this, FontAwesomeIcon.ROCKET, progress, "-fx-fill: lightslategrey") } } } } @@ -150,22 +136,22 @@ class StateMachineViewer : CordaView("Flow Triage") { "Flow name" to { sm, s -> sm.stateMachineName.contains(s, true) }, "Initiator" to { sm, s -> FlowInitiatorFormatter.format(sm.flowInitiator).contains(s, true) }, "Flow Status" to { sm, s -> - val stat = sm.stateMachineStatus.value.status ?: "No progress data" + val stat = sm.smmStatus.second.value?.status ?: "No progress data" stat.contains(s, true) }, "Error" to { sm, _ -> - val smAddRm = sm.addRmStatus.value + val smAddRm = sm.smmStatus.first.value if (smAddRm is StateMachineStatus.Removed) smAddRm.result.error != null else false }, "Done" to { sm, _ -> - val smAddRm = sm.addRmStatus.value + val smAddRm = sm.smmStatus.first.value if (smAddRm is StateMachineStatus.Removed) smAddRm.result.error == null else false }, - "In progress" to { sm, _ -> sm.addRmStatus.value !is StateMachineStatus.Removed }, + "In progress" to { sm, _ -> sm.smmStatus.first.value !is StateMachineStatus.Removed }, disabledFields = listOf("Error", "Done", "In progress") ) root.top = searchField.root @@ -175,31 +161,20 @@ class StateMachineViewer : CordaView("Flow Triage") { }) } - private inner class StateMachineDetailsView(val smmData: StateMachineData) : Fragment() { + private inner class StateMachineDetailsView(smmData: StateMachineData) : Fragment() { override val root by fxml() - private val flowNameLabel by fxid