Improvements to level up and slot fill
- class level refs work with level up - Improve UI - Fixed level up backfill repeating levels when selecting higher levels multiple times - Allowed user to ignore slot fill condition - Auto load more if many disabled fillers
This commit is contained in:
@@ -18,23 +18,31 @@ export default function getSlotFillFilter({ slot, libraryIds }) {
|
||||
}]
|
||||
});
|
||||
} else if (slot.type === 'class') {
|
||||
filter.$and.push({
|
||||
$or: [{
|
||||
type: 'classLevel',
|
||||
}, {
|
||||
slotFillerType: 'classLevel',
|
||||
}]
|
||||
});
|
||||
const classLevelFilter = {
|
||||
type: 'classLevel',
|
||||
};
|
||||
const slotFillerFilter = {
|
||||
slotFillerType: 'classLevel',
|
||||
};
|
||||
|
||||
// Match variable name or tags
|
||||
if (slot.variableName) {
|
||||
filter.variableName = slot.variableName;
|
||||
classLevelFilter.variableName = slot.variableName;
|
||||
slotFillerFilter.libraryTags = slot.variableName;
|
||||
}
|
||||
|
||||
// Only search for levels the class needs
|
||||
if (slot.missingLevels && slot.missingLevels.length) {
|
||||
filter.level = { $in: slot.missingLevels };
|
||||
classLevelFilter.level = { $in: slot.missingLevels };
|
||||
slotFillerFilter['cache.node.level'] = { $in: slot.missingLevels };
|
||||
} else {
|
||||
filter.level = { $gt: slot.level || 0 };
|
||||
classLevelFilter.level = { $gt: slot.level || 0 };
|
||||
slotFillerFilter['cache.node.level'] = { $gt: slot.level || 0 };
|
||||
}
|
||||
|
||||
filter.$and.push({
|
||||
$or: [classLevelFilter, slotFillerFilter]
|
||||
});
|
||||
}
|
||||
let tagsOr = [];
|
||||
let tagsNin = [];
|
||||
|
||||
@@ -105,6 +105,8 @@ function insertPropertyFromNode(nodeId, ancestors, order) {
|
||||
|
||||
// Convert all references into actual nodes
|
||||
nodes = reifyNodeReferences(nodes);
|
||||
// Refetch the root node, it might have been reified
|
||||
node = nodes[0] || node;
|
||||
|
||||
// set libraryNodeIds
|
||||
storeLibraryNodeReferences(nodes);
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
:key="libraryNode._id"
|
||||
:model="libraryNode"
|
||||
:data-id="libraryNode._id"
|
||||
:class="{disabled: isDisabled(libraryNode)}"
|
||||
:class="{disabled: isDisabled(libraryNode) || libraryNode._disabledBySlotFillerCondition}"
|
||||
>
|
||||
<v-expansion-panel-header>
|
||||
<template #default="{ open }">
|
||||
@@ -69,6 +69,7 @@
|
||||
v-model="selectedNodeIds"
|
||||
class="my-0 py-0"
|
||||
hide-details
|
||||
:color="libraryNode._disabledBySlotFillerCondition ? 'error' : ''"
|
||||
:disabled="isDisabled(libraryNode)"
|
||||
:value="libraryNode._id"
|
||||
@click.stop
|
||||
@@ -110,7 +111,7 @@
|
||||
</template>
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<library-node-expansion-content :model="libraryNode" />
|
||||
<library-node-expansion-content :id="libraryNode._id" />
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</template>
|
||||
@@ -120,11 +121,12 @@
|
||||
column
|
||||
align-center
|
||||
justify-center
|
||||
class="ma-3"
|
||||
class="ma-3 mt-8"
|
||||
>
|
||||
<v-btn
|
||||
:loading="!$subReady.classFillers"
|
||||
color="accent"
|
||||
outlined
|
||||
@click="loadMore"
|
||||
>
|
||||
Load More
|
||||
@@ -247,6 +249,13 @@ export default {
|
||||
});
|
||||
return { or, not };
|
||||
},
|
||||
filledLevels() {
|
||||
return LibraryNodes.find({
|
||||
_id: { $in: this.selectedNodeIds }
|
||||
}).map(
|
||||
node => node.level || node.cache?.node?.level || 0
|
||||
).sort((a, b) => a - b);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selectedNodeIds(selectedIds, oldSelectedIds) {
|
||||
@@ -257,14 +266,19 @@ export default {
|
||||
if (!addedId) return;
|
||||
const addedNode = LibraryNodes.findOne(addedId);
|
||||
if (!addedNode) return;
|
||||
// Tick any unchecked nodes of a lower level, but only one per level
|
||||
// Check which levels are already backfilled
|
||||
const backFilledLevels = new Set();
|
||||
const sortedIds = LibraryNodes.find({
|
||||
_id: { $in: selectedIds }
|
||||
}).map(node => backFilledLevels.add(node.level || node.cache?.node?.level || 0));
|
||||
// Tick any unchecked nodes of a lower level, but only one per level
|
||||
this.libraryNodes.forEach(node => {
|
||||
if (
|
||||
!selectedIds.includes(node._id)
|
||||
&& node.level < addedNode.level
|
||||
&& (node.level < addedNode.level)
|
||||
&& !backFilledLevels.has(node.level)
|
||||
&& !this.isDisabled(node)
|
||||
&& !node._disabledBySlotFillerCondition
|
||||
) {
|
||||
selectedIds.push(node._id);
|
||||
backFilledLevels.add(node.level)
|
||||
@@ -278,12 +292,26 @@ export default {
|
||||
_id: { $in: selectedIds }
|
||||
}, {
|
||||
sort: { level: 1, name: 1, order: 1 }
|
||||
}).map(node => node._id);
|
||||
})
|
||||
.fetch()
|
||||
.sort((a, b) => (a.level || a.cache?.node?.level || 0) - (b.level || b.cache?.node?.level || 0))
|
||||
.map(node => node._id);
|
||||
// Only update if the order changed
|
||||
if (!isEqual(this.selectedNodeIds, sortedIds)) {
|
||||
this.selectedNodeIds = sortedIds;
|
||||
}
|
||||
}
|
||||
},
|
||||
activeCount(val) {
|
||||
// Still loading fillers
|
||||
if (!this._subs['classFillers'].ready()) return;
|
||||
// Can load more, and not showing enough active choices, so load more
|
||||
if (
|
||||
this.currentLimit < this.countAll
|
||||
&& val < 20
|
||||
) {
|
||||
this.loadMore();
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
loadMore() {
|
||||
@@ -300,12 +328,10 @@ export default {
|
||||
});
|
||||
},
|
||||
isDisabled(node) {
|
||||
return node._disabledBySlotFillerCondition ||
|
||||
node._disabledByAlreadyAdded ||
|
||||
(
|
||||
node._disabledByQuantityFilled &&
|
||||
!this.selectedNodeIds.includes(node._id)
|
||||
)
|
||||
const selected = this.selectedNodeIds.includes(node._id);
|
||||
return node._disabledByAlreadyAdded
|
||||
|| ( node._disabledByQuantityFilled && !selected )
|
||||
|| ( this.filledLevels.includes(node.level || node.cache?.node?.level || 0) && !selected )
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
@@ -338,6 +364,10 @@ export default {
|
||||
countAll() {
|
||||
return this._subs['classFillers'].data('countAll');
|
||||
},
|
||||
activeCount() {
|
||||
if (!this.libraryNodes) return;
|
||||
return this.libraryNodes.length - (this.disabledNodeCount || 0);
|
||||
},
|
||||
alreadyAdded() {
|
||||
let added = new Set();
|
||||
if (!this.model.unique) return added;
|
||||
@@ -397,6 +427,9 @@ export default {
|
||||
// Mark classFillers whose condition isn't met or are too big to fit
|
||||
// the quantity to fill
|
||||
nodes.forEach(node => {
|
||||
if (node.cache?.node) {
|
||||
node.level = node.cache.node.level;
|
||||
}
|
||||
if (node.slotFillerCondition) {
|
||||
try {
|
||||
let parseNode = parse(node.slotFillerCondition);
|
||||
@@ -430,6 +463,7 @@ export default {
|
||||
node._disabledByAlreadyAdded = true;
|
||||
}
|
||||
});
|
||||
nodes.sort((a, b) => a.level - b.level);
|
||||
this.disabledNodeCount = disabledNodeCount;
|
||||
return nodes;
|
||||
},
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
:key="libraryNode._id"
|
||||
:model="libraryNode"
|
||||
:data-id="libraryNode._id"
|
||||
:class="{disabled: isDisabled(libraryNode)}"
|
||||
:class="{disabled: isDisabled(libraryNode) || libraryNode._disabledBySlotFillerCondition}"
|
||||
>
|
||||
<v-expansion-panel-header>
|
||||
<template #default="{ open }">
|
||||
@@ -84,6 +84,7 @@
|
||||
v-model="selectedNodeIds"
|
||||
class="my-0 py-0"
|
||||
hide-details
|
||||
:color="libraryNode._disabledBySlotFillerCondition ? 'error' : ''"
|
||||
:disabled="isDisabled(libraryNode)"
|
||||
:value="libraryNode._id"
|
||||
@click.stop
|
||||
@@ -125,7 +126,7 @@
|
||||
</template>
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<library-node-expansion-content :model="libraryNode" />
|
||||
<library-node-expansion-content :id="libraryNode._id" />
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</template>
|
||||
@@ -136,16 +137,38 @@
|
||||
column
|
||||
align-center
|
||||
justify-center
|
||||
class="ma-3"
|
||||
class="ma-3 mt-8"
|
||||
>
|
||||
<v-btn
|
||||
:loading="!$subReady.slotFillers"
|
||||
color="accent"
|
||||
outlined
|
||||
@click="loadMore"
|
||||
>
|
||||
Load More
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
<template v-if="!showDisabled && disabledNodeCount">
|
||||
<v-layout
|
||||
column
|
||||
align-center
|
||||
justify-center
|
||||
class="ma-3 mt-8"
|
||||
>
|
||||
<div>
|
||||
Requirements of {{ disabledNodeCount }} properties were not met
|
||||
</div>
|
||||
<v-btn
|
||||
class="mt-2"
|
||||
elevation="0"
|
||||
color="accent"
|
||||
outlined
|
||||
@click="showDisabled = true"
|
||||
>
|
||||
Show All
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
</template>
|
||||
<v-layout
|
||||
align-center
|
||||
justify-center
|
||||
@@ -162,6 +185,7 @@
|
||||
<v-btn
|
||||
v-if="!dummySlot"
|
||||
text
|
||||
small
|
||||
data-id="library-browser-button"
|
||||
:disabled="!model"
|
||||
@click="openLibraryBrowser"
|
||||
@@ -171,7 +195,7 @@
|
||||
<v-btn
|
||||
v-if="!dummySlot"
|
||||
text
|
||||
color="accent"
|
||||
small
|
||||
:disabled="!model"
|
||||
data-id="custom-button"
|
||||
@click="insertCustomFiller"
|
||||
@@ -179,26 +203,7 @@
|
||||
Create custom filler
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
<template v-if="!showDisabled && disabledNodeCount">
|
||||
<v-layout
|
||||
column
|
||||
align-center
|
||||
justify-center
|
||||
class="ma-3"
|
||||
>
|
||||
<div>
|
||||
Requirements of {{ disabledNodeCount }} properties were not met
|
||||
</div>
|
||||
<v-btn
|
||||
class="mt-2"
|
||||
elevation="0"
|
||||
color="accent"
|
||||
@click="showDisabled = true"
|
||||
>
|
||||
Show All
|
||||
</v-btn>
|
||||
</v-layout>
|
||||
</template>
|
||||
|
||||
<template slot="actions">
|
||||
<v-btn
|
||||
text
|
||||
@@ -306,6 +311,19 @@ export default {
|
||||
return propName;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
activeCount(val) {
|
||||
// Still loading fillers
|
||||
if (!this._subs['slotFillers'].ready()) return;
|
||||
// Can load more, and not showing enough active choices, so load more
|
||||
if (
|
||||
this.currentLimit < this.countAll
|
||||
&& val < 25
|
||||
) {
|
||||
this.loadMore();
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
loadMore() {
|
||||
if (this.currentLimit >= this.countAll) return;
|
||||
@@ -327,8 +345,7 @@ export default {
|
||||
});
|
||||
},
|
||||
isDisabled(node) {
|
||||
return node._disabledBySlotFillerCondition ||
|
||||
node._disabledByAlreadyAdded ||
|
||||
return node._disabledByAlreadyAdded ||
|
||||
(
|
||||
node._disabledByQuantityFilled &&
|
||||
!this.selectedNodeIds.includes(node._id)
|
||||
@@ -408,6 +425,10 @@ export default {
|
||||
countAll() {
|
||||
return this._subs['slotFillers'].data('countAll');
|
||||
},
|
||||
activeCount() {
|
||||
if (!this.libraryNodes) return;
|
||||
return this.libraryNodes.length - (this.disabledNodeCount || 0);
|
||||
},
|
||||
libraryNodeFilter() {
|
||||
const filterString = this._subs['slotFillers'].data('libraryNodeFilter');
|
||||
if (!filterString) return;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<div :key="id">
|
||||
<v-progress-linear
|
||||
v-if="!subsReady"
|
||||
indeterminate
|
||||
@@ -37,8 +37,8 @@ export default {
|
||||
...propertyViewerIndex,
|
||||
},
|
||||
props: {
|
||||
model: {
|
||||
type: Object,
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
@@ -61,16 +61,19 @@ export default {
|
||||
meteor: {
|
||||
$subscribe: {
|
||||
libraryNode(){
|
||||
return [this.model._id];
|
||||
return [this.id];
|
||||
},
|
||||
descendantLibraryNodes(){
|
||||
return [this.model._id];
|
||||
return [this.id];
|
||||
},
|
||||
},
|
||||
model() {
|
||||
return LibraryNodes.findOne(this.id);
|
||||
},
|
||||
propertyChildren(){
|
||||
return nodesToTree({
|
||||
collection: LibraryNodes,
|
||||
ancestorId: this.model._id
|
||||
ancestorId: this.id
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user