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';