Add treeView to visualize changes in transaction

Test: N/A
Change-Id: Ida61733f1cc73b3bee4d3963b1bc17dfe2b626fc
This commit is contained in:
Pablo Gamito
2020-06-01 23:33:17 +01:00
parent d07c46dc6b
commit bd47ff7863
4 changed files with 142 additions and 22 deletions

View File

@@ -57,7 +57,7 @@ import LocalStore from './localstore.js'
import DataAdb from './DataAdb.vue'
import FileType from './mixins/FileType.js'
const APP_NAME = "Winscope";
const APP_NAME = "Winscope"
export default {
name: 'app',

View File

@@ -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>

View File

@@ -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 @@ export default {
transactionTypes: Array.from(transactionTypes),
selectedTransactionTypes: [],
searchInput: "",
selectedTree: null,
};
},
computed: {
@@ -95,6 +115,47 @@ export default {
},
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 @@ export default {
}
};
},
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 @@ export default {
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 @@ export default {
}
}
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;
}

View File

@@ -65,6 +65,7 @@
:initial-depth="depth + 1"
:collapse="collapseChildren"
:collapseChildren="collapseChildren"
:useGlobalCollapsedState="useGlobalCollapsedState"
ref="children"
/>
</div>
@@ -98,6 +99,14 @@ export default {
"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 @@ export default {
isChildSelected: false,
clickTimeout: null,
isCollapsedByDefault,
localCollapsedState: isCollapsedByDefault,
};
},
methods: {
setCollapseValue(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 @@ export default {
return false;
}
if (this.useGlobalCollapsedState) {
return this.$store.getters.collapsedStateStoreFor(this.item) ??
this.isCollapsedByDefault;
}
return this.localCollapsedState;
},
isSelected() {
return this.selected === this.item;