diff --git a/app/imports/api/creature/archive/ArchiveCreatureFiles.js b/app/imports/api/creature/archive/ArchiveCreatureFiles.js index c0d1094e..044e6158 100644 --- a/app/imports/api/creature/archive/ArchiveCreatureFiles.js +++ b/app/imports/api/creature/archive/ArchiveCreatureFiles.js @@ -1,8 +1,14 @@ -import { createS3FilesCollection } from '/imports/api/files/s3FileStorage.js'; + import SimpleSchema from 'simpl-schema'; import { incrementFileStorageUsed } from '/imports/api/users/methods/updateFileStorageUsed.js'; import { CreaturePropertySchema } from '/imports/api/creature/creatureProperties/CreatureProperties.js'; import { CreatureSchema } from '/imports/api/creature/creatures/Creatures.js'; +let createS3FilesCollection; +if (Meteor.isServer) { + createS3FilesCollection = require('/imports/api/files/server/s3FileStorage.js').createS3FilesCollection +} else { + createS3FilesCollection = require('/imports/api/files/client/s3FileStorage.js').createS3FilesCollection +} const ArchiveCreatureFiles = createS3FilesCollection({ collectionName: 'archiveCreatureFiles', diff --git a/app/imports/api/creature/creatures/methods/restCreature.js b/app/imports/api/creature/creatures/methods/restCreature.js index 7e7edb1e..bb351c03 100644 --- a/app/imports/api/creature/creatures/methods/restCreature.js +++ b/app/imports/api/creature/creatures/methods/restCreature.js @@ -83,13 +83,13 @@ export function resetProperties(creatureId, resetFilter, actionContext) { const attributeFilter = { ...filter, type: 'attribute', - damage: { $ne: 0 }, + damage: { $nin: [0, undefined] }, } CreatureProperties.find(attributeFilter).forEach(prop => { damagePropertyWork({ prop, operation: 'increment', - value: -prop.damage, + value: -prop.damage ?? 0, actionContext, logFunction(increment) { actionContext.addLog({ @@ -105,7 +105,7 @@ export function resetProperties(creatureId, resetFilter, actionContext) { type: { $in: ['action', 'spell'] }, - usesUsed: { $ne: 0 }, + usesUsed: { $nin: [0, undefined] }, }; CreatureProperties.find(actionFilter, { fields: { name: 1, usesUsed: 1 } diff --git a/app/imports/api/engine/actions/applyPropertyByType/applyAction.js b/app/imports/api/engine/actions/applyPropertyByType/applyAction.js index d749990d..021370d4 100644 --- a/app/imports/api/engine/actions/applyPropertyByType/applyAction.js +++ b/app/imports/api/engine/actions/applyPropertyByType/applyAction.js @@ -165,7 +165,7 @@ function rollAttack(attack, scope) { } scope['$attackDiceRoll'] = { value }; const result = value + attack.value; - scope['$attackRoll'] = { result }; + scope['$attackRoll'] = { value: result }; const { criticalHit, criticalMiss } = applyCrits(value, scope); return { resultPrefix, result, value, criticalHit, criticalMiss }; } diff --git a/app/imports/api/files/UserImages.js b/app/imports/api/files/UserImages.js index 9638d2f0..057c48a0 100644 --- a/app/imports/api/files/UserImages.js +++ b/app/imports/api/files/UserImages.js @@ -1,4 +1,9 @@ -import { createS3FilesCollection } from '/imports/api/files/s3FileStorage.js'; +let createS3FilesCollection; +if (Meteor.isServer) { + createS3FilesCollection = require('/imports/api/files/server/s3FileStorage.js').createS3FilesCollection +} else { + createS3FilesCollection = require('/imports/api/files/client/s3FileStorage.js').createS3FilesCollection +} const UserImages = createS3FilesCollection({ collectionName: 'userImages', diff --git a/app/imports/api/files/client/s3FileStorage.js b/app/imports/api/files/client/s3FileStorage.js new file mode 100644 index 00000000..ce2777cc --- /dev/null +++ b/app/imports/api/files/client/s3FileStorage.js @@ -0,0 +1,24 @@ +// https://github.com/VeliovGroup/Meteor-Files/blob/master/docs/aws-s3-integration.md +import { FilesCollection } from 'meteor/ostrio:files'; + +const createS3FilesCollection = function ({ + collectionName, + storagePath, + onBeforeUpload, + onAfterUpload, + debug,// = !Meteor.isProduction, + allowClientCode = false, +}) { + const collection = new FilesCollection({ + collectionName, + storagePath, + onBeforeUpload, + onAfterUpload, + debug, + allowClientCode, + }); + + return collection; +} + +export { createS3FilesCollection }; diff --git a/app/imports/api/files/server/s3.js b/app/imports/api/files/server/s3.js deleted file mode 100644 index 83719fa6..00000000 --- a/app/imports/api/files/server/s3.js +++ /dev/null @@ -1,2 +0,0 @@ -import S3 from 'aws-sdk/clients/s3'; -export default S3; diff --git a/app/imports/api/files/s3FileStorage.js b/app/imports/api/files/server/s3FileStorage.js similarity index 95% rename from app/imports/api/files/s3FileStorage.js rename to app/imports/api/files/server/s3FileStorage.js index 1ef22730..27fbed67 100644 --- a/app/imports/api/files/s3FileStorage.js +++ b/app/imports/api/files/server/s3FileStorage.js @@ -4,9 +4,7 @@ import { each, clone } from 'lodash'; import { Random } from 'meteor/random'; import { FilesCollection } from 'meteor/ostrio:files'; import stream from 'stream'; -if (Meteor.isServer) { - import S3 from '/imports/api/files/server/s3.js'; -} +import S3 from 'aws-sdk/clients/s3'; /* See fs-extra and graceful-fs NPM packages */ /* For better i/o performance */ @@ -31,7 +29,7 @@ let createS3FilesCollection; /* Check settings existence in `Meteor.settings` */ /* This is the best practice for app security */ -if (Meteor.isServer && Meteor.settings.useS3) { +if (Meteor.settings.useS3) { // Create a new S3 object const s3 = new S3({ accessKeyId: s3Conf.key, @@ -236,13 +234,11 @@ if (Meteor.isServer && Meteor.settings.useS3) { allowClientCode, }); - if (Meteor.isServer) { - // Use the normal file system to read files - collection.readJSONFile = async function (file) { - const fileString = await fsp.readFile(file.path, 'utf8'); - return JSON.parse(fileString); - }; - } + // Use the normal file system to read files + collection.readJSONFile = async function (file) { + const fileString = await fsp.readFile(file.path, 'utf8'); + return JSON.parse(fileString); + }; return collection; } diff --git a/app/imports/client/ui/components/ColumnLayout.vue b/app/imports/client/ui/components/ColumnLayout.vue index 8d3fc918..16721057 100644 --- a/app/imports/client/ui/components/ColumnLayout.vue +++ b/app/imports/client/ui/components/ColumnLayout.vue @@ -39,9 +39,6 @@ export default { .column-layout>div, .column-layout>span>div { - /* - Table and width set because firefox does not support break-inside: avoid - */ display: table; table-layout: fixed; width: 100%; diff --git a/app/imports/client/ui/components/global/DragHandle.vue b/app/imports/client/ui/components/global/DragHandle.vue index 8c06cc0f..7ec3b784 100644 --- a/app/imports/client/ui/components/global/DragHandle.vue +++ b/app/imports/client/ui/components/global/DragHandle.vue @@ -2,8 +2,8 @@ mdi-drag diff --git a/app/imports/client/ui/creature/CreatureForm.vue b/app/imports/client/ui/creature/CreatureForm.vue index d0752e73..65d1b6e6 100644 --- a/app/imports/client/ui/creature/CreatureForm.vue +++ b/app/imports/client/ui/creature/CreatureForm.vue @@ -218,30 +218,30 @@ export default { }, methods: { changeShowTreeTab(value) { + let currentTab = this.$store.getters.tabNameById(this.model._id); + if (!value && currentTab === 'tree') { + this.$store.commit( + 'setTabForCharacterSheet', + { id: this.model._id, tab: 'build' } + ); + } this.$emit('change', { path: ['settings', 'showTreeTab'], value: !!value }); - let currentTab = this.$store.getters.tabById(this.model._id); - if (!value && currentTab === 5) { - this.$store.commit( - 'setTabForCharacterSheet', - { id: this.model._id, tab: 4 } - ); - } }, changeHideSpellsTab(value) { + let currentTab = this.$store.getters.tabNameById(this.model._id); + if (!value && currentTab === 'spells') { + this.$store.commit( + 'setTabForCharacterSheet', + { id: this.model._id, tab: 'actions' } + ); + } this.$emit('change', { path: ['settings', 'hideSpellsTab'], value: !value }); - let currentTab = this.$store.getters.tabById(this.model._id); - if (!value && currentTab === 3) { - this.$store.commit( - 'setTabForCharacterSheet', - { id: this.model._id, tab: 4 } - ); - } }, allUserLibrariesChange(value, ack) { toggleAllUserLibraries.call({ diff --git a/app/imports/client/ui/creature/buildTree/BuildTreeNode.vue b/app/imports/client/ui/creature/buildTree/BuildTreeNode.vue index 853d79cf..a61b0c3b 100644 --- a/app/imports/client/ui/creature/buildTree/BuildTreeNode.vue +++ b/app/imports/client/ui/creature/buildTree/BuildTreeNode.vue @@ -4,7 +4,7 @@ :class="{ 'empty': !hasChildren, }" - :data-id="`build-tree-node-${node._id}`" + :data-id="`tree-node-${node._id}`" >
{ diff --git a/app/imports/client/ui/creature/character/CharacterDeleteDialog.vue b/app/imports/client/ui/creature/character/CharacterDeleteDialog.vue index 774d6e57..235b660a 100644 --- a/app/imports/client/ui/creature/character/CharacterDeleteDialog.vue +++ b/app/imports/client/ui/creature/character/CharacterDeleteDialog.vue @@ -5,7 +5,7 @@

- Type "{{ name }}" to permanenetly delete the character + Type "{{ name }}" to permanently delete the character

- - - @@ -58,6 +55,9 @@ + + + @@ -96,22 +96,22 @@ Stats mdi-chart-box - - Features - mdi-text - Actions mdi-lightning-bolt - - Spells + + Spells mdi-fire Inventory mdi-cube + + Features + mdi-text + Journal mdi-book-open-variant diff --git a/app/imports/client/ui/creature/character/CharacterSheetToolbar.vue b/app/imports/client/ui/creature/character/CharacterSheetToolbar.vue index 750819ef..6878df30 100644 --- a/app/imports/client/ui/creature/character/CharacterSheetToolbar.vue +++ b/app/imports/client/ui/creature/character/CharacterSheetToolbar.vue @@ -39,27 +39,45 @@ mdi-dots-vertical - - + + - mdi-delete Delete + + mdi-printer + Print - + + - mdi-pencil Edit details - - - - - mdi-share-variant Sharing - - - - - - - mdi-delete Unshare with me + + mdi-delete + Unshare with me @@ -101,9 +119,6 @@ Stats - - Features - Actions @@ -113,6 +128,9 @@ Inventory + + Features + Journal @@ -144,6 +162,7 @@ import isDarkColor from '/imports/client/ui/utility/isDarkColor.js'; import CharacterSheetFab from '/imports/client/ui/creature/character/CharacterSheetFab.vue'; import getThemeColor from '/imports/client/ui/utility/getThemeColor.js'; import SharedIcon from '/imports/client/ui/components/SharedIcon.vue'; +import getCreatureUrlName from '/imports/api/creature/creatures/getCreatureUrlName.js'; export default { components: { @@ -167,6 +186,9 @@ export default { isDark() { return isDarkColor(this.toolbarColor); }, + printUrl() { + return `/print-character/${this.creature._id}/${getCreatureUrlName(this.creature)}`; + }, }, methods: { ...mapMutations([ diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/ActionsTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/ActionsTab.vue index 9021333c..13b5b4fa 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/ActionsTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/ActionsTab.vue @@ -58,8 +58,20 @@ export default { }}, meteor: { actions() { - return CreatureProperties.find({ + const folderIds = CreatureProperties.find({ 'ancestors.id': this.creatureId, + type: 'folder', + groupStats: true, + hideStatsGroup: true, + removed: { $ne: true }, + inactive: { $ne: true }, + }, { fields: { _id: 1 } }).map(folder => folder._id); + + return CreatureProperties.find({ + 'ancestors.id': { + $eq: this.creatureId, + $nin: folderIds, + }, type: 'action', actionType: { $ne: 'event' }, removed: { $ne: true }, diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/BuildTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/BuildTab.vue index 1f4cd4bb..02846e91 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/BuildTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/BuildTab.vue @@ -86,7 +86,7 @@ diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/FeaturesTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/FeaturesTab.vue index 11144684..4a8a22ff 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/FeaturesTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/FeaturesTab.vue @@ -56,8 +56,20 @@ export default { }, meteor: { features() { - return CreatureProperties.find({ + const folderIds = CreatureProperties.find({ 'ancestors.id': this.creatureId, + type: 'folder', + groupStats: true, + hideStatsGroup: true, + removed: { $ne: true }, + inactive: { $ne: true }, + }, { fields: { _id: 1 } }).map(folder => folder._id); + + return CreatureProperties.find({ + 'ancestors.id': { + $eq: this.creatureId, + $nin: folderIds, + }, type: 'feature', removed: { $ne: true }, inactive: { $ne: true }, diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/InventoryTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/InventoryTab.vue index 89c4d59b..b87f2dd9 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/InventoryTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/InventoryTab.vue @@ -141,9 +141,22 @@ export default { }; }, meteor: { - containers() { + folderIds() { return CreatureProperties.find({ 'ancestors.id': this.creatureId, + type: 'folder', + groupStats: true, + hideStatsGroup: true, + removed: { $ne: true }, + inactive: { $ne: true }, + }, { fields: { _id: 1 } }).map(folder => folder._id); + }, + containers() { + return CreatureProperties.find({ + 'ancestors.id': { + $eq: this.creatureId, + $nin: this.folderIds, + }, type: 'container', removed: { $ne: true }, inactive: { $ne: true }, @@ -166,7 +179,7 @@ export default { return CreatureProperties.find({ 'ancestors.id': { $eq: this.creatureId, - $nin: this.containerIds + $nin: [...this.containerIds, ...this.folderIds], }, type: 'container', removed: { $ne: true }, @@ -179,7 +192,7 @@ export default { return CreatureProperties.find({ 'ancestors.id': { $eq: this.creatureId, - $nin: this.containerIds + $nin: [...this.containerIds, ...this.folderIds], }, type: 'item', equipped: { $ne: true }, diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/JournalTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/JournalTab.vue index 2679265a..36502e54 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/JournalTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/JournalTab.vue @@ -60,8 +60,20 @@ export default { }, meteor: { notes(){ - return CreatureProperties.find({ + const folderIds = CreatureProperties.find({ 'ancestors.id': this.creatureId, + type: 'folder', + groupStats: true, + hideStatsGroup: true, + removed: { $ne: true }, + inactive: { $ne: true }, + }, { fields: { _id: 1 } }).map(folder => folder._id); + + return CreatureProperties.find({ + 'ancestors.id': { + $eq: this.creatureId, + $nin: folderIds, + }, type: 'note', removed: {$ne: true}, inactive: {$ne: true}, diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/SpellsTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/SpellsTab.vue index f34da451..549d742c 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/SpellsTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/SpellsTab.vue @@ -10,7 +10,7 @@ @remove="softRemove" />
folder._id); + }, + hasSpellSlots() { + return !!CreatureProperties.findOne({ + 'ancestors.id': this.creatureId, + inactive: { $ne: true }, + removed: { $ne: true }, + overridden: { $ne: true }, + level: { $ne: 0 }, + type: 'attribute', + attributeType: 'spellSlot', + }); + }, + spellSlots() { + return CreatureProperties.find({ + 'ancestors.id': { + $eq: this.creatureId, + $nin: this.folderIds, + }, inactive: { $ne: true }, removed: { $ne: true }, overridden: { $ne: true }, @@ -89,11 +113,16 @@ export default { { hideWhenTotalZero: true, total: 0 }, { hideWhenValueZero: true, value: 0 }, ], + }, { + sort: { order: 1 } }); }, spellLists() { return CreatureProperties.find({ - 'ancestors.id': this.creatureId, + 'ancestors.id': { + $eq: this.creatureId, + $nin: this.folderIds, + }, type: 'spellList', removed: { $ne: true }, inactive: { $ne: true }, @@ -113,7 +142,7 @@ export default { return CreatureProperties.find({ 'ancestors.id': { $eq: this.creatureId, - $nin: this.spellListIds, + $nin: [...this.spellListIds, ...this.folderIds], }, type: 'spell', removed: { $ne: true }, @@ -130,7 +159,7 @@ export default { return CreatureProperties.find({ 'ancestors.id': { $eq: this.creatureId, - $nin: this.spellListIds, + $nin: [...this.spellListIds, ...this.folderIds], }, type: 'spellList', removed: { $ne: true }, diff --git a/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue b/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue index b5254836..535a7fdd 100644 --- a/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue +++ b/app/imports/client/ui/creature/character/characterSheetTabs/StatsTab.vue @@ -28,7 +28,7 @@ @remove="softRemove" />
@@ -161,13 +161,13 @@
Hit Dice -