mirror of
https://github.com/corda/corda.git
synced 2025-04-07 19:34:41 +00:00
explorer: Add Low level events viewer for tx screen
asd
This commit is contained in:
parent
f4de05c982
commit
767077c764
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>()
|
||||
}
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -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({
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user