From b3ed77964febb38a32201209be23284e4d881b7d Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Wed, 28 Jun 2023 10:22:38 +0200 Subject: [PATCH 01/13] Hotfix library select turning into links incorrectly --- app/imports/client/ui/library/LibraryListTile.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/imports/client/ui/library/LibraryListTile.vue b/app/imports/client/ui/library/LibraryListTile.vue index 10216f0c..c19e64d8 100644 --- a/app/imports/client/ui/library/LibraryListTile.vue +++ b/app/imports/client/ui/library/LibraryListTile.vue @@ -5,7 +5,7 @@ Date: Wed, 19 Jul 2023 18:49:18 +0200 Subject: [PATCH 02/13] Fixed searching by tag in slot fillers --- app/imports/server/publications/slotFillers.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/imports/server/publications/slotFillers.js b/app/imports/server/publications/slotFillers.js index fba54ca6..207ba336 100644 --- a/app/imports/server/publications/slotFillers.js +++ b/app/imports/server/publications/slotFillers.js @@ -41,16 +41,21 @@ Meteor.publish('slotFillers', function (slotId, searchTerm, isDummySlot) { sort: { name: 1 } }); - // Build a filter for nodes in those libraries that match the slot - let filter = getSlotFillFilter({ slot, libraryIds }); this.autorun(function () { + // Build a filter for nodes in those libraries that match the slot + let filter = getSlotFillFilter({ slot, libraryIds }); // Get the limit of the documents the user can fetch var limit = self.data('limit') || 50; check(limit, Number); let options = undefined; if (searchTerm) { - filter.name = { $regex: escapeRegex(searchTerm), '$options': 'i' }; + filter.$and.push({ + $or: [ + { name: { $regex: escapeRegex(searchTerm), '$options': 'i' } }, + { libraryTags: searchTerm } + ] + }); //filter.$text = { $search: searchTerm }; options = { // relevant documents have a higher score. From 25e2523d5117d31caa71749ed709dca70583f332 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Wed, 19 Jul 2023 18:57:06 +0200 Subject: [PATCH 03/13] Fixed resources in folder increment button loading forever --- .../folderGroupComponents/AttributeGroupComponent.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/imports/client/ui/properties/components/folders/folderGroupComponents/AttributeGroupComponent.vue b/app/imports/client/ui/properties/components/folders/folderGroupComponents/AttributeGroupComponent.vue index 2b485e3b..72020377 100644 --- a/app/imports/client/ui/properties/components/folders/folderGroupComponents/AttributeGroupComponent.vue +++ b/app/imports/client/ui/properties/components/folders/folderGroupComponents/AttributeGroupComponent.vue @@ -30,7 +30,7 @@ v-else-if="model.attributeType === 'resource'" :model="model" @click="$emit('click')" - @change="({ type, value }) => damageProperty({type, value: -value})" + @change="({ type, value, ack }) => damageProperty({type, value: -value, ack})" @mouseover="hover = true" @mouseleave="hover = false" /> @@ -96,6 +96,9 @@ export default { _id: this.model._id, operation: change.type, value: change.value + }, e => { + console.log(change); + change.ack?.(e); }); }, log({_id}) { From 2b1a6de1e57737f919a9ed4f013255a464c954ce Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Wed, 19 Jul 2023 19:03:36 +0200 Subject: [PATCH 04/13] Relaxed rate limiting on duplicating library props --- app/imports/api/library/methods/duplicateLibraryNode.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/imports/api/library/methods/duplicateLibraryNode.js b/app/imports/api/library/methods/duplicateLibraryNode.js index 83f20106..43aa0a8a 100644 --- a/app/imports/api/library/methods/duplicateLibraryNode.js +++ b/app/imports/api/library/methods/duplicateLibraryNode.js @@ -28,8 +28,8 @@ const duplicateLibraryNode = new ValidatedMethod({ }).validator(), mixins: [RateLimiterMixin], rateLimit: { - numRequests: 1, - timeInterval: 5000, + numRequests: 4, + timeInterval: 6000, }, run({ _id }) { let libraryNode = LibraryNodes.findOne(_id); From 4133a0f78c0e8b2e5c6380bf920fe07991dbc041 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Wed, 19 Jul 2023 19:40:59 +0200 Subject: [PATCH 05/13] Fixed proficiency bonus not applying in actions --- .../applyEffectsToCalculationParseNode.js | 30 ++++++++++++++++--- .../shared/recalculateCalculation.js | 2 +- .../utility/evaluateCalculation.js | 10 +++---- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/app/imports/api/engine/actions/applyPropertyByType/shared/applyEffectsToCalculationParseNode.js b/app/imports/api/engine/actions/applyPropertyByType/shared/applyEffectsToCalculationParseNode.js index 0ada4ea1..6ee0a765 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/shared/applyEffectsToCalculationParseNode.js +++ b/app/imports/api/engine/actions/applyPropertyByType/shared/applyEffectsToCalculationParseNode.js @@ -2,9 +2,8 @@ import operator from '/imports/parser/parseTree/operator.js'; import { parse } from '/imports/parser/parser.js'; import logErrors from './logErrors.js'; -export default function applyEffectsToCalculationParseNode(calcObj, actionContext){ - if (!calcObj.effects) return; - calcObj.effects.forEach(effect => { +export default function applyEffectsToCalculationParseNode(calcObj, actionContext) { + calcObj.effects?.forEach(effect => { if (effect.operation !== 'add') return; if (!effect.amount) return; if (effect.amount.value === null) return; @@ -17,8 +16,31 @@ export default function applyEffectsToCalculationParseNode(calcObj, actionContex operator: '+', fn: 'add' }); - } catch (e){ + } catch (e) { logErrors([e], actionContext) } }); + // Add the highest proficiency as well + let highestProficiency; + calcObj.proficiencies?.forEach(proficiency => { + if ( + proficiency.value > highestProficiency + || (highestProficiency === undefined && Number.isFinite(proficiency.value)) + ) { + highestProficiency = proficiency.value; + } + }); + if (highestProficiency) { + try { + let profParseNode = parse(highestProficiency.toString()); + calcObj.parseNode = operator.create({ + left: calcObj.parseNode, + right: profParseNode, + operator: '+', + fn: 'add' + }); + } catch (e) { + logErrors([e], actionContext) + } + } } diff --git a/app/imports/api/engine/actions/applyPropertyByType/shared/recalculateCalculation.js b/app/imports/api/engine/actions/applyPropertyByType/shared/recalculateCalculation.js index 2f484567..16f2cfe3 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/shared/recalculateCalculation.js +++ b/app/imports/api/engine/actions/applyPropertyByType/shared/recalculateCalculation.js @@ -2,7 +2,7 @@ import evaluateCalculation from '/imports/api/engine/computation/utility/evaluat import applyEffectsToCalculationParseNode from '/imports/api/engine/actions/applyPropertyByType/shared/applyEffectsToCalculationParseNode.js'; import logErrors from './logErrors.js'; -export default function recalculateCalculation(calc, actionContext, context){ +export default function recalculateCalculation(calc, actionContext, context) { if (!calc?.parseNode) return; calc._parseLevel = 'reduce'; applyEffectsToCalculationParseNode(calc, actionContext); diff --git a/app/imports/api/engine/computation/utility/evaluateCalculation.js b/app/imports/api/engine/computation/utility/evaluateCalculation.js index 580cafde..6d5f1f82 100644 --- a/app/imports/api/engine/computation/utility/evaluateCalculation.js +++ b/app/imports/api/engine/computation/utility/evaluateCalculation.js @@ -1,14 +1,14 @@ import resolve, { toString } from '/imports/parser/resolve.js'; -export default function evaluateCalculation(calculation, scope, givenContext){ +export default function evaluateCalculation(calculation, scope, givenContext) { const parseNode = calculation.parseNode; const fn = calculation._parseLevel; - const calculationScope = {...calculation._localScope, ...scope}; - const {result: resultNode, context} = resolve(fn, parseNode, calculationScope, givenContext); + const calculationScope = { ...calculation._localScope, ...scope }; + const { result: resultNode, context } = resolve(fn, parseNode, calculationScope, givenContext); calculation.errors = context.errors; - if (resultNode?.parseType === 'constant'){ + if (resultNode?.parseType === 'constant') { calculation.value = resultNode.value; - } else if (resultNode?.parseType === 'error'){ + } else if (resultNode?.parseType === 'error') { calculation.value = null; } else { calculation.value = toString(resultNode); From 30fabce7f16805221db8223a6cfbb95b0ceae6c2 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Thu, 20 Jul 2023 11:13:57 +0200 Subject: [PATCH 06/13] Removed variables object from creature docs --- app/imports/api/creature/creatures/Creatures.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/imports/api/creature/creatures/Creatures.js b/app/imports/api/creature/creatures/Creatures.js index b94fe7e4..bd05254e 100644 --- a/app/imports/api/creature/creatures/Creatures.js +++ b/app/imports/api/creature/creatures/Creatures.js @@ -151,11 +151,6 @@ let CreatureSchema = new SimpleSchema({ blackbox: true, defaultValue: {} }, - variables: { - type: Object, - blackbox: true, - defaultValue: {} - }, computeErrors: { type: Array, optional: true, From b0afc86ad40f84ed3ae85a1c7074065f024d9634 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Fri, 21 Jul 2023 16:12:50 +0200 Subject: [PATCH 07/13] "fixed" column layout again As yet untested on Safari --- .../client/ui/components/ColumnLayout.vue | 29 +++++-------------- .../printedCharacterSheet/PrintedStats.vue | 1 - 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/app/imports/client/ui/components/ColumnLayout.vue b/app/imports/client/ui/components/ColumnLayout.vue index 2d5341a5..69306c67 100644 --- a/app/imports/client/ui/components/ColumnLayout.vue +++ b/app/imports/client/ui/components/ColumnLayout.vue @@ -16,42 +16,27 @@ export default { wideColumns: Boolean, }, }; - -/* -Removed to improve chrome layout performance, put it back if there are rendering errors -.column-layout>span>div { - display: table; - table-layout: fixed; -} -*/ diff --git a/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedStats.vue b/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedStats.vue index 039209e2..f6e2ecf3 100644 --- a/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedStats.vue +++ b/app/imports/client/ui/creature/character/printedCharacterSheet/PrintedStats.vue @@ -596,7 +596,6 @@ export default { margin-top: 4px; margin-left: -30px; padding-left: 34px; - z-index: -1; } .number-label .number { From 0e5bf399588a439571645aaaff4f362c612a850f Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Fri, 21 Jul 2023 16:18:50 +0200 Subject: [PATCH 08/13] Bumped version --- app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index 463be480..bf7ce27c 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "dicecloud", - "version": "2.0.53", + "version": "2.0.54", "description": "Unofficial Online Realtime D&D 5e App", "license": "GPL-3.0", "repository": { From 7ea972d4763102fc95c95df7428822743c3fefcf Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 1 Aug 2023 11:28:17 +0200 Subject: [PATCH 09/13] Fixed level up backfill selecting too many props Fixed out of order --- .../methods/insertPropertyFromLibraryNode.js | 2 + .../ui/creature/slots/LevelUpDialog.vue | 63 ++++++++++++------- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js index deb55bc7..79dcc70c 100644 --- a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js +++ b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js @@ -60,6 +60,8 @@ const insertPropertyFromLibraryNode = new ValidatedMethod({ nodeIds.forEach(nodeId => { // TODO: Check library view permission for each node before starting node = insertPropertyFromNode(nodeId, ancestors, order); + // Increment order, slightly, to keep the nodes inserted in the given id order + order += 0.001; }); // get one of the root inserted docs diff --git a/app/imports/client/ui/creature/slots/LevelUpDialog.vue b/app/imports/client/ui/creature/slots/LevelUpDialog.vue index aefd4405..dcf4ce08 100644 --- a/app/imports/client/ui/creature/slots/LevelUpDialog.vue +++ b/app/imports/client/ui/creature/slots/LevelUpDialog.vue @@ -81,7 +81,7 @@ v-if="libraryNode._disabledBySlotFillerCondition" class="error--text text-no-wrap text-truncate" > - {{ libraryNode.slotFillerCondition }} + {{ libraryNode._conditionError }}
@@ -192,7 +192,7 @@ import getSlotFillFilter from '/imports/api/creature/creatureProperties/methods/ import Libraries from '/imports/api/library/Libraries.js'; import LibraryNodeExpansionContent from '/imports/client/ui/library/LibraryNodeExpansionContent.vue'; import PropertyTags from '/imports/client/ui/properties/viewers/shared/PropertyTags.vue'; -import { clone, difference } from 'lodash'; +import { clone, difference, isEqual } from 'lodash'; export default { components: { @@ -250,25 +250,39 @@ export default { }, watch: { selectedNodeIds(selectedIds, oldSelectedIds) { - // Skip if we didn't increase the length by adding a new Id - if (oldSelectedIds.length >= selectedIds.length) return; - // Find out which library node was added - const addedId = difference(selectedIds, oldSelectedIds)[0]; - if (!addedId) return; - const addedNode = LibraryNodes.findOne(addedId); - if (!addedNode) return; - // Tick any unchecked nodes of a lower level, but only one per level - const backFilledLevels = new Set(); - this.libraryNodes.forEach(node => { - if ( - !selectedIds.includes(node._id) - && node.level < addedNode.level - && !backFilledLevels.has(node.level) - ) { - selectedIds.push(node._id); - } - }); - this.selectedNodeIds = selectedIds; + // Skip if we increased the length by adding a new Id, see if we need to backfill levels + if (oldSelectedIds.length < selectedIds.length) { + // Find out which library node was added + const addedId = difference(selectedIds, oldSelectedIds)[0]; + if (!addedId) return; + const addedNode = LibraryNodes.findOne(addedId); + if (!addedNode) return; + // Tick any unchecked nodes of a lower level, but only one per level + const backFilledLevels = new Set(); + this.libraryNodes.forEach(node => { + if ( + !selectedIds.includes(node._id) + && node.level < addedNode.level + && !backFilledLevels.has(node.level) + && !this.isDisabled(node) + ) { + selectedIds.push(node._id); + backFilledLevels.add(node.level) + } + }); + this.selectedNodeIds = sortedIds; + } + + // Refetch the library nodes to sort them correctly + const sortedIds = LibraryNodes.find({ + _id: { $in: selectedIds } + }, { + sort: { level: 1, name: 1, order: 1 } + }).map(node => node._id); + // Only update if the order changed + if (!isEqual(this.selectedNodeIds, sortedIds)) { + this.selectedNodeIds = sortedIds; + } } }, methods: { @@ -377,7 +391,7 @@ export default { if (!this.libraryNodeFilter) return []; if (!this.$subReady.classFillers) return []; let nodes = LibraryNodes.find(this.libraryNodeFilter, { - sort: { name: 1, order: 1 } + sort: { level: 1, name: 1, order: 1 } }).fetch(); let disabledNodeCount = 0; // Mark classFillers whose condition isn't met or are too big to fit @@ -390,18 +404,19 @@ export default { if (resultNode?.parseType === 'constant') { if (!resultNode.value) { node._disabledBySlotFillerCondition = true; + node._conditionError = node.slotFillerConditionNote || node.slotFillerCondition; disabledNodeCount += 1; } } else { node._disabledBySlotFillerCondition = true; - node._conditionError = toString(resultNode); + node._conditionError = node.slotFillerConditionNote || toString(resultNode); disabledNodeCount += 1; } } catch (e) { console.warn(e); let error = prettifyParseError(e); node._disabledBySlotFillerCondition = true; - node._conditionError = error; + node._conditionError = 'Condition error: ' + error; disabledNodeCount += 1; } } From a262d773c0bc942f4d01ddee119475aca70ffa16 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 1 Aug 2023 11:28:39 +0200 Subject: [PATCH 10/13] Reduced snackbar timeout to 15s --- app/imports/client/ui/components/snackbars/SnackbarQueue.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/imports/client/ui/components/snackbars/SnackbarQueue.vue b/app/imports/client/ui/components/snackbars/SnackbarQueue.vue index a17e085f..c746bbb4 100644 --- a/app/imports/client/ui/components/snackbars/SnackbarQueue.vue +++ b/app/imports/client/ui/components/snackbars/SnackbarQueue.vue @@ -52,7 +52,7 @@ export default { props: { timeout: { type: Number, - default: 6000000, + default: 15000, }, pause: { type: Number, From 31c2580a9bef031ca45e9540bcc35186640e270d Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 1 Aug 2023 11:30:53 +0200 Subject: [PATCH 11/13] Bumped version --- app/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/package.json b/app/package.json index bf7ce27c..37857bfc 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "dicecloud", - "version": "2.0.54", + "version": "2.0.55", "description": "Unofficial Online Realtime D&D 5e App", "license": "GPL-3.0", "repository": { From d9e06797349f8d54755fec269cbde28a9897ef62 Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Tue, 1 Aug 2023 12:09:21 +0200 Subject: [PATCH 12/13] Hotfix order increment breaking property insert --- .../creatureProperties/methods/insertPropertyFromLibraryNode.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js index 79dcc70c..deb55bc7 100644 --- a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js +++ b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js @@ -60,8 +60,6 @@ const insertPropertyFromLibraryNode = new ValidatedMethod({ nodeIds.forEach(nodeId => { // TODO: Check library view permission for each node before starting node = insertPropertyFromNode(nodeId, ancestors, order); - // Increment order, slightly, to keep the nodes inserted in the given id order - order += 0.001; }); // get one of the root inserted docs From e89b4946d57e75a17f97354049a4117811b9099b Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Wed, 2 Aug 2023 11:27:17 +0200 Subject: [PATCH 13/13] 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 --- .../methods/getSlotFillFilter.js | 28 ++++--- .../methods/insertPropertyFromLibraryNode.js | 2 + .../ui/creature/slots/LevelUpDialog.vue | 60 +++++++++++---- .../ui/creature/slots/SlotFillDialog.vue | 73 ++++++++++++------- .../library/LibraryNodeExpansionContent.vue | 15 ++-- 5 files changed, 123 insertions(+), 55 deletions(-) diff --git a/app/imports/api/creature/creatureProperties/methods/getSlotFillFilter.js b/app/imports/api/creature/creatureProperties/methods/getSlotFillFilter.js index 9558ff55..f3d82f75 100644 --- a/app/imports/api/creature/creatureProperties/methods/getSlotFillFilter.js +++ b/app/imports/api/creature/creatureProperties/methods/getSlotFillFilter.js @@ -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 = []; diff --git a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js index deb55bc7..469cd0fc 100644 --- a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js +++ b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js @@ -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); diff --git a/app/imports/client/ui/creature/slots/LevelUpDialog.vue b/app/imports/client/ui/creature/slots/LevelUpDialog.vue index dcf4ce08..7b49f6f7 100644 --- a/app/imports/client/ui/creature/slots/LevelUpDialog.vue +++ b/app/imports/client/ui/creature/slots/LevelUpDialog.vue @@ -49,7 +49,7 @@ :key="libraryNode._id" :model="libraryNode" :data-id="libraryNode._id" - :class="{disabled: isDisabled(libraryNode)}" + :class="{disabled: isDisabled(libraryNode) || libraryNode._disabledBySlotFillerCondition}" > - + @@ -120,11 +121,12 @@ column align-center justify-center - class="ma-3" + class="ma-3 mt-8" > 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; }, diff --git a/app/imports/client/ui/creature/slots/SlotFillDialog.vue b/app/imports/client/ui/creature/slots/SlotFillDialog.vue index 75af7420..197aedd0 100644 --- a/app/imports/client/ui/creature/slots/SlotFillDialog.vue +++ b/app/imports/client/ui/creature/slots/SlotFillDialog.vue @@ -64,7 +64,7 @@ :key="libraryNode._id" :model="libraryNode" :data-id="libraryNode._id" - :class="{disabled: isDisabled(libraryNode)}" + :class="{disabled: isDisabled(libraryNode) || libraryNode._disabledBySlotFillerCondition}" > - + @@ -136,16 +137,38 @@ column align-center justify-center - class="ma-3" + class="ma-3 mt-8" > Load More + - +