Refactor QC view to use new API endpoint.

This provides essentially the same user experience as the old
endpoint, with one exception as of this commit:

* The user is not able to “accept” or “unaccept” QC events.
This commit is contained in:
D. Berge
2022-03-09 17:50:55 +01:00
parent 14a2f57c8d
commit c86cbdc493

View File

@@ -65,26 +65,30 @@
<v-treeview <v-treeview
:items="filteredItems" :items="filteredItems"
:open.sync="open" :open.sync="open"
item-key="serial" item-key="_serial"
item-text="_text"
item-children="_children"
:open-on-click="true" :open-on-click="true"
> >
<template v-slot:label="{item}"> <template v-slot:label="{item}">
<div @dblclick.stop.prevent="toggleChildren(item)"> <div @dblclick.stop.prevent="toggleChildren(item)" v-if="item._kind=='test'">
{{item.name}} <b>{{item._text}}</b>
<v-chip v-if="item.children && itemCount(item)" <v-chip class="ml-2" v-if="item._children && itemCount(item)"
small x-small
color="warning" color="warning"
v-text="itemCount(item)" v-text="itemCount(item)"
> >
</v-chip> </v-chip>
<v-chip v-for="label of item.labels" <v-chip v-for="label of item.labels"
class="mx-1" class="mx-1"
small small
:color="labels[label] && labels[label].view.colour" :color="labels[label] && labels[label].view.colour"
:title="labels[label] && labels[label].view.description" :title="labels[label] && labels[label].view.description"
:close="writeaccess && label == 'QCAccepted'" :close="writeaccess && label == 'QCAccepted'"
@click:close="unaccept(item)"> @click:close="unaccept(item)"
>
{{label}} {{label}}
</v-chip> </v-chip>
@@ -121,6 +125,20 @@
</v-btn> </v-btn>
</v-hover> </v-hover>
</template> </template>
</div>
<div :title="item.remarks" @dblclick.stop.prevent="toggleChildren(item)" v-else-if="item._kind=='sequence'">
{{item._text}}
<v-chip class="ml-2" v-if="item._children && itemCount(item)"
x-small
color="primary"
v-text="itemCount(item)"
>
</v-chip>
</div>
<div class="text--secondary" v-else>
{{item._text}}
</div> </div>
</template> </template>
@@ -174,12 +192,10 @@ export default {
sequences () { sequences () {
function getSeq (item) { function getSeq (item) {
return "_id" in item return item?._kind == "sequence"
? Array.isArray(item._id) ? item.sequence
? Number(item._id[0]) : item?._children?.length
: Number(item._id) ? item._children.map(i => getSeq(i)).flat()
: "children" in item
? item.children.map(i => getSeq(i)).flat()
: undefined; : undefined;
} }
@@ -192,8 +208,8 @@ export default {
const values = []; const values = [];
function filterResults (item) { function filterResults (item) {
if (item.children) { if (item._children) {
for (const child of item.children) { for (const child of item._children) {
filterResults(child); filterResults(child);
} }
} else if (item._id && item.id) { } else if (item._id && item.id) {
@@ -253,17 +269,17 @@ export default {
itemCount (item, count = 0) { itemCount (item, count = 0) {
let sum = count; let sum = count;
if (item.children) { if (item._children) {
sum += item.children.map(child => this.itemCount(child)).reduce( (a, b) => a+b, 0 ) sum += item._children.map(child => this.itemCount(child)).reduce( (a, b) => a+b, 0 )
} else { } else {
sum++; sum++;
} }
return sum; return sum;
}, },
accepted (item) { accepted (item) {
if (item.children) { if (item._children) {
return item.children.every(child => this.accepted(child)); return item._children.every(child => this.accepted(child));
} }
if (item.labels) { if (item.labels) {
@@ -273,8 +289,8 @@ export default {
}, },
accept (item) { accept (item) {
if (item.children) { if (item._children) {
for (const child of item.children) { for (const child of item._children) {
this.accept(child); this.accept(child);
} }
return; return;
@@ -288,8 +304,8 @@ export default {
}, },
unaccept (item) { unaccept (item) {
if (item.children) { if (item._children) {
for (const child of item.children) { for (const child of item._children) {
this.unaccept(child); this.unaccept(child);
} }
return; return;
@@ -319,7 +335,6 @@ export default {
for (const path of sequences) { for (const path of sequences) {
const url = `/project/${this.$route.params.project}/meta/raw/sequences/${path}`; const url = `/project/${this.$route.params.project}/meta/raw/sequences/${path}`;
const promise = this.api([url]).then(res => { const promise = this.api([url]).then(res => {
console.log("Apply QC labels (seq)", res);
for (const item of res) { for (const item of res) {
const obj = this.resultObjects.find(o => o.sequence == item.sequence && const obj = this.resultObjects.find(o => o.sequence == item.sequence &&
o.point == item.point && o.point == item.point &&
@@ -337,7 +352,6 @@ export default {
for (const path of points) { for (const path of points) {
const url = `/project/${this.$route.params.project}/meta/raw/points/${path}`; const url = `/project/${this.$route.params.project}/meta/raw/points/${path}`;
const promise = this.api([url]).then(res => { const promise = this.api([url]).then(res => {
console.log("Apply QC labels (point)", res);
for (const item of res) { for (const item of res) {
const obj = this.resultObjects.find(o => o.sequence == item.sequence && const obj = this.resultObjects.find(o => o.sequence == item.sequence &&
o.point == item.point && o.point == item.point &&
@@ -358,27 +372,25 @@ export default {
async saveLabels () { async saveLabels () {
const url = `/project/${this.$route.params.project}/meta`; const url = `/project/${this.$route.params.project}/meta`;
console.log("Saving", this.resultObjects.filter(r => typeof r.value !== "undefined"));
const res = await this.api([url, { const res = await this.api([url, {
method: "PUT", method: "PUT",
body: this.resultObjects.filter(r => typeof r.value !== "undefined") body: this.resultObjects.filter(r => typeof r.value !== "undefined")
}]); }]);
console.log("RES", res);
this.isDirty = false; this.isDirty = false;
}, },
filterByText(item, queryText) { filterByText(item, queryText) {
if (!queryText || !item) return item; if (!queryText || !item) return item;
if (item.children) { if (item._children) {
const newItem = Object.assign({}, item); const newItem = Object.assign({}, item);
newItem.children = item.children.map( child => this.filterByText(child, queryText) ).filter(i => !!i) newItem._children = item._children.map( child => this.filterByText(child, queryText) ).filter(i => !!i)
if (newItem.children.length > 0) { if (newItem._children.length > 0) {
return newItem; return newItem;
} }
} }
if (item.name && item.name.toLowerCase().indexOf(queryText.toLowerCase()) > -1) { if (item._text && item._text.toLowerCase().indexOf(queryText.toLowerCase()) > -1) {
return item; return item;
} }
}, },
@@ -386,16 +398,17 @@ export default {
filterBySequence(item, sequences) { filterBySequence(item, sequences) {
if (!sequences || !sequences.length) return item; if (!sequences || !sequences.length) return item;
if (item._id) { if (item._kind == "sequence" && (sequences.includes(item.sequence) || sequences.includes(item))) {
if ( (item._id.length > 1 && sequences.includes(item._id[0])) || sequences.includes(item) ) { return item;
return item;
}
} }
if (item.children) { if (item._children) {
const newItem = Object.assign({}, item); const newItem = {...item};
newItem.children = item.children.map( child => this.filterBySequence(child, sequences) ).filter(i => !!i); newItem._children = item._children.map(child =>
if (newItem.children.length > 0) { this.filterBySequence(child, sequences)
).filter(i => !!i);
if (newItem._children.length) {
return newItem; return newItem;
} }
} }
@@ -403,71 +416,60 @@ export default {
toggleChildren (item, state) { toggleChildren (item, state) {
const open = typeof state == 'undefined' const open = typeof state == 'undefined'
? !this.open.includes(item.serial) ? !this.open.includes(item._serial)
: state; : state;
if (item.children) { if (item._children) {
item.children.forEach(child => this.toggleChildren(child, open)); item._children.forEach(child => this.toggleChildren(child, open));
} }
if (open) { if (open) {
if (!this.open.includes(item.serial)) { if (!this.open.includes(item._serial)) {
this.open.push(item.serial); this.open.push(item._serial);
} }
} else { } else {
const index = this.open.indexOf(item.serial); const index = this.open.indexOf(item._serial);
if (index > -1) { if (index > -1) {
this.open.splice(index, 1); this.open.splice(index, 1);
} }
} }
}, },
transform (item, testId) { transform (item, qcId) {
item.serial = ++this.itemIndex; item._serial = ++this.itemIndex;
if (item.id) { if (item.name && (item.check || item.children)) {
testId = item.id; // This is probably a test
} else { qcId ??= item.id;
item.id = testId;
} item._kind = "test";
if (item.check) { item._text = item.name;
switch (item.iterate) { item._children = [];
case "sequences": if (item.children) {
item.check = item.check.map(check => ({ // Child tests
_id: check._id, item._children = item.children.map(i => this.transform(i, qcId));
name: `Sequence ${check._id}: ${check.results}` }
}));
break; if (item.sequences) {
case "shots": // In theory an item could have both subtests and its own results
default: // so we don't do an if … else but two independent ifs.
const bySequence = {}; item._children = item._children.concat(item.sequences.map(i => this.transform(i, qcId)));
for (const check of item.check) { }
if (!bySequence[check._id[0]]) { } else if (item.sequence && item.line) {
bySequence[check._id[0]] = []; // This is probably a sequence
}
bySequence[check._id[0]].push({ item._kind = "sequence";
_id: check._id, item._text = `Sequence ${item.sequence}${item.meta?.qc && item.meta.qc[qcId] ? (": "+item.meta.qc[qcId]) : ""}`;
name: `Point ${check._id[1]}: ${check.results}`
}); if (item.shots && item.shots.length) {
} item._children = item.shots.map(i => this.transform(i, qcId));
item.check = Object.keys(bySequence).map(seq => ({ }
_id: seq, } else if (item.sequence && item.point) {
name: `Sequence: ${seq}`, // This is probably a shotpoint
children: bySequence[seq]
})); item._kind = "point";
} item._text = `Point ${item.point}: ${item.remarks}`
if (!("children" in item)) {
item.children = item.check;
delete item.check;
}
}
if (item.children) {
for (const child of item.children) {
this.transform(child, testId);
}
if (item.check) {
item.children = item.check.concatenate(item.children);
}
} }
return item; return item;
}, },
@@ -482,12 +484,12 @@ export default {
async getQCData () { async getQCData () {
const url = `/project/${this.$route.params.project}/info/qc`; const url = `/project/${this.$route.params.project}/qc/results`;
const res = await this.api([url]); const res = await this.api([url]);
if (res) { if (res) {
this.items = res.results.map(i => this.transform(i)) || []; this.items = res.map(i => this.transform(i)) || [];
this.updatedOn = res.updatedOn; this.updatedOn = res.updatedOn;
await this.getQCLabels(); await this.getQCLabels();
} else { } else {