mirror of
https://github.com/corda/corda.git
synced 2024-12-20 13:33:12 +00:00
[CORDA-1676] Adjust progress tracking rendering for skipped elements (#4372)
* Adjust styling for flow steps that are skipped
This commit is contained in:
parent
bad7b9b187
commit
f58757bda9
@ -52,8 +52,6 @@ object Emoji {
|
|||||||
val CODE_DEVELOPER: String = codePointsString(0x1F469, 0x200D, 0x1F4BB)
|
val CODE_DEVELOPER: String = codePointsString(0x1F469, 0x200D, 0x1F4BB)
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val CODE_WARNING_SIGN: String = codePointsString(0x26A0, 0xFE0F)
|
val CODE_WARNING_SIGN: String = codePointsString(0x26A0, 0xFE0F)
|
||||||
@JvmStatic
|
|
||||||
val CROSS_MARK_BUTTON: String = codePointsString(0x274E)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When non-null, toString() methods are allowed to use emoji in the output as we're going to render them to a
|
* When non-null, toString() methods are allowed to use emoji in the output as we're going to render them to a
|
||||||
@ -81,7 +79,6 @@ object Emoji {
|
|||||||
val rightArrow: String get() = if (emojiMode.get() != null) "$CODE_RIGHT_ARROW " else "▶︎"
|
val rightArrow: String get() = if (emojiMode.get() != null) "$CODE_RIGHT_ARROW " else "▶︎"
|
||||||
val skullAndCrossbones: String get() = if (emojiMode.get() != null) "$CODE_SKULL_AND_CROSSBONES " else "☂"
|
val skullAndCrossbones: String get() = if (emojiMode.get() != null) "$CODE_SKULL_AND_CROSSBONES " else "☂"
|
||||||
val noEntry: String get() = if (emojiMode.get() != null) "$CODE_NO_ENTRY " else "✘"
|
val noEntry: String get() = if (emojiMode.get() != null) "$CODE_NO_ENTRY " else "✘"
|
||||||
val notRun: String get() = if (emojiMode.get() != null) "$CROSS_MARK_BUTTON " else "-"
|
|
||||||
|
|
||||||
inline fun <T> renderIfSupported(body: () -> T): T {
|
inline fun <T> renderIfSupported(body: () -> T): T {
|
||||||
if (hasEmojiTerminal)
|
if (hasEmojiTerminal)
|
||||||
|
@ -10,6 +10,7 @@ import org.apache.logging.log4j.core.appender.ConsoleAppender
|
|||||||
import org.apache.logging.log4j.core.appender.OutputStreamManager
|
import org.apache.logging.log4j.core.appender.OutputStreamManager
|
||||||
import org.crsh.text.RenderPrintWriter
|
import org.crsh.text.RenderPrintWriter
|
||||||
import org.fusesource.jansi.Ansi
|
import org.fusesource.jansi.Ansi
|
||||||
|
import org.fusesource.jansi.Ansi.Attribute
|
||||||
import org.fusesource.jansi.AnsiConsole
|
import org.fusesource.jansi.AnsiConsole
|
||||||
import org.fusesource.jansi.AnsiOutputStream
|
import org.fusesource.jansi.AnsiOutputStream
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
@ -146,22 +147,25 @@ abstract class ANSIProgressRenderer {
|
|||||||
with(ansi) {
|
with(ansi) {
|
||||||
var lines = 0
|
var lines = 0
|
||||||
for ((index, step) in tree.withIndex()) {
|
for ((index, step) in tree.withIndex()) {
|
||||||
|
val processedStep = treeIndexProcessed.contains(index)
|
||||||
|
val skippedStep = index < treeIndex && !processedStep
|
||||||
|
val activeStep = index == treeIndex
|
||||||
|
|
||||||
val marker = when {
|
val marker = when {
|
||||||
treeIndexProcessed.contains(index) -> " ${Emoji.greenTick} "
|
processedStep -> " ${Emoji.greenTick} "
|
||||||
index < treeIndex -> " ${Emoji.notRun} "
|
skippedStep -> " "
|
||||||
treeIndex == tree.lastIndex -> "${Emoji.greenTick} "
|
activeStep -> "${Emoji.rightArrow} "
|
||||||
index == treeIndex -> "${Emoji.rightArrow} "
|
|
||||||
error -> "${Emoji.noEntry} "
|
error -> "${Emoji.noEntry} "
|
||||||
else -> " " // Not reached yet.
|
else -> " " // Not reached yet.
|
||||||
}
|
}
|
||||||
a(" ".repeat(step.first))
|
a(" ".repeat(step.first))
|
||||||
a(marker)
|
a(marker)
|
||||||
|
|
||||||
val active = index == treeIndex
|
when {
|
||||||
if (active) bold()
|
activeStep -> renderInBold(step.second, ansi)
|
||||||
a(step.second)
|
skippedStep -> renderInFaint(step.second, ansi)
|
||||||
if (active) boldOff()
|
else -> a(step.second)
|
||||||
|
}
|
||||||
|
|
||||||
eraseLine(Ansi.Erase.FORWARD)
|
eraseLine(Ansi.Erase.FORWARD)
|
||||||
newline()
|
newline()
|
||||||
@ -171,6 +175,21 @@ abstract class ANSIProgressRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun renderInBold(payload: String, ansi: Ansi): Unit {
|
||||||
|
with(ansi) {
|
||||||
|
a(Attribute.INTENSITY_BOLD)
|
||||||
|
a(payload)
|
||||||
|
a(Attribute.INTENSITY_BOLD_OFF)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderInFaint(payload: String, ansi: Ansi): Unit {
|
||||||
|
with(ansi) {
|
||||||
|
a(Attribute.INTENSITY_FAINT)
|
||||||
|
a(payload)
|
||||||
|
a(Attribute.INTENSITY_BOLD_OFF)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
package net.corda.tools.shell.utilities
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.argumentCaptor
|
||||||
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
|
import com.nhaarman.mockito_kotlin.verify
|
||||||
|
import net.corda.core.flows.StateMachineRunId
|
||||||
|
import net.corda.core.internal.concurrent.openFuture
|
||||||
|
import net.corda.core.messaging.DataFeed
|
||||||
|
import net.corda.core.messaging.FlowProgressHandleImpl
|
||||||
|
import net.corda.tools.shell.utlities.ANSIProgressRenderer
|
||||||
|
import net.corda.tools.shell.utlities.CRaSHANSIProgressRenderer
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.crsh.text.RenderPrintWriter
|
||||||
|
import org.junit.Test
|
||||||
|
import rx.Observable
|
||||||
|
import org.fusesource.jansi.Ansi
|
||||||
|
import org.junit.Before
|
||||||
|
import rx.subjects.PublishSubject
|
||||||
|
|
||||||
|
class ANSIProgressRendererTest {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val INTENSITY_BOLD_ON_ASCII = "[1m"
|
||||||
|
private const val INTENSITY_OFF_ASCII = "[22m"
|
||||||
|
private const val INTENSITY_FAINT_ON_ASCII = "[2m"
|
||||||
|
|
||||||
|
private const val STEP_1_LABEL = "Running step 1"
|
||||||
|
private const val STEP_2_LABEL = "Running step 2"
|
||||||
|
private const val STEP_3_LABEL = "Running step 3"
|
||||||
|
|
||||||
|
private const val STEP_1_SUCCESS_OUTPUT = """✓ $STEP_1_LABEL"""
|
||||||
|
private const val STEP_2_SKIPPED_OUTPUT = """ $INTENSITY_FAINT_ON_ASCII$STEP_2_LABEL$INTENSITY_OFF_ASCII"""
|
||||||
|
private const val STEP_3_ACTIVE_OUTPUT = """✓ $INTENSITY_BOLD_ON_ASCII$STEP_3_LABEL$INTENSITY_OFF_ASCII"""
|
||||||
|
}
|
||||||
|
|
||||||
|
lateinit var printWriter: RenderPrintWriter
|
||||||
|
lateinit var progressRenderer: ANSIProgressRenderer
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
printWriter = mock()
|
||||||
|
progressRenderer = CRaSHANSIProgressRenderer(printWriter)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test that steps are rendered appropriately depending on their status`() {
|
||||||
|
val indexSubject = PublishSubject.create<Int>()
|
||||||
|
val feedSubject = PublishSubject.create<List<Pair<Int, String>>>()
|
||||||
|
val stepsTreeIndexFeed = DataFeed<Int, Int>(0, indexSubject)
|
||||||
|
val stepsTreeFeed = DataFeed<List<Pair<Int, String>>, List<Pair<Int, String>>>(listOf(), feedSubject)
|
||||||
|
val flowProgressHandle = FlowProgressHandleImpl(StateMachineRunId.createRandom(), openFuture<String>(), Observable.empty(), stepsTreeIndexFeed, stepsTreeFeed)
|
||||||
|
|
||||||
|
progressRenderer.render(flowProgressHandle)
|
||||||
|
// The flow is currently at step 3, while step 1 has been completed and step 2 has been skipped.
|
||||||
|
indexSubject.onNext(2)
|
||||||
|
feedSubject.onNext(listOf(Pair(0, STEP_1_LABEL), Pair(0, STEP_2_LABEL), Pair(0, STEP_3_LABEL)))
|
||||||
|
|
||||||
|
val captor = argumentCaptor<Ansi>()
|
||||||
|
verify(printWriter).print(captor.capture())
|
||||||
|
assertThat(captor.firstValue.toString()).containsSequence(STEP_1_SUCCESS_OUTPUT, STEP_2_SKIPPED_OUTPUT, STEP_3_ACTIVE_OUTPUT)
|
||||||
|
verify(printWriter).flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user