Added undo buttons for deleting properties off a creature

This commit is contained in:
Stefan Zermatten
2020-10-17 19:10:37 +02:00
parent ebab41838c
commit 3f4cb8e26b
6 changed files with 70 additions and 11 deletions

View File

@@ -9,7 +9,7 @@ import { recomputeCreature } from '/imports/api/creature/computation/recomputeCr
import LibraryNodes from '/imports/api/library/LibraryNodes.js'; import LibraryNodes from '/imports/api/library/LibraryNodes.js';
import Creatures from '/imports/api/creature/Creatures.js'; import Creatures from '/imports/api/creature/Creatures.js';
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js'; import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js';
import { softRemove } from '/imports/api/parenting/softRemove.js'; import { softRemove, restore } from '/imports/api/parenting/softRemove.js';
import SoftRemovableSchema from '/imports/api/parenting/SoftRemovableSchema.js'; import SoftRemovableSchema from '/imports/api/parenting/SoftRemovableSchema.js';
import propertySchemasIndex from '/imports/api/properties/computedPropertySchemasIndex.js'; import propertySchemasIndex from '/imports/api/properties/computedPropertySchemasIndex.js';
import { import {
@@ -443,6 +443,23 @@ const softRemoveProperty = new ValidatedMethod({
} }
}); });
const restoreProperty = new ValidatedMethod({
name: 'creatureProperties.restore',
validate: new SimpleSchema({
_id: SimpleSchema.RegEx.Id
}).validator(),
mixins: [RateLimiterMixin],
rateLimit: {
numRequests: 5,
timeInterval: 5000,
},
run({_id}){
let property = CreatureProperties.findOne(_id);
assertPropertyEditPermission(property, this.userId);
restore({_id, collection: CreatureProperties});
recomputeCreatures(property);
}
});
export default CreatureProperties; export default CreatureProperties;
export { export {
@@ -456,5 +473,6 @@ export {
selectAmmoItem, selectAmmoItem,
pushToProperty, pushToProperty,
pullFromProperty, pullFromProperty,
softRemoveProperty, softRemoveProperty,
restoreProperty,
}; };

View File

@@ -41,16 +41,21 @@ const restoreError = function(){
}; };
export function restore({_id, collection}){ export function restore({_id, collection}){
collection = getCollectionByName(collection); if (typeof collection === 'string') {
collection = getCollectionByName(collection);
}
let numUpdated = collection.update({ let numUpdated = collection.update({
_id, _id,
removedWith: {$exists: false} removedWith: {$exists: false}
}, { $unset: { }, { $unset: {
removed: 1, removed: 1,
removedAt: 1, removedAt: 1,
}}); }}, {
selector: {type: 'any'},
},);
if (numUpdated === 0) restoreError(); if (numUpdated === 0) restoreError();
updateDescendants({ updateDescendants({
collection,
ancestorId: _id, ancestorId: _id,
filter: { filter: {
removedWith: _id, removedWith: _id,

View File

@@ -10,11 +10,12 @@
{{ snackbar.text }} {{ snackbar.text }}
<v-btn <v-btn
v-if="snackbar.callback" v-if="snackbar.callback"
class="primary--text"
flat flat
icon icon
@click="snackbar.callback" @click="doCallback"
> >
<v-icon>{{ snackbar.callbackName }}</v-icon> {{ snackbar.callbackName }}
</v-btn> </v-btn>
<v-btn <v-btn
v-if="snackbar.showCloseButton" v-if="snackbar.showCloseButton"
@@ -34,6 +35,12 @@ export default {
return this.$store.state.snackbars.snackbars[0]; return this.$store.state.snackbars.snackbars[0];
} }
}, },
methods: {
doCallback(){
this.snackbar.callback();
this.$store.dispatch('closeSnackbar')
}
}
} }
</script> </script>

View File

@@ -66,6 +66,7 @@ import CreatureProperties, {
pushToProperty, pushToProperty,
pullFromProperty, pullFromProperty,
softRemoveProperty, softRemoveProperty,
restoreProperty,
} from '/imports/api/creature/CreatureProperties.js'; } from '/imports/api/creature/CreatureProperties.js';
import Creatures from '/imports/api/creature/Creatures.js'; import Creatures from '/imports/api/creature/Creatures.js';
import PropertyToolbar from '/imports/ui/components/propertyToolbar.vue'; import PropertyToolbar from '/imports/ui/components/propertyToolbar.vue';
@@ -75,6 +76,7 @@ import PropertyIcon from '/imports/ui/properties/shared/PropertyIcon.vue';
import propertyFormIndex from '/imports/ui/properties/forms/shared/propertyFormIndex.js'; import propertyFormIndex from '/imports/ui/properties/forms/shared/propertyFormIndex.js';
import propertyViewerIndex from '/imports/ui/properties/viewers/shared/propertyViewerIndex.js'; import propertyViewerIndex from '/imports/ui/properties/viewers/shared/propertyViewerIndex.js';
import CreaturePropertiesTree from '/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue'; import CreaturePropertiesTree from '/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue';
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';
@@ -174,12 +176,20 @@ export default {
}); });
}, },
remove(){ remove(){
softRemoveProperty.call({_id: this._id}); const _id = this._id;
softRemoveProperty.call({_id});
if (this.embedded){ if (this.embedded){
this.$emit('removed'); this.$emit('removed');
} else { } else {
this.$store.dispatch('popDialogStack'); this.$store.dispatch('popDialogStack');
} }
this.$store.dispatch('snackbar', {
text: `Deleted ${getPropertyTitle(this.model)}`,
callbackName: 'undo',
callback(){
restoreProperty.call({_id});
},
});
}, },
selectSubProperty(_id){ selectSubProperty(_id){
this.$store.commit('pushDialogStack', { this.$store.commit('pushDialogStack', {

View File

@@ -27,7 +27,7 @@
icon icon
flat flat
small small
@click="remove(child._id)" @click="remove(child)"
> >
<v-icon>delete</v-icon> <v-icon>delete</v-icon>
</v-btn> </v-btn>
@@ -48,8 +48,14 @@
<script> <script>
import CreatureProperties from '/imports/api/creature/CreatureProperties.js'; import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import TreeNodeView from '/imports/ui/properties/treeNodeViews/TreeNodeView.vue'; import TreeNodeView from '/imports/ui/properties/treeNodeViews/TreeNodeView.vue';
import { softRemoveProperty, insertPropertyFromLibraryNode } from '/imports/api/creature/CreatureProperties.js'; import {
insertPropertyFromLibraryNode,
softRemoveProperty,
restoreProperty
} from '/imports/api/creature/CreatureProperties.js';
import getActiveProperties from '/imports/api/creature/getActiveProperties.js'; import getActiveProperties from '/imports/api/creature/getActiveProperties.js';
import getPropertyTitle from '/imports/ui/properties/shared/getPropertyTitle.js';
export default { export default {
components: { components: {
TreeNodeView, TreeNodeView,
@@ -90,8 +96,15 @@ export default {
} }
}); });
}, },
remove(_id){ remove(model){
softRemoveProperty.call({_id}); softRemoveProperty.call({_id: model._id});
this.$store.dispatch('snackbar', {
text: `Deleted ${getPropertyTitle(model)}`,
callbackName: 'undo',
callback(){
restoreProperty.call({_id: model._id});
},
});
} }
}, },
meteor: { meteor: {

View File

@@ -0,0 +1,6 @@
import { getPropertyName } from '/imports/constants/PROPERTIES.js';
export default function getPropertyTitle(prop){
if (prop.name) return prop.name;
return getPropertyName(prop.type);
}