Add treeView to visualize changes in transaction Test: N/A Change-Id: Ida61733f1cc73b3bee4d3963b1bc17dfe2b626fc
diff --git a/tools/winscope/src/App.vue b/tools/winscope/src/App.vue index 3006507..0f6a2ac 100644 --- a/tools/winscope/src/App.vue +++ b/tools/winscope/src/App.vue
@@ -57,7 +57,7 @@ import DataAdb from './DataAdb.vue' import FileType from './mixins/FileType.js' -const APP_NAME = "Winscope"; +const APP_NAME = "Winscope" export default { name: 'app',
diff --git a/tools/winscope/src/TraceView.vue b/tools/winscope/src/TraceView.vue index b51022c..af58c0a 100644 --- a/tools/winscope/src/TraceView.vue +++ b/tools/winscope/src/TraceView.vue
@@ -37,6 +37,7 @@ :filter="hierarchyFilter" :flattened="store.flattened" :items-clickable="true" + :useGlobalCollapsedState="true" ref="hierarchy" /> </md-card> @@ -52,6 +53,7 @@ :item="selectedTree" :filter="propertyFilter" :collapseChildren="true" + :useGlobalCollapsedState="true" /> </md-card> </md-card-content>
diff --git a/tools/winscope/src/TransactionsView.vue b/tools/winscope/src/TransactionsView.vue index 24f4028..34a517c 100644 --- a/tools/winscope/src/TransactionsView.vue +++ b/tools/winscope/src/TransactionsView.vue
@@ -31,7 +31,11 @@ </md-table-toolbar> <div class="scrollBody" ref="tableBody"> - <md-table-row v-for="transaction in filteredData" :key="transaction.timestamp"> + <md-table-row + v-for="transaction in filteredData" + :key="transaction.timestamp" + @click="transactionSelected(transaction)" + > <md-table-cell>{{transaction.time}}</md-table-cell> <div v-if="transaction.type == 'transaction'"> @@ -49,9 +53,24 @@ </div> </md-table> + + <md-card class="changes"> + <md-content md-tag="md-toolbar" md-elevation="0" class="card-toolbar md-transparent md-dense"> + <h2 class="md-title" style="flex: 1">Changes</h2> + </md-content> + <div class="changes-content"> + <tree-view :item="selectedTree" :useGlobalCollapsedState="true" /> + </div> + </md-card> + </md-card-content> </template> <script> +import TreeView from './TreeView.vue'; + +import { transform_json } from './transform.js'; +import { stableIdCompatibilityFixup } from './utils/utils.js' + export default { name: 'transactionsview', props: ['data'], @@ -71,6 +90,7 @@ transactionTypes: Array.from(transactionTypes), selectedTransactionTypes: [], searchInput: "", + selectedTree: null, }; }, computed: { @@ -95,6 +115,47 @@ }, methods: { + removeNullFields(changeObject) { + for (const key in changeObject) { + if (changeObject[key] === null) { + delete changeObject[key]; + } + } + + return changeObject; + }, + transactionSelected(transaction) { + let obj = this.removeNullFields(transaction.obj); + let name = transaction.type; + + if (transaction.type == "transaction") { + name = "changes"; + obj = {}; + + const [surfaceChanges, displayChanges] = + this.aggregateTransactions(transaction.transactions); + + for (const changeId in surfaceChanges) { + this.removeNullFields(surfaceChanges[changeId]); + } + for (const changeId in displayChanges) { + this.removeNullFields(displayChanges[changeId]); + } + + if (Object.keys(surfaceChanges).length > 0) { + obj.surfaceChanges = surfaceChanges; + } + + if (Object.keys(displayChanges).length > 0) { + obj.displayChanges = displayChanges; + } + } + + const transactionUnique = transaction.timestamp; + this.selectedTree = transform_json(obj, name, transactionUnique, { + formatter: () => {} + }); + }, filterTransactions(condition) { return (entry) => { if (entry.type == "transaction") { @@ -110,7 +171,27 @@ } }; }, - summarizeTranscations(transactions) { + mergeChanges(a, b) { + const res = {}; + + for (const key in a) { + if (a[key] !== null && a.hasOwnProperty(key)) { + res[key] = a[key]; + } + } + + for (const key in b) { + if (b[key] !== null && key !== 'id' && b.hasOwnProperty(key)) { + if (res.hasOwnProperty(key)) { + throw new Error(`Merge failed – key '${key}' already present`); + } + res[key] = b[key]; + } + } + + return res; + }, + aggregateTransactions(transactions) { const surfaceChanges = {}; const displayChanges = {}; @@ -120,12 +201,12 @@ switch (transaction.type) { case "surfaceChange": surfaceChanges[obj.id] = - Object.assign(surfaceChanges[obj.id] ?? {}, obj); + this.mergeChanges(surfaceChanges[obj.id] ?? {}, obj); break; case "displayChange": displayChanges[obj.id] = - Object.assign(displayChanges[obj.id] ?? {}, obj); + this.mergeChanges(displayChanges[obj.id] ?? {}, obj); break; default: @@ -133,31 +214,50 @@ } } - const summary = []; + return [surfaceChanges, displayChanges]; + }, + summarizeTranscations(transactions) { + const ids = { + "surfaceChange": new Set(), + "displayChange": new Set(), + }; - const surfaceChangesId = Object.keys(surfaceChanges); - if (surfaceChangesId.length > 0) { - summary.push(`surfaceChanges: ${surfaceChangesId.join(', ')}`); + for (const transaction of transactions) { + ids[transaction.type].add(transaction.obj.id); } - const displayChangesIds = Object.keys(displayChanges); - if (displayChangesIds.length > 0) { - summary.push(`displayChanges: ${displayChangesIds.join(', ')}`); + const summary = []; + + if (ids.surfaceChange.size > 0) { + summary.push(`surfaceChanges: ${[...ids.surfaceChange].join(', ')}`); + } + + if (ids.displayChange.size > 0) { + summary.push(`displayChanges: ${[...ids.displayChange].join(', ')}`); } return summary.join(" | "); - } + }, + }, + components: { + 'tree-view': TreeView, } } </script> <style scoped> -/* .transaction-table { - width: 100%; -} */ +.container { + display: flex; + flex-wrap: wrap; +} + +.transaction-table, +.changes { + flex: 1; + margin: 8px; +} .scrollBody { - /* width: 100%; */ max-height: 75vh; overflow: scroll; }
diff --git a/tools/winscope/src/TreeView.vue b/tools/winscope/src/TreeView.vue index 85a5a01..3dd528a 100644 --- a/tools/winscope/src/TreeView.vue +++ b/tools/winscope/src/TreeView.vue
@@ -65,6 +65,7 @@ :initial-depth="depth + 1" :collapse="collapseChildren" :collapseChildren="collapseChildren" + :useGlobalCollapsedState="useGlobalCollapsedState" ref="children" /> </div> @@ -98,6 +99,14 @@ "initial-depth", "collapse", "collapseChildren", + // Allows collapse state to be tracked by Vuex so that collapse state of + // items with same stableId can remain consisten accross time and easily + // toggled from anywhere in the app. + // Should be true if you are using the same TreeView to display multiple + // trees throughout the component's lifetime to make sure same nodes are + // toggled when switching back and forth between trees. + // If true, requires all nodes in tree to have a stableId. + "useGlobalCollapsedState", ], data() { const isCollapsedByDefault = this.collapse ?? false; @@ -106,14 +115,19 @@ isChildSelected: false, clickTimeout: null, isCollapsedByDefault, + localCollapsedState: isCollapsedByDefault, }; }, methods: { setCollapseValue(isCollapsed) { - this.$store.commit('setCollapsedState', { - item: this.item, - isCollapsed, - }); + if (this.useGlobalCollapsedState) { + this.$store.commit('setCollapsedState', { + item: this.item, + isCollapsed, + }); + } else { + this.localCollapsedState = isCollapsed; + } }, toggleTree() { this.setCollapseValue(!this.isCollapsed); @@ -236,8 +250,12 @@ return false; } - return this.$store.getters.collapsedStateStoreFor(this.item) ?? + if (this.useGlobalCollapsedState) { + return this.$store.getters.collapsedStateStoreFor(this.item) ?? this.isCollapsedByDefault; + } + + return this.localCollapsedState; }, isSelected() { return this.selected === this.item;