explorer: Add Low level events viewer for tx screen

asd
This commit is contained in:
Andras Slemmer 2016-09-01 16:34:42 +01:00
parent f4de05c982
commit 767077c764
8 changed files with 98 additions and 32 deletions

View File

@ -21,7 +21,7 @@ import javafx.collections.ObservableListBase
* The above will create a list that chooses and delegates to the appropriate filtered list based on the type of filter.
*/
class ChosenList<E>(
private val chosenListObservable: ObservableValue<ObservableList<E>>
private val chosenListObservable: ObservableValue<ObservableList<out E>>
): ObservableListBase<E>() {
private var currentList = chosenListObservable.value
@ -48,7 +48,7 @@ class ChosenList<E>(
}
}
private fun pick(list: ObservableList<E>) {
private fun pick(list: ObservableList<out E>) {
currentList.removeListener(listener)
list.addListener(listener)
beginChange()

View File

@ -7,6 +7,7 @@ import com.r3corda.node.services.monitor.TransactionBuildResult
import com.r3corda.node.utilities.AddOrRemove
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.value.ObservableValue
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import rx.Observable
import java.time.Instant
@ -20,6 +21,7 @@ interface GatheredTransactionData {
val transaction: ObservableValue<SignedTransaction?>
val status: ObservableValue<TransactionCreateStatus?>
val lastUpdate: ObservableValue<Instant>
val allEvents: ObservableList<out ServiceToClientEvent>
}
sealed class TransactionCreateStatus(val message: String?) {
@ -42,7 +44,8 @@ data class GatheredTransactionDataWritable(
override val protocolStatus: SimpleObjectProperty<ProtocolStatus?> = SimpleObjectProperty(null),
override val transaction: SimpleObjectProperty<SignedTransaction?> = SimpleObjectProperty(null),
override val status: SimpleObjectProperty<TransactionCreateStatus?> = SimpleObjectProperty(null),
override val lastUpdate: SimpleObjectProperty<Instant>
override val lastUpdate: SimpleObjectProperty<Instant>,
override val allEvents: ObservableList<ServiceToClientEvent> = FXCollections.observableArrayList()
) : GatheredTransactionData
/**
@ -74,7 +77,7 @@ class GatheredTransactionDataModel {
}
is ServiceToClientEvent.OutputState -> {}
is ServiceToClientEvent.StateMachine -> {
newFiberIdTransactionStateOrModify(transactionStates,
newFiberIdTransactionStateOrModify(transactionStates, serviceToClientEvent,
fiberId = serviceToClientEvent.fiberId,
lastUpdate = serviceToClientEvent.time,
tweak = {
@ -87,7 +90,7 @@ class GatheredTransactionDataModel {
)
}
is ServiceToClientEvent.Progress -> {
newFiberIdTransactionStateOrModify(transactionStates,
newFiberIdTransactionStateOrModify(transactionStates, serviceToClientEvent,
fiberId = serviceToClientEvent.fiberId,
lastUpdate = serviceToClientEvent.time,
tweak = {
@ -97,7 +100,7 @@ class GatheredTransactionDataModel {
}
is ServiceToClientEvent.TransactionBuild -> {
val state = serviceToClientEvent.state
newUuidTransactionStateOrModify(transactionStates,
newUuidTransactionStateOrModify(transactionStates, serviceToClientEvent,
uuid = serviceToClientEvent.id,
fiberId = when (state) {
is TransactionBuildResult.ProtocolStarted -> state.fiberId
@ -124,27 +127,32 @@ class GatheredTransactionDataModel {
companion object {
private fun newFiberIdTransactionStateOrModify(
transactionStates: ObservableList<GatheredTransactionDataWritable>,
event: ServiceToClientEvent,
fiberId: Long,
lastUpdate: Instant,
tweak: GatheredTransactionDataWritable.() -> Unit
) {
val index = transactionStates.indexOfFirst { it.fiberId.value == fiberId }
if (index < 0) {
val state = if (index < 0) {
val newState = GatheredTransactionDataWritable(
fiberId = SimpleObjectProperty(fiberId),
lastUpdate = SimpleObjectProperty(lastUpdate)
)
tweak(newState)
transactionStates.add(newState)
newState
} else {
val existingState = transactionStates[index]
existingState.lastUpdate.set(lastUpdate)
tweak(existingState)
existingState
}
state.allEvents.add(event)
}
private fun newUuidTransactionStateOrModify(
transactionStates: ObservableList<GatheredTransactionDataWritable>,
event: ServiceToClientEvent,
uuid: UUID,
fiberId: Long?,
lastUpdate: Instant,
@ -153,7 +161,7 @@ class GatheredTransactionDataModel {
val index = transactionStates.indexOfFirst {
it.uuid.value == uuid || (fiberId != null && it.fiberId.value == fiberId)
}
if (index < 0) {
val state = if (index < 0) {
val newState = GatheredTransactionDataWritable(
uuid = SimpleObjectProperty(uuid),
fiberId = SimpleObjectProperty(fiberId),
@ -161,11 +169,14 @@ class GatheredTransactionDataModel {
)
tweak(newState)
transactionStates.add(newState)
newState
} else {
val existingState = transactionStates[index]
existingState.lastUpdate.set(lastUpdate)
tweak(existingState)
existingState
}
state.allEvents.add(event)
}
}

View File

@ -0,0 +1,6 @@
package com.r3corda.explorer.ui
sealed class SingleRowSelection<A> {
class None<A> : SingleRowSelection<A>()
class Selected<A>(val node: A) : SingleRowSelection<A>()
}

View File

@ -47,3 +47,10 @@ fun <S, T> Formatter<T>.toTableCellFactory() = Callback<TableColumn<S, T?>, Tabl
}
}
fun <S> TableView<S>.singleRowSelection() = Bindings.createObjectBinding({
if (selectionModel.selectedItems.size == 0) {
SingleRowSelection.None<S>()
} else {
SingleRowSelection.Selected(selectionModel.selectedItems[0])
}
}, arrayOf(selectionModel.selectedItems))

View File

@ -47,3 +47,11 @@ fun <S, T> Formatter<T>.toTreeTableCellFactory() = Callback<TreeTableColumn<S, T
}
}
}
fun <S> TreeTableView<S>.singleRowSelection() = Bindings.createObjectBinding({
if (selectionModel.selectedItems.size == 0) {
SingleRowSelection.None<S>()
} else {
SingleRowSelection.Selected(selectionModel.selectedItems[0].value)
}
}, arrayOf(selectionModel.selectedItems))

View File

@ -14,7 +14,9 @@ import com.r3corda.explorer.formatters.AmountFormatter
import com.r3corda.explorer.formatters.NumberFormatter
import com.r3corda.explorer.model.ReportingCurrencyModel
import com.r3corda.explorer.model.SettingsModel
import com.r3corda.explorer.ui.SingleRowSelection
import com.r3corda.explorer.ui.setColumnPrefWidthPolicy
import com.r3corda.explorer.ui.singleRowSelection
import com.r3corda.explorer.ui.toTreeTableCellFactory
import javafx.beans.binding.Bindings
import javafx.beans.property.ReadOnlyObjectWrapper
@ -172,18 +174,7 @@ class CashViewer : View() {
treeItem
}
sealed class ViewerNodeSelection {
object None : ViewerNodeSelection()
class Selected(val node: ViewerNode) : ViewerNodeSelection()
}
val selectedViewerNode = Bindings.createObjectBinding({
if (cashViewerTable.selectionModel.selectedItems.size == 0) {
ViewerNodeSelection.None
} else {
ViewerNodeSelection.Selected(cashViewerTable.selectionModel.selectedItems[0].value)
}
}, arrayOf(cashViewerTable.selectionModel.selectedItems))
val selectedViewerNode = cashViewerTable.singleRowSelection()
data class StateRow (
val originated: LocalDateTime,
@ -221,10 +212,10 @@ class CashViewer : View() {
}
private val noSelectionStates = FXCollections.observableArrayList<StateAndRef<Cash.State>>()
private val selectedViewerNodeStates = ChosenList(EasyBind.map(selectedViewerNode) { selection ->
private val selectedViewerNodeStates = ChosenList<StateAndRef<Cash.State>>(EasyBind.map(selectedViewerNode) { selection ->
when (selection) {
CashViewer.ViewerNodeSelection.None -> noSelectionStates
is CashViewer.ViewerNodeSelection.Selected ->
is SingleRowSelection.None -> noSelectionStates
is SingleRowSelection.Selected ->
when (selection.node) {
CashViewer.ViewerNode.Root -> noSelectionStates
is CashViewer.ViewerNode.IssuerNode -> selection.node.states
@ -236,8 +227,8 @@ class CashViewer : View() {
private val noSelectionSumEquiv = EasyBind.map(reportingCurrency) { Amount(0, it) }
private val selectedViewerNodeSumEquiv = EasyBind.monadic(selectedViewerNode).flatMap { selection ->
when (selection) {
ViewerNodeSelection.None -> noSelectionSumEquiv
is ViewerNodeSelection.Selected ->
is SingleRowSelection.None -> noSelectionSumEquiv
is SingleRowSelection.Selected ->
when (selection.node) {
ViewerNode.Root -> noSelectionSumEquiv
is ViewerNode.IssuerNode -> selection.node.sumEquivAmount
@ -252,10 +243,10 @@ class CashViewer : View() {
private val onlyLeftPaneShown = FXCollections.observableArrayList<Node>(leftPane)
private val bothPanesShown = FXCollections.observableArrayList<Node>(leftPane, rightPane)
private val panesShown = ChosenList(EasyBind.map(selectedViewerNode) {
private val panesShown = ChosenList<Node>(EasyBind.map(selectedViewerNode) {
when (it) {
CashViewer.ViewerNodeSelection.None -> onlyLeftPaneShown
is CashViewer.ViewerNodeSelection.Selected -> bothPanesShown
is SingleRowSelection.None -> onlyLeftPaneShown
is SingleRowSelection.Selected -> bothPanesShown
}
})
@ -271,7 +262,7 @@ class CashViewer : View() {
Bindings.bindContent(topSplitPane.items, panesShown)
rightPane.visibleProperty().bind(EasyBind.map(selectedViewerNode) {
it != ViewerNodeSelection.None
it !is SingleRowSelection.None
})
totalPositionsLabel.textProperty().bind(Bindings.createStringBinding({

View File

@ -1,5 +1,6 @@
package com.r3corda.explorer.views
import com.r3corda.client.fxutils.ChosenList
import com.r3corda.client.model.*
import com.r3corda.contracts.asset.Cash
import com.r3corda.core.contracts.Amount
@ -8,10 +9,15 @@ import com.r3corda.core.contracts.withoutIssuer
import com.r3corda.core.transactions.SignedTransaction
import com.r3corda.explorer.formatters.AmountFormatter
import com.r3corda.explorer.model.ReportingCurrencyModel
import com.r3corda.explorer.ui.SingleRowSelection
import com.r3corda.explorer.ui.setColumnPrefWidthPolicy
import com.r3corda.explorer.ui.singleRowSelection
import com.r3corda.explorer.ui.toTableCellFactory
import com.r3corda.node.services.monitor.ServiceToClientEvent
import javafx.beans.binding.Bindings
import javafx.beans.property.ReadOnlyObjectWrapper
import javafx.beans.value.ObservableValue
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.geometry.Insets
import javafx.scene.control.Label
@ -31,6 +37,7 @@ import java.util.*
class TransactionViewer: View() {
override val root: VBox by fxml()
// Top half (transactions table)
private val transactionViewTable: TableView<ViewerNode> by fxid("TransactionViewTable")
private val transactionViewTransactionId: TableColumn<ViewerNode, String> by fxid("TransactionViewTransactionId")
private val transactionViewOriginator: TableColumn<ViewerNode, String> by fxid("TransactionViewOriginator")
@ -39,6 +46,11 @@ class TransactionViewer: View() {
private val transactionViewCommandTypes: TableColumn<ViewerNode, String> by fxid("TransactionViewCommandTypes")
private val transactionViewTotalValueEquiv: TableColumn<ViewerNode, Amount<Currency>> by fxid("TransactionViewTotalValueEquiv")
// Bottom half (details)
private val lowLevelEventsTable: TableView<ServiceToClientEvent> by fxid("LowLevelEventsTable")
private val lowLevelEventsTimestamp: TableColumn<ServiceToClientEvent, Instant> by fxid("LowLevelEventsTimestamp")
private val lowLevelEventsEvent: TableColumn<ServiceToClientEvent, ServiceToClientEvent> by fxid("LowLevelEventsEvent")
private val gatheredTransactionDataList: ObservableList<out GatheredTransactionData>
by observableListReadOnly(GatheredTransactionDataModel::gatheredTransactionDataList)
private val reportingExchange: ObservableValue<Pair<Currency, (Amount<Currency>) -> Amount<Currency>>>
@ -51,7 +63,8 @@ class TransactionViewer: View() {
val statusUpdated: ObservableValue<Instant>,
val commandTypes: ObservableValue<Collection<Class<CommandData>>>,
val viewTotalValueEquiv: ObservableValue<Amount<Currency>?>,
val transaction: ObservableValue<SignedTransaction?>
val transaction: ObservableValue<SignedTransaction?>,
val allEvents: ObservableList<out ServiceToClientEvent>
)
private val viewerNodes = EasyBind.map(gatheredTransactionDataList) {
@ -78,7 +91,8 @@ class TransactionViewer: View() {
viewTotalValueEquiv = EasyBind.combine(reportingExchange, it.transaction) { exchange, transaction ->
transaction?.let { calculateTotalEquiv(exchange.first, exchange.second, transaction) }
},
transaction = it.transaction
transaction = it.transaction,
allEvents = it.allEvents
)
}
@ -92,7 +106,18 @@ class TransactionViewer: View() {
)
}
private val selectedViewerNode = transactionViewTable.singleRowSelection()
private val noLowLevelEvents = FXCollections.emptyObservableList<ServiceToClientEvent>()
private val lowLevelEvents = ChosenList(EasyBind.map(selectedViewerNode) {
when (it) {
is SingleRowSelection.None -> noLowLevelEvents
is SingleRowSelection.Selected -> it.node.allEvents
}
})
init {
// Transaction table
Bindings.bindContent(transactionViewTable.items, viewerNodes)
transactionViewTable.setColumnPrefWidthPolicy { tableWidthWithoutPaddingAndBorder, column ->
@ -146,5 +171,13 @@ class TransactionViewer: View() {
}
transactionViewTotalValueEquiv.setCellValueFactory<ViewerNode, Amount<Currency>> { it.value.viewTotalValueEquiv }
transactionViewTotalValueEquiv.cellFactory = AmountFormatter.comma.toTableCellFactory()
// Low level events
Bindings.bindContent(lowLevelEventsTable.items, lowLevelEvents)
lowLevelEventsTimestamp.setCellValueFactory { ReadOnlyObjectWrapper(it.value.time) }
lowLevelEventsEvent.setCellValueFactory { ReadOnlyObjectWrapper(it.value) }
lowLevelEventsTable.setColumnPrefWidthPolicy { tableWidthWithoutPaddingAndBorder, column ->
Math.floor(tableWidthWithoutPaddingAndBorder.toDouble() / lowLevelEventsTable.columns.size).toInt()
}
}
}

View File

@ -32,7 +32,7 @@
</TextField>
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true" styleClass="search-clear">
<image>
<Image url="@../../images/clear_inactive.png" />
<Image url="@../../../../../../../../../internal/explorer/src/main/resources/images/clear_inactive.png" />
</image>
<StackPane.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
@ -156,6 +156,16 @@
</columns>
</TableView>
</content></TitledPane>
<TitledPane animated="false" text="Low level events">
<content>
<TableView fx:id="LowLevelEventsTable">
<columns>
<TableColumn fx:id="LowLevelEventsTimestamp" prefWidth="102.0" text="Timestamp" />
<TableColumn fx:id="LowLevelEventsEvent" prefWidth="138.0" text="Event" />
</columns>
</TableView>
</content>
</TitledPane>
</panes>
</Accordion>
</items>