Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion workflow-trace-viewer/api/workflow-trace-viewer.api
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,19 @@ public final class com/squareup/workflow1/traceviewer/MainKt {

public final class com/squareup/workflow1/traceviewer/model/Node {
public static final field $stable I
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/util/List;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getChildren ()Ljava/util/List;
public final fun getId ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getParent ()Ljava/lang/String;
public final fun getParentId ()Ljava/lang/String;
public final fun getProps ()Ljava/lang/Object;
public final fun getRenderings ()Ljava/lang/Object;
public final fun getState ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/squareup/workflow1/traceviewer/ui/FrameSelectTabKt {
Expand All @@ -42,6 +51,7 @@ public final class com/squareup/workflow1/traceviewer/util/ComposableSingletons$
}

public final class com/squareup/workflow1/traceviewer/util/JsonParserKt {
public static final field ROOT_ID Ljava/lang/String;
public static final fun parseTrace (Lio/github/vinceglb/filekit/PlatformFile;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,25 @@ package com.squareup.workflow1.traceviewer.model
* TBD what more metadata should be involved with each node, e.g. (props, states, # of render passes)
*/
public class Node(
val id: String,
val name: String,
val children: List<Node>
)
val id: String,
val parent: String,
val parentId: String,
val props: Any? = null,
val state: Any? = null,
val renderings: Any? = null,
val children: List<Node>,
) {
override fun toString(): String {
return "Node(name='$name', parent='$parent', children=${children.size})"
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Node) return false
return this.id == other.id
}
override fun hashCode(): Int {
return id.hashCode()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public fun FrameSelectTab(
) {
items(frames.size) { index ->
Text(
text = "State ${index + 1}",
text = "Frame ${index + 1}",
color = if (index == currentIndex) Color.Black else Color.LightGray,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.squareup.workflow1.traceviewer.model.Node
Expand Down Expand Up @@ -83,11 +85,22 @@ private fun NodePanelDetails(
return@Column
}

Text("only visible with a node selected")
Text(
text = "This is a node panel for ${node.name}",
fontSize = 20.sp,
modifier = Modifier.padding(8.dp)
val textModifier = Modifier.padding(8.dp)
val textStyle = TextStyle(fontSize = 16.sp, textAlign = TextAlign.Center)
val fields = mapOf(
"Name" to node.name,
"ID" to node.id,
"Props" to node.props.toString(),
"State" to node.state.toString(),
"Renderings" to node.renderings.toString()
)

fields.forEach { (label, value) ->
Text(
text = "$label: $value",
modifier = textModifier,
style = textStyle
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ public fun RenderDiagram(
if (!isLoading) {
DrawTree(frames[frameInd], onNodeSelect)
}

// TODO: catch errors and display UI here
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ import com.squareup.workflow1.traceviewer.model.Node
import io.github.vinceglb.filekit.PlatformFile
import io.github.vinceglb.filekit.readString

/*
The root workflow Node uses an ID of 0, and since we are filtering childrenByParent by the
parentId, the root node has a parent of -1 ID. This is reflected seen inside android-register
*/
const val ROOT_ID: String = "-1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My guess is when the parent is null in the WorkflowSession you have just given it a default value of -1 in your recording code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! I will make note of this on both PR's in workflow library and register


/**
* Parses a given file's JSON String into [Node] with Moshi adapters.
* Parses a given file's JSON String into a list of [Node]s with Moshi adapters. Each of these nodes
* count as the root of a tree which forms a Frame.
*
* @return A [ParseResult] representing result of parsing, either an error related to the
* format of the JSON, or a success and a parsed trace.
Expand All @@ -19,18 +26,63 @@ public suspend fun parseTrace(
): ParseResult {
return try {
val jsonString = file.readString()
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val workflowList = Types.newParameterizedType(List::class.java, Node::class.java)
val workflowAdapter: JsonAdapter<List<Node>> = moshi.adapter(workflowList)
val trace = workflowAdapter.fromJson(jsonString)
ParseResult.Success(trace)
val workflowAdapter = createMoshiAdapter()
val parsedRenderPasses = workflowAdapter.fromJson(jsonString)

val parsedFrames = mutableListOf<Node>()
parsedRenderPasses?.forEach { renderPass ->
val parsed = getFrameFromRenderPass(renderPass)
parsedFrames.add(parsed)
}

ParseResult.Success(parsedFrames)
} catch (e: Exception) {
ParseResult.Failure(e)
}
}

/**
* Creates a Moshi adapter for parsing the JSON trace file.
*/
private fun createMoshiAdapter(): JsonAdapter<List<List<Node>>> {
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val workflowList = Types.newParameterizedType(
List::class.java,
Types.newParameterizedType(List::class.java, Node::class.java)
)
val adapter: JsonAdapter<List<List<Node>>> = moshi.adapter(workflowList)
return adapter
}

/**
* We take an unparsed render pass and build up a tree structure from it to form a Frame.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* We take an unparsed render pass and build up a tree structure from it to form a Frame.
* We take an unparsed render pass and build up a tree structure from it to form a Frame.
* @return Node the root node of the tree for that frame.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

*
* @return Node the root node of the tree for that specific frame.
*/
private fun getFrameFromRenderPass(renderPass: List<Node>): Node {
val childrenByParent: Map<String, List<Node>> = renderPass.groupBy { it.parentId }
val root = childrenByParent[ROOT_ID]?.single()
return buildTree(root!!, childrenByParent)
}

/**
* Recursively builds a tree using each node's children.
*/
private fun buildTree(node: Node, childrenByParent: Map<String, List<Node>>): Node {
val children = (childrenByParent[node.id] ?: emptyList())
return Node(
name = node.name,
id = node.id,
parent = node.parent,
parentId = node.parentId,
props = node.props,
state = node.state,
children = children.map { buildTree(it, childrenByParent) },
)
}

sealed interface ParseResult {
class Success(val trace: List<Node>?) : ParseResult
class Failure(val error: Throwable) : ParseResult
Expand Down