Reworked log data format, overhauled snackbar

This commit is contained in:
Stefan Zermatten
2021-03-28 12:31:39 +02:00
parent ada1355c29
commit 3c26bb2fc6
27 changed files with 273 additions and 244 deletions

View File

@@ -4,7 +4,7 @@ import embedInlineCalculations from '/imports/api/creature/computation/afterComp
export default function applyAction({prop, log}){ export default function applyAction({prop, log}){
let content = { name: prop.name }; let content = { name: prop.name };
if (prop.summary){ if (prop.summary){
content.description = embedInlineCalculations( content.value = embedInlineCalculations(
prop.summary, prop.summaryCalculations prop.summary, prop.summaryCalculations
); );
} }

View File

@@ -21,7 +21,7 @@ export default function applyAdjustment({
context.errors.forEach(e => { context.errors.forEach(e => {
log.content.push({ log.content.push({
name: 'Attribute damage error', name: 'Attribute damage error',
error: e.message || e.toString(), value: e.message || e.toString(),
}); });
}); });
if (damageTargets) { if (damageTargets) {
@@ -41,15 +41,15 @@ export default function applyAdjustment({
}); });
log.content.push({ log.content.push({
name: 'Attribute damage', name: 'Attribute damage',
resultPrefix: `${prop.stat} ${prop.operation === 'set' ? 'set to' : ''}`, value: `${prop.stat}${prop.operation === 'set' ? ' set to' : ''}` +
result: `${result.isNumber ? -result.value : result.toString()}`, ` ${result.isNumber ? -result.value : result.toString()}`,
}); });
}); });
} else { } else {
log.content.push({ log.content.push({
name: 'Attribute damage', name: 'Attribute damage',
resultPrefix: `${prop.stat} ${prop.operation === 'set' ? 'set to' : ''}`, value: `${prop.stat}${prop.operation === 'set' ? ' set to' : ''}` +
result: `${result.isNumber ? -result.value : result.toString()}`, ` ${result.isNumber ? -result.value : result.toString()}`,
}); });
} }
} }

View File

@@ -17,7 +17,6 @@ export default function applyAttack({
log.content.push({ log.content.push({
name: criticalHit ? 'Critical Hit!' : 'To Hit', name: criticalHit ? 'Critical Hit!' : 'To Hit',
resultPrefix: `1d20 [${value}] + ${prop.rollBonusResult} = `, value: `1d20 [${value}] + ${prop.rollBonusResult} = ` + result,
result,
}); });
} }

View File

