From e8158ba531abc711e4d3f7831336492c8df8111d Mon Sep 17 00:00:00 2001 From: Thaum Rystra <9525416+ThaumRystra@users.noreply.github.com> Date: Mon, 28 Oct 2024 14:26:48 +0200 Subject: [PATCH] Iterate on action engine and tree data store migration --- .../creature/actions/input/CastSpellInput.vue | 24 +---- .../CreaturePropertyDialog.vue | 2 +- .../ui/creature/slots/LevelUpDialog.vue | 9 +- .../client/ui/library/LibraryEditDialog.vue | 3 +- .../client/ui/log/TabletopLogContent.vue | 87 +++++++++++++++---- .../ui/properties/InsertPropertyDialog.vue | 5 +- .../ui/properties/viewers/SkillViewer.vue | 7 +- .../client/ui/tabletop/TabletopActionCard.vue | 15 ++-- .../client/ui/tabletop/TabletopBuffCard.vue | 29 +++---- .../client/ui/tabletop/TabletopComponent.vue | 5 +- app/imports/server/publications/library.js | 9 +- .../server/publications/searchLibraryNodes.js | 10 ++- .../server/rest/apiPublications/creature.js | 47 ---------- 13 files changed, 124 insertions(+), 128 deletions(-) diff --git a/app/imports/client/ui/creature/actions/input/CastSpellInput.vue b/app/imports/client/ui/creature/actions/input/CastSpellInput.vue index f94d4190..81d096fa 100644 --- a/app/imports/client/ui/creature/actions/input/CastSpellInput.vue +++ b/app/imports/client/ui/creature/actions/input/CastSpellInput.vue @@ -145,15 +145,6 @@ - - Cast - @@ -186,18 +177,10 @@ export default { type: String, required: true, }, - slotId: { - type: String, - default: undefined, - }, value: { type: Object, required: true, }, - spellId: { - type: String, - default: undefined, - }, }, data() { return { @@ -258,7 +241,7 @@ export default { } else { const newSlot = find( CreatureProperties.find({ - 'ancestors.id': this.creatureId, + ...getFilter.descendantsOfRoot(this.creatureId), ...slotFilter }, { sort: { 'spellSlotLevel.value': 1, order: 1 }, @@ -339,9 +322,6 @@ export default { ); } }, - cast() { - this.$emit('continue'); - } }, meteor: { spells() { @@ -379,7 +359,7 @@ export default { }, spellSlots() { return CreatureProperties.find({ - 'ancestors.id': this.creatureId, + ...getFilter.descendantsOfRoot(this.creatureId), ...slotFilter }, { sort: { 'spellSlotLevel.value': 1, order: 1 }, diff --git a/app/imports/client/ui/creature/creatureProperties/CreaturePropertyDialog.vue b/app/imports/client/ui/creature/creatureProperties/CreaturePropertyDialog.vue index f21c4041..a31ac8f6 100644 --- a/app/imports/client/ui/creature/creatureProperties/CreaturePropertyDialog.vue +++ b/app/imports/client/ui/creature/creatureProperties/CreaturePropertyDialog.vue @@ -87,7 +87,7 @@ import { getPropertyName } from '/imports/constants/PROPERTIES'; import PropertyForm from '/imports/client/ui/properties/PropertyForm.vue'; import getPropertyTitle from '/imports/client/ui/properties/shared/getPropertyTitle'; import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions'; -import { get, findLast } from 'lodash'; +import { get } from 'lodash'; import equipItem from '/imports/api/creature/creatureProperties/methods/equipItem'; import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue'; import insertProperty from '/imports/api/creature/creatureProperties/methods/insertProperty'; diff --git a/app/imports/client/ui/creature/slots/LevelUpDialog.vue b/app/imports/client/ui/creature/slots/LevelUpDialog.vue index 73d6cb4a..58c05eb1 100644 --- a/app/imports/client/ui/creature/slots/LevelUpDialog.vue +++ b/app/imports/client/ui/creature/slots/LevelUpDialog.vue @@ -86,7 +86,7 @@
- {{ libraryNames[libraryNode.ancestors[0].id ] }} + {{ libraryNames[libraryNode.root.id ] }}
-

- {{ content.name }} -

- + mdi-chevron-right + + + + {{ creature.name && creature.name[0] || '?' }} + + +
+ v-for="(content, contentIndex) in contentGroup.content" + :key="contentIndex" + class="content-line" + > +

+ {{ content.name }} +

+ +
+
diff --git a/app/imports/client/ui/properties/InsertPropertyDialog.vue b/app/imports/client/ui/properties/InsertPropertyDialog.vue index b3ad859e..78904e89 100644 --- a/app/imports/client/ui/properties/InsertPropertyDialog.vue +++ b/app/imports/client/ui/properties/InsertPropertyDialog.vue @@ -206,7 +206,6 @@ import getThemeColor from '/imports/client/ui/utility/getThemeColor'; import PropertySelector from '/imports/client/ui/properties/shared/PropertySelector.vue'; import {snackbar} from '/imports/client/ui/components/snackbars/SnackbarQueue'; import PropertyForm from '/imports/client/ui/properties/PropertyForm.vue'; -import SimpleSchema from 'simpl-schema'; export default { components: { @@ -372,9 +371,9 @@ export default { _searchResult: true },{ sort: { - 'ancestors.0.id': 1, name: 1, - order: 1, + type: 1, + left: 1, }, }); }, diff --git a/app/imports/client/ui/properties/viewers/SkillViewer.vue b/app/imports/client/ui/properties/viewers/SkillViewer.vue index a9604589..f3525800 100644 --- a/app/imports/client/ui/properties/viewers/SkillViewer.vue +++ b/app/imports/client/ui/properties/viewers/SkillViewer.vue @@ -123,6 +123,7 @@ import SkillProficiency from '/imports/client/ui/properties/components/skills/Sk import getProficiencyIcon from '/imports/client/ui/utility/getProficiencyIcon'; import sortEffects from '/imports/client/ui/utility/sortEffects'; import PropertyTargetTags from '/imports/client/ui/properties/viewers/shared/PropertyTargetTags.vue'; +import { getFilter } from '/imports/api/parenting/parentingFunctions'; export default { components: { @@ -201,12 +202,12 @@ export default { let ability = this.model.ability; if (!creatureId || !ability) return; let abilityProp = CreatureProperties.findOne({ + ...getFilter.descendantsOfRoot(creatureId), variableName: ability, type: 'attribute', removed: { $ne: true }, inactive: { $ne: true }, overridden: { $ne: true }, - 'ancestors.id': creatureId, }); if (!abilityProp) return; return { @@ -215,16 +216,16 @@ export default { operation: 'base', amount: { value: abilityProp.modifier }, stats: [this.model.variableName], - ancestors: abilityProp.ancestors, + root: abilityProp.root, } }, proficiencyBonus() { return CreatureProperties.findOne({ + ...getFilter.descendantsOfRoot(this.context.creatureId), variableName: 'proficiencyBonus', overridden: { $ne: true }, removed: { $ne: true }, inactive: { $ne: true }, - 'ancestors.id': this.context.creatureId, })?.value; }, }, diff --git a/app/imports/client/ui/tabletop/TabletopActionCard.vue b/app/imports/client/ui/tabletop/TabletopActionCard.vue index ff27ab92..5d63b0bd 100644 --- a/app/imports/client/ui/tabletop/TabletopActionCard.vue +++ b/app/imports/client/ui/tabletop/TabletopActionCard.vue @@ -109,6 +109,7 @@ import TreeNodeList from '/imports/client/ui/components/tree/TreeNodeList.vue'; import { docsToForest } from '/imports/api/parenting/parentingFunctions'; import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { some } from 'lodash'; +import { getFilter } from '/imports/api/parenting/parentingFunctions'; export default { components: { @@ -184,9 +185,9 @@ export default { }, meteor: { children() { - const indicesOfTerminatingProps = []; + const excludedRanges = []; const decendants = CreatureProperties.find({ - 'ancestors.id': this.model._id, + ...getFilter.descendants(this.model), 'removed': { $ne: true }, }, { sort: {left: 1} @@ -194,9 +195,9 @@ export default { // Get all the props we don't want to show the decendants of and // where they might appear in the ancestor list if (prop.type === 'buff' || prop.type === 'folder') { - indicesOfTerminatingProps.push({ - id: prop._id, - ancestorIndex: prop.ancestors.length, + excludedRanges.push({ + left: prop.left, + right: prop.right, }); } return prop; @@ -204,8 +205,8 @@ export default { // Filter out folders entirely if (prop.type === 'folder') return false; // Filter out decendants of terminating props - return !some(indicesOfTerminatingProps, buffIndex => { - return prop.ancestors[buffIndex.ancestorIndex]?.id === buffIndex.id; + return !some(excludedRanges, range => { + return prop.left > range.left && prop.right < range.right; }); }); return docsToForest(decendants); diff --git a/app/imports/client/ui/tabletop/TabletopBuffCard.vue b/app/imports/client/ui/tabletop/TabletopBuffCard.vue index 2d425ddb..0de0ce1d 100644 --- a/app/imports/client/ui/tabletop/TabletopBuffCard.vue +++ b/app/imports/client/ui/tabletop/TabletopBuffCard.vue @@ -64,6 +64,7 @@ import TreeNodeList from '/imports/client/ui/components/tree/TreeNodeList.vue'; import { docsToForest } from '/imports/api/parenting/parentingFunctions'; import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import { some } from 'lodash'; +import { getFilter } from '/imports/api/parenting/parentingFunctions'; export default { components: { @@ -137,31 +138,29 @@ export default { }, meteor: { children() { - const indicesOfTerminatingProps = []; - const decendants = CreatureProperties.find({ - 'ancestors.id': this.model._id, + const excludedRanges = []; + const descendants = CreatureProperties.find({ + ...getFilter.descendants(this.model), 'removed': { $ne: true }, }, { sort: {left: 1} }).map(prop => { - // Get all the props we don't want to show the decendants of and - // where they might appear in the ancestor list - if (prop.type === 'buff' || prop.type === 'folder') { - indicesOfTerminatingProps.push({ - id: prop._id, - ancestorIndex: prop.ancestors.length, - }); - } + // Get all the props we don't want to show the descendants of and what range they cover in + // the tree + excludedRanges.push({ + left: prop.left, + right: prop.right, + }); return prop; }).filter(prop => { // Filter out folders entirely if (prop.type === 'folder') return false; - // Filter out decendants of terminating props - return !some(indicesOfTerminatingProps, buffIndex => { - return prop.ancestors[buffIndex.ancestorIndex]?.id === buffIndex.id; + // Filter out descendants of terminating props + return !some(excludedRanges, range => { + return prop.left > range.left && prop.right < range.right; }); }); - return docsToForest(decendants); + return docsToForest(descendants); }, }, methods: { diff --git a/app/imports/client/ui/tabletop/TabletopComponent.vue b/app/imports/client/ui/tabletop/TabletopComponent.vue index e1381500..b821d88e 100644 --- a/app/imports/client/ui/tabletop/TabletopComponent.vue +++ b/app/imports/client/ui/tabletop/TabletopComponent.vue @@ -109,12 +109,11 @@ import { assertEditPermission } from '/imports/api/creature/creatures/creaturePe import SelectedCreatureBar from '/imports/client/ui/tabletop/selectedCreatureBar/SelectedCreatureBar.vue'; import addCreaturesFromLibraryToTabletop from '/imports/api/tabletop/methods/addCreaturesFromLibraryToTabletop'; import removeCreatureFromTabletop from '/imports/api/tabletop/methods/removeCreatureFromTabletop'; +import { getFilter } from '/imports/api/parenting/parentingFunctions'; const getProperties = function (creatureId, selector = {}) { return CreatureProperties.find({ - 'ancestors.id': { - $eq: creatureId, - }, + ...getFilter.descendantsOfRoot(creatureId), inactive: { $ne: true }, removed: { $ne: true }, overridden: { $ne: true }, diff --git a/app/imports/server/publications/library.js b/app/imports/server/publications/library.js index 2466617c..5482866f 100644 --- a/app/imports/server/publications/library.js +++ b/app/imports/server/publications/library.js @@ -4,6 +4,7 @@ import LibraryCollections from '/imports/api/library/LibraryCollections'; import LibraryNodes from '/imports/api/library/LibraryNodes'; import { assertViewPermission, assertDocViewPermission } from '/imports/api/sharing/sharingPermissions'; import { union } from 'lodash'; +import { getFilter } from '/imports/api/parenting/parentingFunctions'; const LIBRARY_NODE_TREE_FIELDS = { _id: 1, @@ -284,7 +285,7 @@ Meteor.publish('softRemovedLibraryNodes', function (libraryId) { } return [ LibraryNodes.find({ - 'ancestors.0.id': libraryId, + ...getFilter.descendantsOfRoot(libraryId), removed: true, removedWith: { $exists: false }, }, { @@ -296,8 +297,8 @@ Meteor.publish('softRemovedLibraryNodes', function (libraryId) { Meteor.publish('descendantLibraryNodes', function (nodeId) { let node = LibraryNodes.findOne(nodeId); - let libraryId = node?.ancestors[0]?.id; - if (!libraryId) return []; + let libraryId = node?.root.id; + if (!libraryId || !node) return []; this.autorun(function () { let userId = this.userId; let library = Libraries.findOne(libraryId); @@ -307,7 +308,7 @@ Meteor.publish('descendantLibraryNodes', function (nodeId) { } return [ LibraryNodes.find({ - 'ancestors.id': nodeId, + ...getFilter.descendants(node), }, { sort: { left: 1 }, }), diff --git a/app/imports/server/publications/searchLibraryNodes.js b/app/imports/server/publications/searchLibraryNodes.js index 44edb214..72c017df 100644 --- a/app/imports/server/publications/searchLibraryNodes.js +++ b/app/imports/server/publications/searchLibraryNodes.js @@ -5,6 +5,7 @@ import getCreatureLibraryIds from '/imports/api/library/getCreatureLibraryIds'; import getUserLibraryIds from '/imports/api/library/getUserLibraryIds'; import { assertViewPermission } from '/imports/api/sharing/sharingPermissions'; import escapeRegex from '/imports/api/utility/escapeRegex'; +import { getFilter } from '/imports/api/parenting/parentingFunctions'; Meteor.publish('selectedLibraryNodes', function (selectedNodeIds) { check(selectedNodeIds, Array); @@ -13,10 +14,12 @@ Meteor.publish('selectedLibraryNodes', function (selectedNodeIds) { selectedNodeIds = selectedNodeIds.slice(0, 20); } let libraryViewPermissions = {}; + const nodes = []; // Check view permissions of all libraries for (let id of selectedNodeIds) { let node = LibraryNodes.findOne(id); if (!node) continue; + nodes.push(node); let libraryId = node.ancestors[0].id; if (libraryViewPermissions[id]) { continue; @@ -27,6 +30,9 @@ Meteor.publish('selectedLibraryNodes', function (selectedNodeIds) { readers: 1, writers: 1, public: 1, + root: 1, + left: 1, + right: 1, } }); assertViewPermission(library, this.userId); @@ -37,7 +43,7 @@ Meteor.publish('selectedLibraryNodes', function (selectedNodeIds) { return [LibraryNodes.find({ $or: [ { _id: { $in: selectedNodeIds } }, - { 'ancestors.id': { $in: selectedNodeIds } }, + { ...getFilter.descendantsOfAll(nodes) }, ], })]; }); @@ -63,7 +69,7 @@ Meteor.publish('searchLibraryNodes', function (creatureId) { // Build a filter for nodes in those libraries that match the type let filter = { - 'ancestors.id': { $in: libraryIds }, + ...getFilter.descendantsOfAllRoots(libraryIds), removed: { $ne: true }, searchable: true //library nodes must opt-in }; diff --git a/app/imports/server/rest/apiPublications/creature.js b/app/imports/server/rest/apiPublications/creature.js index 9f0fcc5e..f25abc82 100644 --- a/app/imports/server/rest/apiPublications/creature.js +++ b/app/imports/server/rest/apiPublications/creature.js @@ -53,50 +53,3 @@ JsonRoutes.add('get', 'api/creature/:id', function (req, res) { }); }); - -/* -Meteor.publish('api-creature', function (creatureId) { - try { - new SimpleSchema({ - creatureId: { - type: String, - regEx: SimpleSchema.RegEx.Id, - }, - }).validate({ creatureId }); - } catch (e) { - console.error(e) - this.error(e); - return; - } - const userId = this.userId; - const creatureCursor = Creatures.find({ - _id: creatureId, - }); - const creature = creatureCursor.fetch()[0]; - try { - assertViewPermission(creature, userId) - } catch (e) { - console.error(e) - this.error(e); - return; - } - if (creature.computeVersion !== VERSION) { - try { - computeCreature(creatureId) - } catch (e) { - console.error(e) - } - } - return [ - creatureCursor, - CreatureProperties.find({ - 'ancestors.id': creatureId, - }), - CreatureVariables.find({ - _creatureId: creatureId, - }), - ]; -}, { - url: 'api/creature/:0' -}); -*/