Fixed adding creatures from libraries -> tabletops

This commit is contained in:
Thaum Rystra
2024-06-05 17:29:50 +02:00
parent a00292a523
commit 4921a34dfe
5 changed files with 158 additions and 91 deletions

View File

@@ -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;
}

View File

@@ -80,7 +80,7 @@
</div>
</v-layout>
<div class="text-caption text-no-wrap text-truncate">
{{ libraryNames[libraryNode.ancestors[0].id ] }}
{{ libraryNames[libraryNode.root.id ] }}
</div>
</v-layout>
<div
@@ -225,31 +225,6 @@ export default {
name: 'context',
include: ['creatureId'],
},
computed: {
tagsSearched() {
let or = [];
let not = [];
if (this.model.slotTags && this.model.slotTags.length) {
or.push(this.model.slotTags);
}
this.model.extraTags?.forEach(extras => {
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)

View File

@@ -159,11 +159,6 @@ export default {
}
},
meteor: {
$subscribe: {
'tabletop'() {
return [this.model._id];
},
},
creatures(){
return Creatures.find({ tabletopId: this.model._id });
},

View File

@@ -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
];
});
});
});
});

View File

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