Continued iterating on calculations, added failing test for bugs found
This commit is contained in:
@@ -4,10 +4,13 @@ import { unset } from 'lodash';
|
|||||||
export default function removeSchemaFields(schemas, prop){
|
export default function removeSchemaFields(schemas, prop){
|
||||||
schemas.forEach(schema => {
|
schemas.forEach(schema => {
|
||||||
schema._schemaKeys.forEach(key => {
|
schema._schemaKeys.forEach(key => {
|
||||||
// Skip object and array keys
|
// Skip object and array keys, except the errors array
|
||||||
if (
|
if (
|
||||||
schema.getQuickTypeForKey(key) === 'object' ||
|
schema.getQuickTypeForKey(key) === 'object' ||
|
||||||
schema.getQuickTypeForKey(key) === 'objectArray'
|
(
|
||||||
|
schema.getQuickTypeForKey(key) === 'objectArray' &&
|
||||||
|
key.slice(-6)!== 'errors'
|
||||||
|
)
|
||||||
) return;
|
) return;
|
||||||
// Unset other computed only keys
|
// Unset other computed only keys
|
||||||
applyFnToKey(prop, key, unset)
|
applyFnToKey(prop, key, unset)
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ function evaluateCalculation(calculation, scope){
|
|||||||
} else {
|
} else {
|
||||||
calculation.errors = context.errors
|
calculation.errors = context.errors
|
||||||
}
|
}
|
||||||
|
// remove the working fields
|
||||||
|
delete calculation._parseLevel;
|
||||||
|
delete calculation._parsedCalculation;
|
||||||
}
|
}
|
||||||
|
|
||||||
function embedInlineCalculations(inlineCalcObj){
|
function embedInlineCalculations(inlineCalcObj){
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ export default function(){
|
|||||||
assert.equal(prop.uses.value, 7);
|
assert.equal(prop.uses.value, 7);
|
||||||
assert.equal(prop.usesLeft, 2);
|
assert.equal(prop.usesLeft, 2);
|
||||||
|
|
||||||
|
const rolled = computation.propsById['rolledDescriptionId'];
|
||||||
|
assert.equal(rolled.summary.value, 'test roll gets compiled {1d4 + 4} properly');
|
||||||
|
|
||||||
const itemConsumed = prop.resources.itemsConsumed[0];
|
const itemConsumed = prop.resources.itemsConsumed[0];
|
||||||
assert.equal(itemConsumed.quantity.value, 3);
|
assert.equal(itemConsumed.quantity.value, 3);
|
||||||
assert.equal(itemConsumed.available, 27);
|
assert.equal(itemConsumed.available, 27);
|
||||||
@@ -60,6 +63,14 @@ var testProperties = [
|
|||||||
},
|
},
|
||||||
usesUsed: 5,
|
usesUsed: 5,
|
||||||
}),
|
}),
|
||||||
|
clean({
|
||||||
|
_id: 'rolledDescriptionId',
|
||||||
|
type: 'action',
|
||||||
|
ancestors: [{id: 'charId'}],
|
||||||
|
summary: {
|
||||||
|
text: 'test roll gets compiled {1d4 + (2 + 2)} properly',
|
||||||
|
},
|
||||||
|
}),
|
||||||
clean({
|
clean({
|
||||||
_id: 'numItemsConumedId',
|
_id: 'numItemsConumedId',
|
||||||
type: 'attribute',
|
type: 'attribute',
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Meteor } from 'meteor/meteor'
|
import { Meteor } from 'meteor/meteor'
|
||||||
import { isEqual, forOwn } from 'lodash';
|
import { isEqual } from 'lodash';
|
||||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||||
import propertySchemasIndex from '/imports/api/properties/computedOnlyPropertySchemasIndex.js';
|
import propertySchemasIndex from '/imports/api/properties/computedOnlyPropertySchemasIndex.js';
|
||||||
|
|
||||||
export default function writeAlteredProperties(computation){
|
export default function writeAlteredProperties(computation){
|
||||||
let bulkWriteOperations = [];
|
let bulkWriteOperations = [];
|
||||||
// Loop through all properties on the memo
|
// Loop through all properties on the memo
|
||||||
forOwn(computation.propsById, changed => {
|
computation.props.forEach(changed => {
|
||||||
let schema = propertySchemasIndex[changed.type];
|
let schema = propertySchemasIndex[changed.type];
|
||||||
if (!schema){
|
if (!schema){
|
||||||
console.warn('No schema for ' + changed.type);
|
console.warn('No schema for ' + changed.type);
|
||||||
@@ -36,6 +36,9 @@ function addChangedKeysToOp(op, keys, original, changed) {
|
|||||||
// and compile an operation that sets all those keys
|
// and compile an operation that sets all those keys
|
||||||
for (let key of keys){
|
for (let key of keys){
|
||||||
if (!isEqual(original[key], changed[key])){
|
if (!isEqual(original[key], changed[key])){
|
||||||
|
console.log('not equal: ', key);
|
||||||
|
console.log(original[key])
|
||||||
|
console.log(changed[key])
|
||||||
if (!op) op = newOperation(original._id, changed.type);
|
if (!op) op = newOperation(original._id, changed.type);
|
||||||
let value = changed[key];
|
let value = changed[key];
|
||||||
if (value === undefined){
|
if (value === undefined){
|
||||||
@@ -83,6 +86,7 @@ function addUnsetOp(op, key){
|
|||||||
// compensation without needing to roll back changes, which causes multiple
|
// compensation without needing to roll back changes, which causes multiple
|
||||||
// expensive redraws of the character sheet
|
// expensive redraws of the character sheet
|
||||||
function writePropertiesSequentially(bulkWriteOps){
|
function writePropertiesSequentially(bulkWriteOps){
|
||||||
|
console.log({opsLength: bulkWriteOps.length});
|
||||||
bulkWriteOps.forEach(op => {
|
bulkWriteOps.forEach(op => {
|
||||||
let updateOneOrMany = op.updateOne || op.updateMany;
|
let updateOneOrMany = op.updateOne || op.updateMany;
|
||||||
CreatureProperties.update(updateOneOrMany.filter, updateOneOrMany.update, {
|
CreatureProperties.update(updateOneOrMany.filter, updateOneOrMany.update, {
|
||||||
@@ -91,6 +95,7 @@ function writePropertiesSequentially(bulkWriteOps){
|
|||||||
bypassCollection2: true,
|
bypassCollection2: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
console.log('finished writing ops');
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is more efficient on the database, but significantly less efficient
|
// This is more efficient on the database, but significantly less efficient
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const DamageSchema = createPropertySchema({
|
|||||||
type: 'fieldToCompute',
|
type: 'fieldToCompute',
|
||||||
optional: true,
|
optional: true,
|
||||||
defaultValue: '1d8 + strength.modifier',
|
defaultValue: '1d8 + strength.modifier',
|
||||||
|
parseLevel: 'compile',
|
||||||
},
|
},
|
||||||
// Who this damage applies to
|
// Who this damage applies to
|
||||||
target: {
|
target: {
|
||||||
@@ -31,6 +32,7 @@ const ComputedOnlyDamageSchema = createPropertySchema({
|
|||||||
amount: {
|
amount: {
|
||||||
type: 'computedOnlyField',
|
type: 'computedOnlyField',
|
||||||
optional: true,
|
optional: true,
|
||||||
|
parseLevel: 'compile',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ function computedOnlyInlineCalculationField(field){
|
|||||||
},
|
},
|
||||||
[`${field}.inlineCalculations.$`]: {
|
[`${field}.inlineCalculations.$`]: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
parseLevel: 'compile',
|
||||||
},
|
},
|
||||||
// The part between bracers {}
|
// The part between bracers {}
|
||||||
[`${field}.inlineCalculations.$.calculation`]: {
|
[`${field}.inlineCalculations.$.calculation`]: {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ let schema = new SimpleSchema({
|
|||||||
|
|
||||||
Meteor.publish('singleCharacter', function(creatureId){
|
Meteor.publish('singleCharacter', function(creatureId){
|
||||||
schema.validate({ creatureId });
|
schema.validate({ creatureId });
|
||||||
this.autorun(function (){
|
this.autorun(function (computation){
|
||||||
let userId = this.userId;
|
let userId = this.userId;
|
||||||
let creatureCursor
|
let creatureCursor
|
||||||
creatureCursor = Creatures.find({
|
creatureCursor = Creatures.find({
|
||||||
@@ -24,7 +24,7 @@ Meteor.publish('singleCharacter', function(creatureId){
|
|||||||
let creature = creatureCursor.fetch()[0];
|
let creature = creatureCursor.fetch()[0];
|
||||||
try { assertViewPermission(creature, userId) }
|
try { assertViewPermission(creature, userId) }
|
||||||
catch(e){ return [] }
|
catch(e){ return [] }
|
||||||
if (creature.computeVersion !== VERSION){
|
if (creature.computeVersion !== VERSION && computation.firstRun){
|
||||||
try {
|
try {
|
||||||
computeCreature(creatureId)
|
computeCreature(creatureId)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<div class="attribute-form">
|
<div class="attribute-form">
|
||||||
<div class="layout column align-center">
|
<div class="layout column align-center">
|
||||||
<text-field
|
<computed-field
|
||||||
ref="focusFirst"
|
ref="focusFirst"
|
||||||
label="Base Value"
|
label="Base Value"
|
||||||
class="base-value-field"
|
class="base-value-field"
|
||||||
hint="This is the value of the attribute before effects are applied. Can be a number or a calculation"
|
hint="This is the value of the attribute before effects are applied. Can be a number or a calculation"
|
||||||
style="width: 332px;"
|
style="width: 332px;"
|
||||||
:value="model.baseValueCalculation"
|
:model="model.baseValue"
|
||||||
:error-messages="errors.baseValueCalculation"
|
:error-messages="errors.baseValue"
|
||||||
@change="change('baseValueCalculation', ...arguments)"
|
@change="({path, value, ack}) => $emit('change', {path: ['baseValue', ...path], value, ack})"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<calculation-error-list :errors="model.baseValueErrors" />
|
|
||||||
<div class="layout wrap">
|
<div class="layout wrap">
|
||||||
<text-field
|
<text-field
|
||||||
label="Name"
|
label="Name"
|
||||||
@@ -54,14 +53,12 @@
|
|||||||
:error-messages="errors.spellSlotLevelCalculation"
|
:error-messages="errors.spellSlotLevelCalculation"
|
||||||
@change="change('spellSlotLevelCalculation', ...arguments)"
|
@change="change('spellSlotLevelCalculation', ...arguments)"
|
||||||
/>
|
/>
|
||||||
<calculation-error-list :errors="model.spellSlotLevelErrors" />
|
|
||||||
<text-area
|
<text-area
|
||||||
label="Description"
|
label="Description"
|
||||||
:value="model.description"
|
:value="model.description"
|
||||||
:error-messages="errors.description"
|
:error-messages="errors.description"
|
||||||
@change="change('description', ...arguments)"
|
@change="change('description', ...arguments)"
|
||||||
/>
|
/>
|
||||||
<calculation-error-list :calculations="model.descriptionCalculations" />
|
|
||||||
<form-section
|
<form-section
|
||||||
name="Advanced"
|
name="Advanced"
|
||||||
standalone
|
standalone
|
||||||
@@ -122,12 +119,12 @@
|
|||||||
<script lang="js">
|
<script lang="js">
|
||||||
import FormSection from '/imports/ui/properties/forms/shared/FormSection.vue';
|
import FormSection from '/imports/ui/properties/forms/shared/FormSection.vue';
|
||||||
import propertyFormMixin from '/imports/ui/properties/forms/shared/propertyFormMixin.js';
|
import propertyFormMixin from '/imports/ui/properties/forms/shared/propertyFormMixin.js';
|
||||||
import CalculationErrorList from '/imports/ui/properties/forms/shared/CalculationErrorList.vue';
|
import ComputedField from '/imports/ui/properties/forms/shared/ComputedField.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FormSection,
|
FormSection,
|
||||||
CalculationErrorList,
|
ComputedField,
|
||||||
},
|
},
|
||||||
mixins: [propertyFormMixin],
|
mixins: [propertyFormMixin],
|
||||||
inject: {
|
inject: {
|
||||||
|
|||||||
29
app/imports/ui/properties/forms/shared/ComputedField.vue
Normal file
29
app/imports/ui/properties/forms/shared/ComputedField.vue
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<template lang="html">
|
||||||
|
<div class="computed-field">
|
||||||
|
<text-field
|
||||||
|
:value="model.calculation"
|
||||||
|
v-bind="$attrs"
|
||||||
|
@change="(value, ack) => $emit('change', {path: ['calculation'], value, ack})"
|
||||||
|
/>
|
||||||
|
<calculation-error-list :errors="model.errors" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CalculationErrorList from '/imports/ui/properties/forms/shared/CalculationErrorList.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CalculationErrorList,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="css" scoped>
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user