From 4921a34dfe60fd33c1bf63c3b502900fb6de7eb5 Mon Sep 17 00:00:00 2001 From: Thaum Rystra <9525416+ThaumRystra@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:29:50 +0200 Subject: [PATCH] Fixed adding creatures from libraries -> tabletops --- .../addCreaturesFromLibraryToTabletop.ts | 14 +- .../ui/tabletop/CreatureFromLibraryDialog.vue | 89 +---------- .../client/ui/tabletop/TabletopComponent.vue | 5 - .../server/publications/creatureTemplates.js | 140 ++++++++++++++++++ app/imports/server/publications/index.js | 1 + 5 files changed, 158 insertions(+), 91 deletions(-) create mode 100644 app/imports/server/publications/creatureTemplates.js diff --git a/app/imports/api/tabletop/methods/addCreaturesFromLibraryToTabletop.ts b/app/imports/api/tabletop/methods/addCreaturesFromLibraryToTabletop.ts index 47e283c8..a92d5645 100644 --- a/app/imports/api/tabletop/methods/addCreaturesFromLibraryToTabletop.ts +++ b/app/imports/api/tabletop/methods/addCreaturesFromLibraryToTabletop.ts @@ -8,6 +8,7 @@ import LibraryNodes from '/imports/api/library/LibraryNodes'; import { getFilter, renewDocIds } from '/imports/api/parenting/parentingFunctions'; import { reifyNodeReferences, storeLibraryNodeReferences } from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode'; import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; +import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables'; const addCreaturesFromLibraryToTabletop = new ValidatedMethod({ @@ -58,14 +59,25 @@ const addCreaturesFromLibraryToTabletop = new ValidatedMethod({ } } + // Insert the creature const creatureId = Creatures.insert({ ...creatureNode, + _id: Random.id(), type: 'monster', tabletopId, owner: this.userId, + readers: [], writers: [this.userId], + public: false, dirty: true, + settings: {}, }); + + // Insert the creature variables + CreatureVariables.insert({ + _creatureId: creatureId, + }); + insertSubProperties(creatureNode, creatureId); } }, @@ -98,7 +110,7 @@ function insertSubProperties(node, creatureId: string) { // Insert the creature properties // @ts-expect-error Batch insert not defined - CreatureProperties.batchInsert(nodes); + if (nodes.length) CreatureProperties.batchInsert(nodes); return node; } diff --git a/app/imports/client/ui/tabletop/CreatureFromLibraryDialog.vue b/app/imports/client/ui/tabletop/CreatureFromLibraryDialog.vue index 3d56ce3f..cf16a4c5 100644 --- a/app/imports/client/ui/tabletop/CreatureFromLibraryDialog.vue +++ b/app/imports/client/ui/tabletop/CreatureFromLibraryDialog.vue @@ -80,7 +80,7 @@
- {{ libraryNames[libraryNode.ancestors[0].id ] }} + {{ libraryNames[libraryNode.root.id ] }}
{ - if (extras.tags?.length) { - if (extras.operation === 'OR') { - or.push(extras.tags); - } else if (extras.operation === 'NOT') { - not.push(extras.tags); - } - } - }); - return { or, not }; - }, - slotPropertyTypeName() { - if (!this.model) return; - if (!this.model.slotType) return 'Property'; - let propName = getPropertyName(this.model.slotType); - return propName; - }, - }, watch: { activeCount(val) { // Still loading fillers @@ -291,7 +266,8 @@ export default { ) }, insertCustomFiller() { - if (!this.model) return; + //TODO + return; const prop = getDefaultSlotFiller(this.model); const parentRef = { id: this.slotId, collection: 'creatureProperties' }; const order = this.model.order + 0.5; @@ -337,30 +313,12 @@ export default { meteor: { $subscribe: { 'creatureTemplates'() { - return [this.slotId || this.dummySlot?._id, this.searchValue || undefined, !!this.dummySlot] - }, - 'selectedFillers'() { - return [this.slotId || this.dummySlot?._id, this.selectedNodeIds, !!this.dummySlot] + return [this.searchValue || undefined] }, }, searchLoading() { return !!this.searchValue && !this.$subReady.creatureTemplates; }, - model() { - if (this.slotId) { - return CreatureProperties.findOne(this.slotId); - } else if (this.dummySlot) { - let model = clone(this.dummySlot) - if (!model.quantityExpected) model.quantityExpected = {}; - model.quantityExpected.value = +model.quantityExpected.calculation; - model.spaceLeft = model.quantityExpected.value; - return model; - } - }, - variables() { - if (!this.creatureId) return {}; - return CreatureVariables.findOne({ _creatureId: this.creatureId }) || {}; - }, currentLimit() { return this._subs['creatureTemplates'].data('limit') || 50; }, @@ -376,45 +334,6 @@ export default { if (!filterString) return; return EJSON.parse(filterString); }, - alreadyAdded() { - let added = new Set(); - if (!this.model.unique) return added; - let ancestorId; - if (this.model.unique === 'uniqueInSlot') { - ancestorId = this.model._id; - } else if (this.model.unique === 'uniqueInCreature') { - ancestorId = this.creatureId; - } - CreatureProperties.find({ - 'ancestors.id': ancestorId, - libraryNodeId: { $exists: true }, - removed: { $ne: true }, - }, { - fields: { libraryNodeId: 1 }, - }).forEach(prop => { - added.add(prop.libraryNodeId); - }); - return added; - }, - totalQuantitySelected() { - let quantitySelected = 0; - LibraryNodes.find({ - _id: { $in: this.selectedNodeIds } - }, { - fields: { slotQuantityFilled: 1 }, - }).forEach(node => { - if (Number.isFinite(node.slotQuantityFilled)) { - quantitySelected += node.slotQuantityFilled; - } else { - quantitySelected += 1; - } - }); - return quantitySelected; - }, - spaceLeft() { - if (!this.model.quantityExpected || this.model.quantityExpected.value === 0) return undefined; - return this.model.spaceLeft - this.totalQuantitySelected; - }, libraryNames() { let names = {}; Libraries.find().forEach(lib => names[lib._id] = lib.name) diff --git a/app/imports/client/ui/tabletop/TabletopComponent.vue b/app/imports/client/ui/tabletop/TabletopComponent.vue index a3103692..9e9dff75 100644 --- a/app/imports/client/ui/tabletop/TabletopComponent.vue +++ b/app/imports/client/ui/tabletop/TabletopComponent.vue @@ -159,11 +159,6 @@ export default { } }, meteor: { - $subscribe: { - 'tabletop'() { - return [this.model._id]; - }, - }, creatures(){ return Creatures.find({ tabletopId: this.model._id }); }, diff --git a/app/imports/server/publications/creatureTemplates.js b/app/imports/server/publications/creatureTemplates.js new file mode 100644 index 00000000..a59c2926 --- /dev/null +++ b/app/imports/server/publications/creatureTemplates.js @@ -0,0 +1,140 @@ +import { check } from 'meteor/check'; +import Libraries from '/imports/api/library/Libraries'; +import LibraryNodes from '/imports/api/library/LibraryNodes'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; +import getSlotFillFilter from '/imports/api/creature/creatureProperties/methods/getSlotFillFilter' +import getCreatureLibraryIds from '/imports/api/library/getCreatureLibraryIds'; +import { LIBRARY_NODE_TREE_FIELDS } from '/imports/server/publications/library'; +import escapeRegex from '/imports/api/utility/escapeRegex'; +import getUserLibraryIds from '/imports/api/library/getUserLibraryIds'; + +// Publish docs the user has already selected so they don't disappear when searching +Meteor.publish('selectedCreatureTemplates', function (nodeIds) { + let autorun = this.autorun; + autorun(function () { + // TODO + return []; + let userId = this.userId; + if (!userId) { + return []; + } + + // Get all the ids of libraries the user can access + const creatureId = slot.root.id; + const libraryIds = getCreatureLibraryIds(creatureId, userId); + const libraries = Libraries.find({ + $or: [ + { owner: userId }, + { writers: userId }, + { readers: userId }, + { _id: { $in: libraryIds }, public: true }, + ] + }, { + sort: { name: 1 } + }); + + let filter = { _id: { $in: nodeIds } }; + // Get the limit of the documents the user can fetch + let options = { + sort: { + name: 1, + order: 1, + }, + limit: 100, + fields: LIBRARY_NODE_TREE_FIELDS, + }; + autorun(function () { + return [ + LibraryNodes.find(filter, options), + libraries + ]; + }); + }); +}); + +Meteor.publish('creatureTemplates', function (searchTerm) { + if (searchTerm) check(searchTerm, String); + + let self = this; + this.autorun(function () { + let userId = this.userId; + if (!userId) { + return []; + } + + // Get all the ids of libraries the user can access + const userLibIds = getUserLibraryIds(userId); + const libraries = Libraries.find({ + $or: [ + { owner: userId }, + { writers: userId }, + { readers: userId }, + { _id: { $in: userLibIds }, public: true }, + ] + }, { + sort: { name: 1 } + }); + + const libraryIds = libraries.map(lib => lib._id); + + this.autorun(function () { + // Build a filter for nodes in those libraries + const filter = { + 'root.id': { $in: libraryIds }, + type: 'creature', + removed: { $ne: true }, + } + + // Get the limit of the documents the user can fetch + var limit = self.data('limit') || 50; + check(limit, Number); + + let options = undefined; + if (searchTerm) { + if (!filter.$and) filter.$and = []; + filter.$and.push({ + $or: [ + { name: { $regex: escapeRegex(searchTerm), '$options': 'i' } }, + { libraryTags: searchTerm } + ] + }); + //filter.$text = { $search: searchTerm }; + options = { + // relevant documents have a higher score. + fields: { + //_score: { $meta: 'textScore' }, + ...LIBRARY_NODE_TREE_FIELDS, + }, + sort: { + // `score` property specified in the projection fields above. + //_score: { $meta: 'textScore' }, + name: 1, + order: 1, + } + } + } else { + //delete filter.$text + delete filter.name + options = { + sort: { + name: 1, + order: 1, + }, + fields: LIBRARY_NODE_TREE_FIELDS, + }; + } + options.limit = limit; + + self.autorun(function () { + self.setData('countAll', LibraryNodes.find(filter).count()); + self.setData('libraryNodeFilter', EJSON.stringify(filter)); + }); + self.autorun(function () { + return [ + LibraryNodes.find(filter, options), + libraries + ]; + }); + }); + }); +}); diff --git a/app/imports/server/publications/index.js b/app/imports/server/publications/index.js index 3c52d3a5..5beea28b 100644 --- a/app/imports/server/publications/index.js +++ b/app/imports/server/publications/index.js @@ -1,5 +1,6 @@ import '/imports/server/publications/publicationRateLimit'; import '/imports/server/publications/characterList'; +import '/imports/server/publications/creatureTemplates'; import '/imports/server/publications/library'; import '/imports/server/publications/singleCharacter'; import '/imports/server/publications/experiences';