@@ -42,15 +42,15 @@ export default function applyDamage({
if (result.constructor.name === 'ErrorNode'){ if (result.constructor.name === 'ErrorNode'){
log.content.push({ log.content.push({
name: 'Damage error', name: 'Damage error',
error: result.toString(), value: result.toString(),
}); });
return; return;
} }
// Memoise the damage suffix for the log // Memoise the damage suffix for the log
let suffix = (criticalHit ? ' critical ' : '') + let suffix = (criticalHit ? ' critical ' : ' ') +
prop.damageType + prop.damageType +
(prop.damageType !== 'healing' ? ' damage': ''); (prop.damageType !== ' healing ' ? ' damage ': '');
if (damageTargets && damageTargets.length) { if (damageTargets && damageTargets.length) {
// Iterate through all the targets // Iterate through all the targets
@@ -69,7 +69,7 @@ export default function applyDamage({
if (result.constructor.name === 'ErrorNode' || !result.isNumber){ if (result.constructor.name === 'ErrorNode' || !result.isNumber){
log.content.push({ log.content.push({
name: 'Damage error', name: 'Damage error',
error: result.toString(), value: result.toString(),
}); });
return; return;
} }
@@ -86,26 +86,21 @@ export default function applyDamage({
// Target is same as self, log damage as such // Target is same as self, log damage as such
log.content.push({ log.content.push({
name, name,
result: damageDealt, value: damageDealt + suffix + ' to self',
details: suffix + ' to self',
}); });
} else { } else {
log.content.push({ log.content.push({
name, name,
resultPrefix: 'Dealt ', value: 'Dealt ' + damageDealt + suffix + ` ${target.name && ' to '}${target.name}`,
result: damageDealt,
details: suffix + `${target.name && ' to '}${target.name}`,
}); });
// Log the damage received on that creature's log as well // Log the damage received on that creature's log as well
insertCreatureLog.call({ insertCreatureLog.call({
log: { log: {
creatureId: target._id,
content: [{ content: [{
name, name,
resultPrefix: 'Recieved ', value: 'Recieved ' + damageDealt + suffix,
result: damageDealt,
details: suffix,
}], }],
creatureId: target._id,
} }
}); });
} }
@@ -114,8 +109,7 @@ export default function applyDamage({
// There are no targets, just log the result // There are no targets, just log the result
log.content.push({ log.content.push({
name: prop.damageType === 'healing' ? 'Healing' : 'Damage', name: prop.damageType === 'healing' ? 'Healing' : 'Damage',
result: result.toString(), value: result.toString() + suffix,
details: suffix,
}); });
} }
} }

View File

@@ -20,7 +20,6 @@ export default function applyRoll({
} }
log.content.push({ log.content.push({
name: prop.name, name: prop.name,
resultPrefix: prop.variableName + ' = ' + prop.roll + ' = ', value: prop.variableName + ' = ' + prop.roll + ' = ' + result.toString(),
result: result.toString(),
}); });
} }

View File

@@ -22,8 +22,7 @@ export default function applySave({
let dc = result.value; let dc = result.value;
log.content.push({ log.content.push({
name: prop.name, name: prop.name,
resultPrefix: ' DC ', value: ' DC ' + result.toString(),
result: result.toString(),
}); });
if (prop.target === 'self'){ if (prop.target === 'self'){
let save = CreaturesProperties.findOne({ let save = CreaturesProperties.findOne({
@@ -36,7 +35,8 @@ export default function applySave({
}); });
if (!save){ if (!save){
log.content.push({ log.content.push({
error: 'No saving throw found: ' + prop.stat, name: 'Saving throw error',
value: 'No saving throw found: ' + prop.stat,
}); });
return; return;
} }
@@ -60,9 +60,7 @@ export default function applySave({
let saveSuccess = result >= dc; let saveSuccess = result >= dc;
log.content.push({ log.content.push({
name: 'Save', name: 'Save',
resultPrefix, value: resultPrefix + result + (saveSuccess ? 'Passed' : 'Failed')
result,
details: saveSuccess ? 'Passed' : 'Failed'
}); });
return !saveSuccess; return !saveSuccess;
} else { } else {
@@ -71,7 +69,8 @@ export default function applySave({
} }
} catch (e){ } catch (e){
log.content.push({ log.content.push({
error: e.toString(), name: 'Save error',
value: e.toString(),
}); });
} }
} }

View File

@@ -21,14 +21,13 @@ export default function applyToggle({
if (result.constructor.name === 'ErrorNode') { if (result.constructor.name === 'ErrorNode') {
log.content.push({ log.content.push({
name: 'Toggle error', name: 'Toggle error',
error: result.toString(), value: result.toString(),
}); });
return false; return false;
} }
log.content.push({ log.content.push({
name: prop.name || 'Toggle', name: prop.name || 'Toggle',
resultPrefix: prop.condition + ' = ', value: prop.condition + ' = ' + result.toString(),
result: result.toString(),
}); });
return !!result.value; return !!result.value;
} }

View File

@@ -61,7 +61,7 @@ export default function spendResources({prop, log}){
}); });
log.content.push({ log.content.push({
name: 'Uses left', name: 'Uses left',
result: prop.usesResult - (prop.usesUsed || 0) - 1, value: prop.usesResult - (prop.usesUsed || 0) - 1,
}); });
} }
@@ -84,10 +84,10 @@ export default function spendResources({prop, log}){
// Log all the spending // Log all the spending
if (gainLog.length) log.content.push({ if (gainLog.length) log.content.push({
name: 'Gained', name: 'Gained',
description: gainLog.join('\n'), value: gainLog.join('\n'),
}); });
if (spendLog.length) log.content.push({ if (spendLog.length) log.content.push({
name: 'Spent', name: 'Spent',
description: spendLog.join('\n'), value: spendLog.join('\n'),
}); });
} }

View File

