diff --git a/app/.meteor/packages b/app/.meteor/packages index 8f08cd9e..b23db4fc 100644 --- a/app/.meteor/packages +++ b/app/.meteor/packages @@ -51,3 +51,4 @@ typescript@4.9.4 seba:minifiers-autoprefixer mixmax:smart-disconnect zodern:types +zodern:fix-async-stubs diff --git a/app/.meteor/versions b/app/.meteor/versions index 3a927074..4bad2d18 100644 --- a/app/.meteor/versions +++ b/app/.meteor/versions @@ -125,4 +125,5 @@ url@1.3.2 webapp@1.13.5 webapp-hashing@1.1.1 zer0th:meteor-vuetify-loader@0.1.41 +zodern:fix-async-stubs@1.0.2 zodern:types@1.0.9 diff --git a/app/imports/api/creature/creatureProperties/CreatureProperties.ts b/app/imports/api/creature/creatureProperties/CreatureProperties.ts index 0aa23411..e5c2c3a9 100644 --- a/app/imports/api/creature/creatureProperties/CreatureProperties.ts +++ b/app/imports/api/creature/creatureProperties/CreatureProperties.ts @@ -162,6 +162,12 @@ for (const key in propertySchemasIndex) { schema.extend(ColorSchema); schema.extend(ChildSchema); schema.extend(SoftRemovableSchema); + // Use the any schema as a default schema for the collection + if (key === 'any') { + // @ts-expect-error don't have types for .attachSchema + CreatureProperties.attachSchema(schema); + } + // TODO make this an else branch and remove all {selector: {type: any}} options // @ts-expect-error don't have types for .attachSchema CreatureProperties.attachSchema(schema, { selector: { type: key } diff --git a/app/imports/api/creature/creatureProperties/methods/equipItem.js b/app/imports/api/creature/creatureProperties/methods/equipItem.js index 8261e882..27810d95 100644 --- a/app/imports/api/creature/creatureProperties/methods/equipItem.js +++ b/app/imports/api/creature/creatureProperties/methods/equipItem.js @@ -36,7 +36,7 @@ const equipItem = new ValidatedMethod({ let parentRef = getParentRefByTag(creature._id, tag); if (!parentRef) parentRef = { id: creature._id, collection: 'creatures' }; - organizeDoc.call({ + organizeDoc.callAsync({ docRef: { id: _id, collection: 'creatureProperties', diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyAction.ts b/app/imports/api/engine/actions/applyPropertyByType/applyAction.ts index c8b36fc9..a353047a 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyAction.ts +++ b/app/imports/api/engine/actions/applyPropertyByType/applyAction.ts @@ -18,7 +18,7 @@ interface Ammo extends Item { adjustment: number } -export default function applyAction(node: TreeNode, actionContext) { +export default async function applyAction(node: TreeNode, actionContext) { applyNodeTriggers(node, 'before', actionContext); const prop = node.doc; if (prop.target === 'self') actionContext.targets = [actionContext.creature]; @@ -198,7 +198,7 @@ function applyCrits(value, scope) { return { criticalHit, criticalMiss }; } -function spendResources(prop: Action, actionContext) { +async function spendResources(prop: Action, actionContext) { // Check Uses if (!prop.usesLeft || prop.usesLeft <= 0) { if (!prop.silent) actionContext.addLog({ diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyNote.js b/app/imports/api/engine/actions/applyPropertyByType/applyNote.js index 6c29ffaa..127b5c84 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyNote.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyNote.js @@ -2,7 +2,7 @@ import recalculateInlineCalculations from './shared/recalculateInlineCalculation import applyChildren from '/imports/api/engine/actions/applyPropertyByType/shared/applyChildren'; import { applyNodeTriggers } from '/imports/api/engine/actions/applyTriggers'; -export default function applyNote(node, actionContext) { +export default async function applyNote(node, actionContext) { applyNodeTriggers(node, 'before', actionContext); const prop = node.doc diff --git a/app/imports/api/engine/actions/applyTriggers.ts b/app/imports/api/engine/actions/applyTriggers.ts index b4fac8da..143ea5af 100644 --- a/app/imports/api/engine/actions/applyTriggers.ts +++ b/app/imports/api/engine/actions/applyTriggers.ts @@ -6,7 +6,7 @@ import applyProperty from '/imports/api/engine/actions/applyProperty'; import { difference, intersection } from 'lodash'; import getEffectivePropTags from '/imports/api/engine/computation/utility/getEffectivePropTags'; -export function applyNodeTriggers(node: TreeNode, timing, actionContext) { +export async function applyNodeTriggers(node: TreeNode, timing, actionContext) { const prop = node.doc; const type = prop.type; const triggers = actionContext.triggers?.doActionProperty?.[type]?.[timing]; diff --git a/app/imports/api/engine/computation/buildCreatureComputation.js b/app/imports/api/engine/computation/buildCreatureComputation.js index 2437d24e..1c48651b 100644 --- a/app/imports/api/engine/computation/buildCreatureComputation.js +++ b/app/imports/api/engine/computation/buildCreatureComputation.js @@ -1,4 +1,4 @@ -import { docsToForest } from '/imports/api/parenting/parentingFunctions'; +import { applyNestedSetProperties, calculateNestedSetOperations } from '/imports/api/parenting/parentingFunctions'; import { DenormalisedOnlyCreaturePropertySchema as denormSchema } from '/imports/api/creature/creatureProperties/CreatureProperties'; import { getProperties, getCreature, getVariables } from '/imports/api/engine/loadCreatures'; @@ -85,8 +85,14 @@ export function buildComputationFromProps(properties, creature, variables) { }); - // Get all the properties as trees based on their ancestors - let forest = docsToForest(properties); + // Get all the properties as a forest, with their nested set properties set + const forest = applyNestedSetProperties(properties); + const ops = calculateNestedSetOperations(properties); + if (ops.length > 20) { + console.log(ops.length + ' operations to get fixed nested sets'); + } else { + console.log(JSON.stringify(ops, null, 2)); + } // Walk the property trees computing things that need to be inherited walkDown(forest, node => { computeInactiveStatus(node); diff --git a/app/imports/api/engine/computation/computeComputation/computeByType.js b/app/imports/api/engine/computation/computeComputation/computeByType.js index a7adfc3e..3affc066 100644 --- a/app/imports/api/engine/computation/computeComputation/computeByType.js +++ b/app/imports/api/engine/computation/computeComputation/computeByType.js @@ -7,6 +7,7 @@ import propertySlot from './computeByType/computeSlot'; import container from './computeByType/computeContainer'; import spellList from './computeByType/computeSpellList'; import toggle from './computeByType/computeToggle'; +import trigger from './computeByType/computeTrigger'; import _calculation from './computeByType/computeCalculation'; export default Object.freeze({ diff --git a/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js b/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js index 21a7b9fd..638a481b 100644 --- a/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js +++ b/app/imports/api/engine/computation/writeComputation/writeAlteredProperties.js @@ -23,6 +23,9 @@ export default function writeAlteredProperties(computation) { 'deactivatingToggleId', 'damage', 'dirty', + 'left', + 'right', + 'parentId', ...schema.objectKeys(), ]; op = addChangedKeysToOp(op, keys, original, changed); diff --git a/app/imports/api/engine/loadCreatures.ts b/app/imports/api/engine/loadCreatures.ts index caa014cc..4d41e554 100644 --- a/app/imports/api/engine/loadCreatures.ts +++ b/app/imports/api/engine/loadCreatures.ts @@ -56,6 +56,7 @@ export function getProperties(creatureId) { const creature = loadedCreatures.get(creatureId); if (creature) { const props = Array.from(creature.properties.values()); + props.sort((a, b) => a.left - b.left); return EJSON.clone(props); } // console.time(`Cache miss on creature properties: ${creatureId}`) @@ -78,6 +79,7 @@ export function getPropertiesOfType(creatureId, propType) { props.push(prop); } } + props.sort((a, b) => a.left - b.left); return EJSON.clone(props); } // console.time(`Cache miss on creature properties: ${creatureId}`) diff --git a/app/imports/api/parenting/organizeMethods.js b/app/imports/api/parenting/organizeMethods.js new file mode 100644 index 00000000..66d5a98a --- /dev/null +++ b/app/imports/api/parenting/organizeMethods.js @@ -0,0 +1,118 @@ +import SimpleSchema from 'simpl-schema'; +import { ValidatedMethod } from 'meteor/mdg:validated-method'; +import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; +import { RefSchema } from '/imports/api/parenting/ChildSchema'; +import { assertDocEditPermission } from '/imports/api/sharing/sharingPermissions.js'; +import Creatures from '/imports/api/creature/creatures/Creatures.js'; +import { changeParent, fetchDocByRefAsync, getCollectionByName, rebuildNestedSets } from '/imports/api/parenting/parentingFunctions'; + +const organizeDoc = new ValidatedMethod({ + name: 'organize.organizeDoc', + validate: new SimpleSchema({ + docRef: RefSchema, + parentRef: RefSchema, + order: { + type: Number, + // Should end in 0.5 to place it reliably between two existing documents + }, + skipRecompute: { + type: Boolean, + optional: true, + }, + skipClient: { + type: Boolean, + optional: true, + }, + }).validator(), + mixins: [RateLimiterMixin], + rateLimit: { + numRequests: 5, + timeInterval: 5000, + }, + async run({ docRef, parentRef, order, skipRecompute, skipClient }) { + if (skipClient && this.isSimulation) { + return; + } + let doc = await fetchDocByRefAsync(docRef); + let collection = getCollectionByName(docRef.collection); + // The user must be able to edit both the doc and its parent to move it + // successfully + assertDocEditPermission(doc, this.userId); + let parent; + parent = await fetchDocByRefAsync(parentRef); + assertDocEditPermission(parent, this.userId); + + // Moving the doc to the root level means changing its parent to undefined + if (doc.root.id === parent._id) { + parent = null; + } + // Change the doc's parent + await changeParent(doc, parent, collection, order); + + // Figure out which creatures need to be recalculated after this move + const docCreature = getCreatureAncestorId(doc); + const parentCreature = getCreatureAncestorId(parent); + // Mark the creatures for recompute + if (!skipRecompute) { + if (docCreature) { + Creatures.updateAsync({ + _id: docCreature, + }, { + $set: { dirty: true }, + }); + } + if (parentCreature && parentCreature !== docCreature) { + Creatures.updateAsync({ + _id: parentCreature, + }, { + $set: { dirty: true }, + }); + } + } + }, +}); + +const reorderDoc = new ValidatedMethod({ + name: 'organize.reorderDoc', + validate: new SimpleSchema({ + docRef: RefSchema, + order: { + type: Number, + // Should end in 0.5 to place it reliably between two existing documents + }, + }).validator(), + mixins: [RateLimiterMixin], + rateLimit: { + numRequests: 5, + timeInterval: 5000, + }, + async run({ docRef, order }) { + const doc = await fetchDocByRefAsync(docRef); + assertDocEditPermission(doc, this.userId); + + let collection = getCollectionByName(docRef.collection); + console.log('setting doc left to ', order); + await collection.updateAsync(doc._id, { $set: { left: order } }); + + // Recompute the affected creatures + const creatureId = getCreatureAncestorId(doc); + if (creatureId) { + return Creatures.updateAsync({ + _id: creatureId + }, { + $set: { dirty: true }, + }); + } + }, +}); + +function getCreatureAncestorId(doc) { + if (doc.type === 'pc' || doc.type === 'npc' || doc.type === 'monster') { + return doc._id; + } + if (doc?.root?.collection === 'creatures') { + return doc.root.id; + } +} + +export { organizeDoc, reorderDoc }; diff --git a/app/imports/api/parenting/parentingFunctions.ts b/app/imports/api/parenting/parentingFunctions.ts index af81ccef..330b4f88 100644 --- a/app/imports/api/parenting/parentingFunctions.ts +++ b/app/imports/api/parenting/parentingFunctions.ts @@ -1,5 +1,7 @@ import { chain, reverse } from 'lodash'; import { TreeDoc, treeDocFields, Reference } from '/imports/api/parenting/ChildSchema'; +import { getProperties } from '/imports/api/engine/loadCreatures'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; export function getCollectionByName(name: string): Mongo.Collection { const collection = Mongo.Collection.get(name) @@ -11,7 +13,7 @@ export function getCollectionByName(name: string): Mongo.Collection { return collection; } -function assertDocFound(doc) { +function assertDocFound(doc, ref) { if (!doc) { throw new Meteor.Error('document-not-found', `No document could be found with id: ${ref.id} in ${ref.collection}` @@ -21,13 +23,13 @@ function assertDocFound(doc) { export function fetchDocByRefAsync(ref: Reference, options?: Mongo.Options): Promise { const doc = getCollectionByName(ref.collection).findOneAsync(ref.id, options); - assertDocFound(doc); + assertDocFound(doc, ref); return doc; } export function fetchDocByRef(ref: Reference, options?: Mongo.Options): TreeDoc { const doc: TreeDoc = getCollectionByName(ref.collection).findOne(ref.id, options); - assertDocFound(doc); + assertDocFound(doc, ref); return doc; } @@ -87,7 +89,9 @@ type FilteredDoc = { _ancestorOfMatchedDocument?: boolean, } & TreeDoc; -export async function filterToForest( +let filterToForest: undefined | ((...any) => TreeNode[]) = undefined; + +if (Meteor.isClient) filterToForest = function ( collection: Mongo.Collection, rootId: string, filter: Mongo.Selector, @@ -96,7 +100,7 @@ export async function filterToForest( includeFilteredDocAncestors = false, includeFilteredDocDescendants = false } = {} -): Promise[]> { +): TreeNode[] { // Setup the filter let collectionFilter = { 'root.id': rootId, @@ -128,8 +132,8 @@ export async function filterToForest( } } // Find all the docs that match the filter - const docs: TreeDoc[] = await collection.find(collectionFilter, collectionOptions) - .mapAsync(doc => { + const docs: TreeDoc[] = collection.find(collectionFilter, collectionOptions) + .map(doc => { if (!filter) return doc; // Mark the docs that were found by the custom filter doc._matchedDocumentFilter = true; @@ -139,7 +143,7 @@ export async function filterToForest( // Get the doc ancestors let ancestors: object[] = []; if (filter && includeFilteredDocAncestors) { - ancestors = await collection.find(getFilter.ancestorsOfAll(docs), collectionOptions).mapAsync(doc => { + ancestors = collection.find(getFilter.ancestorsOfAll(docs), collectionOptions).map(doc => { // Mark that the nodes are ancestors of the found nodes doc._ancestorOfMatchedDocument = true; return doc; @@ -149,19 +153,19 @@ export async function filterToForest( // Get the doc descendants let descendants: FilteredDoc[] = []; if (filter && includeFilteredDocDescendants) { - descendants = await collection.find({ + descendants = collection.find({ 'removed': { $ne: true }, ...getFilter.descendantsOfAll(docs), - }).mapAsync((doc: FilteredDoc) => { + }).map((doc: FilteredDoc) => { // Mark that the nodes are descendants of the found nodes doc._descendantOfMatchedDocument = true; return doc; }); } const nodes = chain([ - ancestors, - docs, - descendants + ...ancestors, + ...docs, + ...descendants ]).uniqBy('_id') .sortBy('left') .value(); @@ -169,6 +173,8 @@ export async function filterToForest( return docsToForest(nodes); } +export { filterToForest }; + type ForestAndOrphans = { forest: TreeNode[], orphanIds: string[] } /** * Takes a complete set of documents and builds a forest using just their `.parentIds` @@ -339,32 +345,41 @@ export function renewDocIds({ docArray, collectionMap = {}, idMap = {} }) { * Changes the doc to be a child of the parent, and then rebuilds the nested sets of the roots * of both doc and parent * @param doc The doc to move - * @param parent The new parent of the doc + * @param parent The new parent of the doc, null to move the doc to the root of the tree * @param collection * @returns */ -export async function changeParent(doc: TreeDoc, parent: TreeDoc, collection: Mongo.Collection, order?: number) { +export async function changeParent(doc: TreeDoc, parent: TreeDoc | null, collection: Mongo.Collection, order?: number) { // Skip if we aren't changing the parent id - if (doc.parentId === parent._id) return; + if (doc.parentId === parent?._id) return; // Store the original roots - const rootChange = doc.root.id !== parent.root.id; + const rootChange = parent && doc.root.id !== parent.root?.id; // Check that the doc isn't becoming its own ancestor - if (parent.left > doc.left && parent.right < doc.right) { + if (parent && parent.left > doc.left && parent.right < doc.right) { throw new Meteor.Error('invalid parenting', 'A doc can\'t be its own ancestor'); } // update the document's parenting and root if necessary - const update: Mongo.Modifier = { - $set: { parentId: parent._id } - }; + let update: Mongo.Modifier; + if (!parent) { + update = { + $unset: { parentId: 1 } + }; + } else { + update = { + $set: { parentId: parent?._id } + }; + } if (rootChange && update.$set) { update.$set.root = parent.root; } - if (order && update.$set) { + if (order) { + if (!update.$set) update.$set = {}; update.$set.left = order; } + await collection.updateAsync(doc._id, update); // Rebuild the nested sets of everything on the root document(s) @@ -403,7 +418,8 @@ export function hasAncestorRelationship(propA: TreeDoc, propB: TreeDoc): boolean /** * Returns true if A is a direct ancestor of B, assuming their roots are equal */ -export function isAncestor(propA: TreeDoc, propB: TreeDoc): boolean { +export function isAncestor(propA?: TreeDoc, propB?: TreeDoc): boolean { + if (!propA || !propB) return false; return propA.left < propB.left && propA.right > propB.right; } @@ -415,7 +431,7 @@ export function setDocToLastOrder(collection: Mongo.Collection, doc: Tr } export async function rebuildNestedSets(collection: Mongo.Collection, rootId: string) { - const docs = collection.find({ + const docs = await collection.find({ 'root.id': rootId, removed: { $ne: true } }, { @@ -424,11 +440,16 @@ export async function rebuildNestedSets(collection: Mongo.Collection, r //Reverse sorting so that arrays can be used as stacks with the first item on top left: 1, }, - }).fetch(); + }).fetchAsync(); const operations = calculateNestedSetOperations(docs); + return writeBulkOperations(collection, operations); +} - await writeBulkOperations(collection, operations); +export async function rebuildCreatureNestedSets(creatureId) { + const docs = getProperties(creatureId); + const operations = calculateNestedSetOperations(docs); + return writeBulkOperations(CreatureProperties as Mongo.Collection, operations); } /** Calculates the operations needed to make a tree of nested sets @@ -499,14 +520,14 @@ export function calculateNestedSetOperations(docs: TreeDoc[]) { /** * Same as calculateNestedSetOperations, but applies the ops to the properties - * Mostly used to create testing documents. - * @param docs - * @returns + * @param docs An array of documents that share a common root. Must already be sorted by `.left` in ascending order + * @returns The documents as a forest of tree nodes */ export function applyNestedSetProperties(docs: TreeDoc[]) { // Walk around the tree numbering left on the way down and right on the way up like so: - const { forest: stack, orphanIds } = docsToForestByParentId(reverse([...docs])); + const { forest, orphanIds } = docsToForestByParentId(reverse([...docs])); + const stack = [...forest]; const visitedNodes = new Set(); const visitedChildren = new Set(); let count = 1; @@ -540,6 +561,7 @@ export function applyNestedSetProperties(docs: TreeDoc[]) { count += 1; } } + return forest; } /** diff --git a/app/imports/api/tabletop/TabletopMaps.js b/app/imports/api/tabletop/TabletopMaps.js index 76f3e56d..e315daf8 100644 --- a/app/imports/api/tabletop/TabletopMaps.js +++ b/app/imports/api/tabletop/TabletopMaps.js @@ -1,5 +1,5 @@ import SimpleSchema from 'simpl-schema'; -import ChildSchema from '/imports/api/parenting/ChildSchema.js'; +import ChildSchema from '/imports/api/parenting/ChildSchema'; let TabletopMaps = new Mongo.Collection('tabletopmaps'); diff --git a/app/imports/api/tabletop/TabletopObjects.js b/app/imports/api/tabletop/TabletopObjects.js index ff42b0e3..907ef01c 100644 --- a/app/imports/api/tabletop/TabletopObjects.js +++ b/app/imports/api/tabletop/TabletopObjects.js @@ -1,5 +1,5 @@ import SimpleSchema from 'simpl-schema'; -import ChildSchema from '/imports/api/parenting/ChildSchema.js'; +import ChildSchema from '/imports/api/parenting/ChildSchema'; let TabletopObjects = new Mongo.Collection('tabletopObjects'); diff --git a/app/imports/client/ui/components/tree/TreeNode.vue b/app/imports/client/ui/components/tree/TreeNode.vue index 82f63802..968d59c6 100644 --- a/app/imports/client/ui/components/tree/TreeNode.vue +++ b/app/imports/client/ui/components/tree/TreeNode.vue @@ -37,11 +37,13 @@ :disabled="expanded" /> + {{ node.left }} + {{ node.right }} @@ -83,7 +85,6 @@ * the tree view shows off the full character structure, and where each part of * character comes from. **/ -import { canBeParent } from '/imports/api/parenting/parentingFunctions'; import { getPropertyIcon } from '/imports/constants/PROPERTIES'; import TreeNodeView from '/imports/client/ui/properties/treeNodeViews/TreeNodeView.vue'; import { isAncestor } from '/imports/api/parenting/parentingFunctions'; @@ -145,7 +146,7 @@ export default { return children; }, canExpand() { - return canBeParent(this.node.type); + return true; }, }, watch: { diff --git a/app/imports/client/ui/components/tree/TreeNodeList.vue b/app/imports/client/ui/components/tree/TreeNodeList.vue index 54c5d212..b4c4b6a8 100644 --- a/app/imports/client/ui/components/tree/TreeNodeList.vue +++ b/app/imports/client/ui/components/tree/TreeNodeList.vue @@ -12,13 +12,13 @@ > import draggable from 'vuedraggable'; import TreeNode from '/imports/client/ui/components/tree/TreeNode.vue'; -import { isParentAllowed } from '/imports/api/parenting/parentingFunctions'; export default { components: { @@ -93,22 +92,21 @@ export default { change({ added, moved }) { let event = moved || added; if (event) { - let doc = event.element.node; + let doc = event.element.doc; let newIndex; if (event.newIndex === 0) { - newIndex = -0.5; + newIndex = 0.5; } else { if (event.newIndex < this.children.length) { let childAtNewIndex = this.children[event.newIndex]; - let indexOrder = childAtNewIndex.node.order; if (event.newIndex > event.oldIndex) { - newIndex = indexOrder + 0.5; + newIndex = childAtNewIndex.doc.right + 0.5; } else { - newIndex = indexOrder - 0.5; + newIndex = childAtNewIndex.doc.left - 0.5; } } else { let childBeforeNewIndex = this.children[event.newIndex - 1]; - newIndex = childBeforeNewIndex.node.order + 0.5; + newIndex = childBeforeNewIndex.doc.right + 0.5; } } if (moved) { @@ -118,12 +116,8 @@ export default { } } }, - move(evt) { - let parentNode = evt.relatedContext.component.$parent.node - let parentType = parentNode && parentNode.type || 'root'; - let childType = evt.draggedContext.element.node.type; - let allowed = isParentAllowed({ parentType, childType }); - return allowed; + move() { + return true; }, }, }; diff --git a/app/imports/client/ui/creature/creatureList/CreatureListTile.vue b/app/imports/client/ui/creature/creatureList/CreatureListTile.vue index b1c13abc..86c89c6a 100644 --- a/app/imports/client/ui/creature/creatureList/CreatureListTile.vue +++ b/app/imports/client/ui/creature/creatureList/CreatureListTile.vue @@ -99,7 +99,7 @@ export default { // Create the undo function const oldOrder = item.order; const oldParent = item.parent; - const undo = () => organizeDoc.call({ + const undo = () => organizeDoc.callAsync({ docRef, parentRef: oldParent, order: (oldOrder || 0) - 0.5, @@ -112,7 +112,7 @@ export default { }); // Move the doc - organizeDoc.call({ + organizeDoc.callAsync({ docRef, parentRef: { collection: 'creatures', id: this.model._id }, order: -0.5, diff --git a/app/imports/client/ui/creature/creatureProperties/CreaturePropertiesTree.vue b/app/imports/client/ui/creature/creatureProperties/CreaturePropertiesTree.vue index 50e16dae..69ce92fc 100644 --- a/app/imports/client/ui/creature/creatureProperties/CreaturePropertiesTree.vue +++ b/app/imports/client/ui/creature/creatureProperties/CreaturePropertiesTree.vue @@ -47,8 +47,8 @@ export default { expanded: Boolean, }, meteor: { - async children() { - const children = await filterToForest( + children() { + const children = filterToForest?.( getCollectionByName(this.collection), this.root.id, this.filter, @@ -56,14 +56,15 @@ export default { includeFilteredDocAncestors: true, includeFilteredDocDescendants: true, } - ); + ) || []; + console.log(children) this.$emit('length', children.length); return children; }, }, methods: { reordered({ doc, newIndex }) { - reorderDoc.call({ + reorderDoc.callAsync({ docRef: { id: doc._id, collection: this.collection, @@ -81,7 +82,7 @@ export default { } else { parentRef = this.root; } - organizeDoc.call({ + organizeDoc.callAsync({ docRef: { id: doc._id, collection: this.collection, diff --git a/app/imports/client/ui/docs/DocsRightDrawer.vue b/app/imports/client/ui/docs/DocsRightDrawer.vue index 59b9132b..01831f79 100644 --- a/app/imports/client/ui/docs/DocsRightDrawer.vue +++ b/app/imports/client/ui/docs/DocsRightDrawer.vue @@ -19,7 +19,7 @@