@@ -58,6 +58,7 @@ function removeOldLogs(creatureId){
sort: {date: -1}, sort: {date: -1},
skip: PER_CREATURE_LOG_LIMIT, skip: PER_CREATURE_LOG_LIMIT,
}); });
if (!firstExpiredLog) return;
// Remove all logs older than the one over the limit // Remove all logs older than the one over the limit
CreatureLogs.remove({ CreatureLogs.remove({
creatureId, creatureId,
@@ -69,32 +70,10 @@ function logToMessageData(log){
let embed = { let embed = {
fields: [], fields: [],
}; };
log.content.forEach(c => { log.content.forEach(field => {
let field = {}; if (!field.name) field.name = '\u200b';
let descriptionField = {}; if (!field.value) field.value = '\u200b';
if (c.name) field.name = c.name; embed.fields.push(field);
let valueArray = [];
if (c.error) valueArray.push(`*${c.error}*`);
if (c.resultPrefix) valueArray.push(`${c.resultPrefix}`);
if (c.result) valueArray.push(`\`${c.result}\``);
if (c.details) valueArray.push(c.details);
if (valueArray.length) field.value = valueArray.join(' ');
if (c.description){
if (!field.value){
field.value = c.description;
} else {
descriptionField.value = c.description;
}
}
if (field.name || field.value){
if (!field.name) field.name = '\u200b';
if (!field.value) field.value = '\u200b';
embed.fields.push(field);
}
if (descriptionField.value){
descriptionField.name = '\u200b';
embed.fields.push(descriptionField);
}
}); });
return { embeds: [embed] }; return { embeds: [embed] };
} }
@@ -109,7 +88,7 @@ function logWebhook({log, creature}){
} }
const insertCreatureLog = new ValidatedMethod({ const insertCreatureLog = new ValidatedMethod({
name: 'creatureLogs.methods.insertCreatureLog', name: 'creatureLogs.methods.insert',
mixins: [RateLimiterMixin], mixins: [RateLimiterMixin],
rateLimit: { rateLimit: {
numRequests: 5, numRequests: 5,
@@ -138,7 +117,7 @@ const insertCreatureLog = new ValidatedMethod({
export function insertCreatureLogWork({log, creature, method}){ export function insertCreatureLogWork({log, creature, method}){
// Build the new log // Build the new log
if (typeof log === 'string'){ if (typeof log === 'string'){
log = {text: log}; log = {content: [{value: log}]};
} }
log.date = new Date(); log.date = new Date();
// Insert it // Insert it
@@ -190,30 +169,30 @@ const logRoll = new ValidatedMethod({
parsedResult = parse(roll); parsedResult = parse(roll);
} catch (e){ } catch (e){
let error = prettifyParseError(e); let error = prettifyParseError(e);
logContent.push({error}); logContent.push({name: 'Parse Error', value: error});
} }
if (parsedResult) try { if (parsedResult) try {
let rollContext = new CompilationContext(); let rollContext = new CompilationContext();
let compiled = parsedResult.compile(creature.variables, rollContext); let compiled = parsedResult.compile(creature.variables, rollContext);
let compiledString = compiled.toString(); let compiledString = compiled.toString();
if (!equalIgnoringWhitespace(compiledString, roll)) logContent.push({ if (!equalIgnoringWhitespace(compiledString, roll)) logContent.push({
details: roll value: roll
}); });
logContent.push({ logContent.push({
details: compiledString value: compiledString
}); });
let rolled = compiled.roll(creature.variables, rollContext); let rolled = compiled.roll(creature.variables, rollContext);
let rolledString = rolled.toString(); let rolledString = rolled.toString();
if (rolledString !== compiledString) logContent.push({ if (rolledString !== compiledString) logContent.push({
result: rolled.toString() value: rolled.toString()
}); });
let result = rolled.reduce(creature.variables, rollContext); let result = rolled.reduce(creature.variables, rollContext);
let resultString = result.toString(); let resultString = result.toString();
if (resultString !== rolledString) logContent.push({ if (resultString !== rolledString) logContent.push({
result: resultString value: resultString
}); });
} catch (e){ } catch (e){
logContent = [{error: 'Calculation error'}]; logContent = [{name: 'Calculation error'}];
} }
const log = { const log = {
content: logContent, content: logContent,

View File

@@ -3,31 +3,14 @@ import ErrorSchema from '/imports/api/properties/subSchemas/ErrorSchema.js';
import RollDetailsSchema from '/imports/api/properties/subSchemas/RollDetailsSchema.js'; import RollDetailsSchema from '/imports/api/properties/subSchemas/RollDetailsSchema.js';
let LogContentSchema = new SimpleSchema({ let LogContentSchema = new SimpleSchema({
// The name of the field, included in discord webhook message
name: { name: {
type: String, type: String,
optional: true, optional: true,
}, },
error: { // The details of the field, included in discord webhook message
type: String, // Markdown support
optional: true, value: {
},
resultPrefix: {
type: String,
optional: true,
},
result: {
type: String,
optional: true,
},
expandedResult: {
type: String,
optional: true,
},
details: {
type: String,
optional: true,
},
description: {
type: String, type: String,
optional: true, optional: true,
}, },

View File

@@ -53,6 +53,10 @@ export default class OperatorNode extends ParseNode {
} }
toString(){ toString(){
let {left, right, operator} = this; let {left, right, operator} = this;
// special case of adding a negative number
if (operator === '+' && right.isNumber && right.value < 0){
return `${left.toString()} - ${-right.value}`
}
return `${left.toString()} ${operator} ${right.toString()}`; return `${left.toString()} ${operator} ${right.toString()}`;
} }
traverse(fn){ traverse(fn){

View File

@@ -0,0 +1,6 @@
import { SyncedCron } from 'meteor/percolate:synced-cron';
SyncedCron.config({
// Log job run details to console
log: false,
});

View File

@@ -0,0 +1,16 @@
// Modified from https://gitlab.com/tozd/vue/snackbar-que
import Vue from 'vue';
const globalState = Vue.observable({queue: []});
let lastSnackbarId = 0;
function snackbar(data) {
globalState.queue.push({
data,
id: ++lastSnackbarId,
enqueuedAt: new Date(),
shown: false,
});
}
export {snackbar, globalState}

View File

@@ -0,0 +1,128 @@
<template lang="html">
<v-snackbar
bottom
left
v-bind="$attrs"
:value="isShown"
:timeout="timeout"
@input="value => isShown = value"
>
<div class="layout align-center">
<template v-if="snackbar && snackbar.data">
<div v-if="snackbar.data.text">
{{ snackbar.data.text }}
</div>
<template v-else-if="snackbar.data.content">
<log-content :model="snackbar.data.content" />
</template>
<v-spacer />
<v-btn
v-if="snackbar.data.callback"
color="primary"
text
@click="closeSnackbar(); snackbar.data.callback()"
>
{{ snackbar.data.callbackName }}
</v-btn>
</template>
</div>
<template #action="{ attrs }">
<v-btn
icon
v-bind="attrs"
@click="closeSnackbar"
>
<v-icon>close</v-icon>
</v-btn>
</template>
</v-snackbar>
</template>
<script lang="js">
// Modified from https://gitlab.com/tozd/vue/snackbar-queue
import { globalState } from '/imports/ui/components/snackbars/SnackbarQueue.js';
import LogContent from '/imports/ui/log/LogContent.vue';
export default {
components: {
LogContent,
},
props: {
timeout: {
type: Number,
default: 6000,
},
pause: {
type: Number,
default: 300,
},
},
data() {
return {
isShown: false,
snackbar: null,
};
},
watch: {
isShown(newValue) {
if (newValue === false && this.snackbar) {
const snackbarIndex = globalState.queue.findIndex((element) => element.id === this.snackbar.id);
if (snackbarIndex > -1) {
globalState.queue.splice(snackbarIndex, 1);
}
this.snackbar = null;
}
},
},
created() {
this.handle = null;
this.unwait = null;
this.showNextSnackbar();
},
methods: {
clearSnackbarState() {
if (this.handle) {
clearTimeout(this.handle);
this.handle = null;
}
if (this.unwait) {
this.unwait();
this.unwait = null;
}
},
showNextSnackbar() {
this.clearSnackbarState();
// Wait for the first next snackbar to be available.
this.unwait = this.$wait(function () {
// Snackbars are enqueued from oldest to newest and "find" searches array elements in
// same order as well, so the first one which matches is also the oldest one.
return globalState.queue.find((element) => element.shown === false);
}, function (snackbar) {
this.unwait = null;
snackbar.shown = true;
this.snackbar = snackbar;
this.isShown = true;
this.handle = setTimeout(() => {
this.handle = null;
this.showNextSnackbar();
}, this.timeout + this.pause);
});
},
closeSnackbar() {
this.clearSnackbarState();
this.isShown = false;
setTimeout(() => {
this.showNextSnackbar();
}, this.pause);
},
},
};
</script>

View File

@@ -1,46 +0,0 @@
<template lang="html">
<v-snackbar
v-if="snackbar"
:key="snackbar.text"
auto-height
bottom
:value="true"
:timeout="0"
>
{{ snackbar.text }}
<v-btn
v-if="snackbar.callback"
class="primary--text"
icon
@click="doCallback"
>
{{ snackbar.callbackName }}
</v-btn>
<v-btn
v-if="snackbar.showCloseButton"
icon
@click="$store.dispatch('closeSnackbar')"
>
<v-icon>close</v-icon>
</v-btn>
</v-snackbar>
</template>
<script lang="js">
export default {
computed: {
snackbar(){
return this.$store.state.snackbars.snackbars[0];
}
},
methods: {
doCallback(){
this.snackbar.callback();
this.$store.dispatch('closeSnackbar')
}
}
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -1,47 +0,0 @@
const snackbarStore = {
state: {
snackbars: [],
snackbarTimout: undefined,
},
mutations: {
addSnackbar(state, value){
state.snackbars.push(value)
},
closeCurrentSnackbar (state){
state.snackbars.shift();
},
cancelSnackbarTimeout (state){
if(state.snackbarTimout){
clearTimeout(state.snackbarTimout);
}
},
setSnackbarTimout(state, value){
state.snackbarTimout = value;
},
},
actions: {
snackbar({dispatch, commit}, value){
// value = {
// text,
// showCloseButton,
// callback,
// callbackName
// }
commit('addSnackbar', value);
commit('setSnackbarTimout', setTimeout(() => {
dispatch('closeSnackbar');
}, 5000));
},
closeSnackbar({dispatch, commit, state}){
commit('closeCurrentSnackbar');
commit('cancelSnackbarTimeout');
if (state.snackbars.length){
commit('setSnackbarTimout', setTimeout(() => {
dispatch('closeSnackbar');
}, 5000));
}
},
}
};
export default snackbarStore;

View File

@@ -78,6 +78,7 @@
import TreeTab from '/imports/ui/creature/character/characterSheetTabs/TreeTab.vue'; import TreeTab from '/imports/ui/creature/character/characterSheetTabs/TreeTab.vue';
import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js'; import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js'; import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js';
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
export default { export default {
components: { components: {
@@ -119,13 +120,10 @@
this.logObserver = CreatureLogs.find({ this.logObserver = CreatureLogs.find({
creatureId: this.creatureId, creatureId: this.creatureId,
}).observe({ }).observe({
added(doc){ added({content}){
if (!that.$subReady.singleCharacter) return; if (!that.$subReady.singleCharacter) return;
if (that.$store.state.rightDrawer) return; if (that.$store.state.rightDrawer) return;
that.$store.dispatch('snackbar', { snackbar({content});
text: doc.name,
showCloseButton: true,
});
}, },
}); });
}, },

View File

@@ -80,6 +80,7 @@ import getPropertyTitle from '/imports/ui/properties/shared/getPropertyTitle.js'
import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js'; import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
import { get, findLast } from 'lodash'; import { get, findLast } from 'lodash';
import equipItem from '/imports/api/creature/creatureProperties/methods/equipItem.js'; import equipItem from '/imports/api/creature/creatureProperties/methods/equipItem.js';
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
let formIndex = {}; let formIndex = {};
for (let key in propertyFormIndex){ for (let key in propertyFormIndex){
@@ -194,7 +195,7 @@ export default {
} else { } else {
this.$store.dispatch('popDialogStack'); this.$store.dispatch('popDialogStack');
} }
this.$store.dispatch('snackbar', { snackbar({
text: `Deleted ${getPropertyTitle(this.model)}`, text: `Deleted ${getPropertyTitle(this.model)}`,
callbackName: 'undo', callbackName: 'undo',
callback(){ callback(){

View File

@@ -57,6 +57,7 @@ import softRemoveProperty from '/imports/api/creature/creatureProperties/methods
import restoreProperty from '/imports/api/creature/creatureProperties/methods/restoreProperty.js'; import restoreProperty from '/imports/api/creature/creatureProperties/methods/restoreProperty.js';
import getPropertyTitle from '/imports/ui/properties/shared/getPropertyTitle.js'; import getPropertyTitle from '/imports/ui/properties/shared/getPropertyTitle.js';
import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js'; import insertPropertyFromLibraryNode from '/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js';
import { snackbar } from '/imports/ui/components/snackbars/SnackbarQueue.js';
export default { export default {
components: { components: {
@@ -104,7 +105,7 @@ export default {
}, },
remove(model){ remove(model){
softRemoveProperty.call({_id: model._id}); softRemoveProperty.call({_id: model._id});
this.$store.dispatch('snackbar', { snackbar({
text: `Deleted ${getPropertyTitle(model)}`, text: `Deleted ${getPropertyTitle(model)}`,
callbackName: 'undo', callbackName: 'undo',
callback(){ callback(){

View File

@@ -65,7 +65,7 @@
name="rightDrawer" name="rightDrawer"
/> />
<dialog-stack /> <dialog-stack />
<snackbars /> <snackbar-queue />
</v-app> </v-app>
</template> </template>
@@ -74,13 +74,13 @@
import Sidebar from '/imports/ui/layouts/Sidebar.vue'; import Sidebar from '/imports/ui/layouts/Sidebar.vue';
import DialogStack from '/imports/ui/dialogStack/DialogStack.vue'; import DialogStack from '/imports/ui/dialogStack/DialogStack.vue';
import { mapMutations } from 'vuex'; import { mapMutations } from 'vuex';
import Snackbars from '/imports/ui/components/snackbars/Snackbars.vue'; import SnackbarQueue from '/imports/ui/components/snackbars/SnackbarQueue.vue';
export default { export default {
components: { components: {
Sidebar, Sidebar,
DialogStack, DialogStack,
Snackbars, SnackbarQueue,
}, },
data(){return { data(){return {
name: 'Home', name: 'Home',

View File

@@ -0,0 +1,51 @@
<template lang="html">
<div class="log-content">
<div
v-for="(content, index) in model"
:key="index"
class="content-line"
>
<h4 class="content-name">
{{ content.name }}
</h4>
<markdown-text
v-if="content.value"
class="content-value"
:markdown="content.value"
/>
</div>
</div>
</template>
<script lang="js">
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
export default {
components: {
MarkdownText,
},
props: {
model: {
type: Array,
default: () => [],
},
},
}
</script>
<style lang="css" scoped>
.content-line {
min-height: 24px;
margin-top: 2px;
margin-bottom: 2px;
}
.content-line .details {
display: inline-block;
}
</style>
<style lang="css">
.log-content .content-value > p:last-of-type{
margin-bottom: 0;
}
</style>

View File

@@ -6,42 +6,17 @@
v-if="model.text || (model.content && model.content.length)" v-if="model.text || (model.content && model.content.length)"
class="pa-2" class="pa-2"
> >
<div <log-content :model="model.content" />
v-for="(content, index) in model.content"
:key="index"
class="content-line"
>
<h4>
{{ content.name }}
</h4>
<span
v-if="content.error"
class="error"
>{{ content.error }}</span>
{{ content.resultPrefix }}
<span
v-if="content.result"
class="subheading font-weight-bold mx-1"
>{{ content.result }}</span>
<span
v-if="content.details"
>{{ content.details }}</span>
<markdown-text
v-if="content.description"
class="description"
:markdown="content.description"
/>
</div>
</v-card-text> </v-card-text>
</v-card> </v-card>
</template> </template>
<script lang="js"> <script lang="js">
import MarkdownText from '/imports/ui/components/MarkdownText.vue'; import LogContent from '/imports/ui/log/LogContent.vue';
export default { export default {
components: { components: {
MarkdownText, LogContent,
}, },
props: { props: {
model: { model: {
@@ -51,20 +26,3 @@ export default {
}, },
} }
</script> </script>
<style lang="css" scoped>
.content-line {
min-height: 24px;
margin-top: 2px;
margin-bottom: 2px;
}
.content-line .details {
display: inline-block;
}
</style>
<style lang="css">
.log-entry .description > p:last-of-type{
margin-bottom: 0;
}
</style>

View File

@@ -3,6 +3,7 @@ import store from '/imports/ui/vuexStore.js';
import VueMeteorTracker from 'vue-meteor-tracker'; import VueMeteorTracker from 'vue-meteor-tracker';
import AppLayout from '/imports/ui/layouts/AppLayout.vue'; import AppLayout from '/imports/ui/layouts/AppLayout.vue';
import ReactiveProvide from 'vue-reactive-provide'; import ReactiveProvide from 'vue-reactive-provide';
import VueObserverUtils from '@tozd/vue-observer-utils';
import router from '/imports/ui/router.js'; import router from '/imports/ui/router.js';
import themes from '/imports/ui/themes.js'; import themes from '/imports/ui/themes.js';
import '/imports/ui/components/global/globalIndex.js'; import '/imports/ui/components/global/globalIndex.js';
@@ -35,7 +36,8 @@ Vue.use(Vuetify, {
}); });
Vue.use(ReactiveProvide, { Vue.use(ReactiveProvide, {
name: 'reactiveProvide', // default value name: 'reactiveProvide', // default value
}) });
Vue.use(VueObserverUtils);
// App start // App start
Meteor.startup(() => { Meteor.startup(() => {

View File

@@ -1,14 +1,12 @@
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import dialogStackStore from '/imports/ui/dialogStack/dialogStackStore.js'; import dialogStackStore from '/imports/ui/dialogStack/dialogStackStore.js';
import snackbarStore from '/imports/ui/components/snackbars/snackboxStore.js';
Vue.use(Vuex); Vue.use(Vuex);
const store = new Vuex.Store({ const store = new Vuex.Store({
strict: process.env.NODE_ENV !== 'production', strict: process.env.NODE_ENV !== 'production',
modules: { modules: {
dialogStack: dialogStackStore, dialogStack: dialogStackStore,
snackbars: snackbarStore,
}, },
state: { state: {
drawer: undefined, drawer: undefined,

5
app/package-lock.json generated
View File

@@ -79,6 +79,11 @@
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
"integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw=="
}, },
"@tozd/vue-observer-utils": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@tozd/vue-observer-utils/-/vue-observer-utils-0.5.0.tgz",
"integrity": "sha512-HeRxWFJB7FXcQigH2LvauiR0l7hA4qqBC6hK9rBeKf076Ew08C4lx3eo7/YmvADt3b8ZP1j+TN0pGCEhKYOhEA=="
},
"@types/color-name": { "@types/color-name": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",

View File

@@ -19,6 +19,7 @@
"dependencies": { "dependencies": {
"@babel/runtime": "^7.9.2", "@babel/runtime": "^7.9.2",
"@chenfengyuan/vue-countdown": "^1.1.5", "@chenfengyuan/vue-countdown": "^1.1.5",
"@tozd/vue-observer-utils": "^0.5.0",
"animejs": "^2.2.0", "animejs": "^2.2.0",
"bcrypt": "^5.0.0", "bcrypt": "^5.0.0",
"core-js": "^2.6.11", "core-js": "^2.6.11",

View File

@@ -1,4 +1,5 @@
import '/imports/server/config/SimpleRestConfig.js'; import '/imports/server/config/SimpleRestConfig.js';
import '/imports/server/config/SyncedCronConfig.js';
import '/imports/server/publications/index.js'; import '/imports/server/publications/index.js';
import '/imports/server/config/simpleSchemaDebug.js'; import '/imports/server/config/simpleSchemaDebug.js';
import '/imports/server/cron/deleteSoftRemovedDocuments.js'; import '/imports/server/cron/deleteSoftRemovedDocuments.js';