Disabled various buttons when the user doesn't have edit permission

This commit is contained in:
Thaum Rystra
2020-05-21 12:47:02 +02:00
parent 47aad6d186
commit 13a0d66433
10 changed files with 303 additions and 189 deletions

View File

@@ -5,6 +5,7 @@
:value="model.name" :value="model.name"
:error-messages="errors.name" :error-messages="errors.name"
:debounce-time="debounceTime" :debounce-time="debounceTime"
:disabled="disabled"
@change="(value, ack) => $emit('change', {path: ['name'], value, ack})" @change="(value, ack) => $emit('change', {path: ['name'], value, ack})"
/> />
<text-field <text-field
@@ -12,6 +13,7 @@
:value="model.alignment" :value="model.alignment"
:error-messages="errors.alignment" :error-messages="errors.alignment"
:debounce-time="debounceTime" :debounce-time="debounceTime"
:disabled="disabled"
@change="(value, ack) => $emit('change', {path: ['alignment'], value, ack})" @change="(value, ack) => $emit('change', {path: ['alignment'], value, ack})"
/> />
<text-field <text-field
@@ -19,6 +21,7 @@
:value="model.gender" :value="model.gender"
:error-messages="errors.gender" :error-messages="errors.gender"
:debounce-time="debounceTime" :debounce-time="debounceTime"
:disabled="disabled"
@change="(value, ack) => $emit('change', {path: ['gender'], value, ack})" @change="(value, ack) => $emit('change', {path: ['gender'], value, ack})"
/> />
<text-field <text-field
@@ -27,6 +30,7 @@
:value="model.picture" :value="model.picture"
:error-messages="errors.picture" :error-messages="errors.picture"
:debounce-time="debounceTime" :debounce-time="debounceTime"
:disabled="disabled"
@change="(value, ack) => $emit('change', {path: ['picture'], value, ack})" @change="(value, ack) => $emit('change', {path: ['picture'], value, ack})"
/> />
<text-field <text-field
@@ -35,6 +39,7 @@
:value="model.avatarPicture" :value="model.avatarPicture"
:error-messages="errors.avatarPicture" :error-messages="errors.avatarPicture"
:debounce-time="debounceTime" :debounce-time="debounceTime"
:disabled="disabled"
@change="(value, ack) => $emit('change', {path: ['avatarPicture'], value, ack})" @change="(value, ack) => $emit('change', {path: ['avatarPicture'], value, ack})"
/> />
<!-- <!--
@@ -44,18 +49,21 @@
label="Use variant encumbrance" label="Use variant encumbrance"
:input-value="model.settings.useVariantEncumbrance" :input-value="model.settings.useVariantEncumbrance"
:error-messages="errors.useVariantEncumbrance" :error-messages="errors.useVariantEncumbrance"
:disabled="disabled"
@change="value => $emit('change', {path: ['settings','useVariantEncumbrance'], value})" @change="value => $emit('change', {path: ['settings','useVariantEncumbrance'], value})"
/> />
<v-switch <v-switch
label="Hide spells tab" label="Hide spells tab"
:input-value="model.settings.hideSpellcasting" :input-value="model.settings.hideSpellcasting"
:error-messages="errors.hideSpellcasting" :error-messages="errors.hideSpellcasting"
:disabled="disabled"
@change="value => $emit('change', {path: ['settings','hideSpellcasting'], value})" @change="value => $emit('change', {path: ['settings','hideSpellcasting'], value})"
/> />
<v-switch <v-switch
label="Swap ability scores and modifiers" label="Swap ability scores and modifiers"
:input-value="model.settings.swapStatAndModifier" :input-value="model.settings.swapStatAndModifier"
:error-messages="errors.swapStatAndModifier" :error-messages="errors.swapStatAndModifier"
:disabled="disabled"
@change="value => $emit('change', {path: ['settings','swapStatAndModifier'], value})" @change="value => $emit('change', {path: ['settings','swapStatAndModifier'], value})"
/> />
</form-section> </form-section>
@@ -88,6 +96,7 @@ export default {
type: Boolean, type: Boolean,
}, },
debounceTime: Number, debounceTime: Number,
disabled: Boolean,
}, },
}; };
</script> </script>

View File

@@ -6,6 +6,7 @@
<div> <div>
<creature-form <creature-form
:model="model" :model="model"
:disabled="editPermission === false"
@change="change" @change="change"
/> />
</div> </div>
@@ -25,6 +26,7 @@ import Creatures from '/imports/api/creature/Creatures.js';
import {updateCreature} from '/imports/api/creature/Creatures.js'; import {updateCreature} from '/imports/api/creature/Creatures.js';
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue'; import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
import CreatureForm from '/imports/ui/creature/CreatureForm.vue' import CreatureForm from '/imports/ui/creature/CreatureForm.vue'
import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
export default { export default {
components: { components: {
@@ -39,6 +41,14 @@ export default {
model(){ model(){
return Creatures.findOne(this._id); return Creatures.findOne(this._id);
}, },
editPermission(){
try {
assertEditPermission(this.model, Meteor.userId());
return true;
} catch (e) {
return false;
}
},
}, },
methods: { methods: {
change({path, value, ack}){ change({path, value, ack}){

View File

@@ -48,17 +48,13 @@
//TODO add a "no character found" screen if shown on a false address //TODO add a "no character found" screen if shown on a false address
// or on a character the user does not have permission to view // or on a character the user does not have permission to view
import Creatures from '/imports/api/creature/Creatures.js'; import Creatures from '/imports/api/creature/Creatures.js';
import removeCreature from '/imports/api/creature/removeCreature.js';
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
import { mapMutations } from 'vuex';
import { theme } from '/imports/ui/theme.js';
import StatsTab from '/imports/ui/creature/character/characterSheetTabs/StatsTab.vue'; import StatsTab from '/imports/ui/creature/character/characterSheetTabs/StatsTab.vue';
import FeaturesTab from '/imports/ui/creature/character/characterSheetTabs/FeaturesTab.vue'; import FeaturesTab from '/imports/ui/creature/character/characterSheetTabs/FeaturesTab.vue';
import InventoryTab from '/imports/ui/creature/character/characterSheetTabs/InventoryTab.vue'; import InventoryTab from '/imports/ui/creature/character/characterSheetTabs/InventoryTab.vue';
import SpellsTab from '/imports/ui/creature/character/characterSheetTabs/SpellsTab.vue'; import SpellsTab from '/imports/ui/creature/character/characterSheetTabs/SpellsTab.vue';
import PersonaTab from '/imports/ui/creature/character/characterSheetTabs/PersonaTab.vue'; import PersonaTab from '/imports/ui/creature/character/characterSheetTabs/PersonaTab.vue';
import TreeTab from '/imports/ui/creature/character/characterSheetTabs/TreeTab.vue'; import TreeTab from '/imports/ui/creature/character/characterSheetTabs/TreeTab.vue';
import { recomputeCreature } from '/imports/api/creature/computation/recomputeCreature.js'; import { assertEditPermission } from '/imports/api/creature/creaturePermissions.js';
export default { export default {
components: { components: {
@@ -81,7 +77,7 @@
}, },
reactiveProvide: { reactiveProvide: {
name: 'context', name: 'context',
include: ['creature'], include: ['creature', 'editPermission'],
}, },
onMounted(){ onMounted(){
this.$store.commit('setPageTitle', this.creature && this.creature.name || 'Character Sheet'); this.$store.commit('setPageTitle', this.creature && this.creature.name || 'Character Sheet');
@@ -100,6 +96,14 @@
creature(){ creature(){
return Creatures.findOne(this.creatureId) || {}; return Creatures.findOne(this.creatureId) || {};
}, },
editPermission(){
try {
assertEditPermission(this.creature, Meteor.userId());
return true;
} catch (e) {
return false;
}
},
}, },
} }
</script> </script>

View File

@@ -5,6 +5,7 @@
<toolbar-card color=""> <toolbar-card color="">
<v-spacer slot="toolbar" /> <v-spacer slot="toolbar" />
<v-switch <v-switch
v-if="context.editPermission !== false"
slot="toolbar" slot="toolbar"
v-model="organize" v-model="organize"
label="Organize" label="Organize"
@@ -53,6 +54,9 @@ export default {
ContainerCard, ContainerCard,
ToolbarCard, ToolbarCard,
}, },
inject: {
context: { default: {} }
},
props: { props: {
creatureId: String, creatureId: String,
}, },

View File

@@ -5,6 +5,7 @@
<v-card> <v-card>
<v-card-text> <v-card-text>
<v-switch <v-switch
v-if="context.editPermission !== false"
v-model="organize" v-model="organize"
label="Organize" label="Organize"
class="justify-end" class="justify-end"
@@ -48,6 +49,9 @@ export default {
CreaturePropertiesTree, CreaturePropertiesTree,
SpellListCard, SpellListCard,
}, },
inject: {
context: { default: {} }
},
props: { props: {
creatureId: { creatureId: {
type: String, type: String,

View File

@@ -21,6 +21,7 @@
> >
<v-spacer /> <v-spacer />
<v-switch <v-switch
v-if="context.editPermission !== false"
v-model="organize" v-model="organize"
label="Organize" label="Organize"
class="mx-3" class="mx-3"
@@ -153,6 +154,9 @@
PropertyIcon, PropertyIcon,
LabeledFab, LabeledFab,
}, },
inject: {
context: { default: {} }
},
props: { props: {
creatureId: { creatureId: {
type: String, type: String,

View File

@@ -1,103 +1,128 @@
<template> <template>
<v-layout <v-layout
row row
wrap wrap
align-center align-center
justify-center justify-center
style="min-height: 48px;" style="min-height: 48px;"
:class="{ hover }" :class="{ hover }"
class="my-3 health-bar" class="my-3 health-bar"
:data-id="_id" :data-id="_id"
> >
<div <div
class="subheading text-truncate pa-2 name" class="subheading text-truncate pa-2 name"
@mouseover="hover = true" @mouseover="hover = true"
@mouseleave="hover = false" @mouseleave="hover = false"
@click="$emit('click')" @click="$emit('click')"
> >
{{ name }} {{ name }}
</div> </div>
<v-flex style="height: 20px; flex-basis: 300px; flex-grow: 100;"> <v-flex style="height: 20px; flex-basis: 300px; flex-grow: 100;">
<v-layout <v-layout
column column
align-center align-center
@click="edit" style="cursor: pointer;"
style="cursor: pointer;" class="bar"
class="bar" @click="edit"
> >
<v-progress-linear <v-progress-linear
:value="(value / maxValue) * 100" :value="(value / maxValue) * 100"
height="20" height="20"
color="green lighten-1" color="green lighten-1"
class="ma-0" class="ma-0"
> />
</v-progress-linear> <span
<span class="value"
class="value" style="margin-top: -20px; z-index: 1; font-size: 15px; font-weight: 600; height: 20px;"
style="margin-top: -20px; z-index: 1; font-size: 15px; font-weight: 600; height: 20px;" >
> {{ value }} / {{ maxValue }}
{{ value }} / {{ maxValue }} </span>
</span> </v-layout>
</v-layout> <transition name="transition">
<transition name="transition"> <v-toolbar
<v-toolbar v-if="editing"
v-if="editing" justify-center
justify-center height="48"
height="48" flat
flat class="transparent toolbar"
class="transparent toolbar" >
> <v-spacer />
<v-spacer /> <v-btn-toggle
<v-btn-toggle :value="operation === 'add' ? 0: operation === 'subtract' ? 1 : null"
:value="operation === 'add' ? 0: operation === 'subtract' ? 1 : null" class="mr-2"
@click="$refs.editInput.focus()" @click="$refs.editInput.focus()"
class="mr-2" >
> <v-btn
<v-btn :disabled="context.editPermission === false"
@click="toggleAdd(); $nextTick(() => $refs.editInput.focus())" class="filled"
class="filled" @click="toggleAdd(); $nextTick(() => $refs.editInput.focus())"
> >
<v-icon>add</v-icon> <v-icon>add</v-icon>
</v-btn> </v-btn>
<v-btn <v-btn
@click="toggleSubtract(); $nextTick(() => $refs.editInput.focus())" :disabled="context.editPermission === false"
class="filled" class="filled"
> @click="toggleSubtract(); $nextTick(() => $refs.editInput.focus())"
<v-icon>remove</v-icon> >
</v-btn> <v-icon>remove</v-icon>
</v-btn-toggle> </v-btn>
<v-text-field </v-btn-toggle>
solo <v-text-field
hide-details v-if="editing"
type="number" ref="editInput"
v-if="editing" solo
ref="editInput" hide-details
style="max-width: 120px;" type="number"
min="0" style="max-width: 120px;"
:value="editValue" min="0"
:prepend-inner-icon="operationIcon(operation)" :value="editValue"
@focus="$event.target.select()" :prepend-inner-icon="operationIcon(operation)"
@keypress="keypress" :disabled="context.editPermission === false"
> @focus="$event.target.select()"
</v-text-field> @keypress="keypress"
<v-btn small fab @click="commitEdit" class="filled" color="red"> />
<v-icon>done</v-icon> <v-btn
</v-btn> small
<v-btn small fab @click="cancelEdit" class="mx-0 filled"> fab
<v-icon>close</v-icon> class="filled"
</v-btn> color="red"
<v-spacer /> @click="commitEdit"
</v-toolbar> >
</transition> <v-icon>done</v-icon>
</v-flex> </v-btn>
<transition name="background-transition"> <v-btn
<div v-if="editing" class="page-tint" @click="cancelEdit" /> small
</transition> fab
</v-layout> class="mx-0 filled"
@click="cancelEdit"
>
<v-icon>close</v-icon>
</v-btn>
<v-spacer />
</v-toolbar>
</transition>
</v-flex>
<transition name="background-transition">
<div
v-if="editing"
class="page-tint"
@click="cancelEdit"
/>
</transition>
</v-layout>
</template> </template>
<script> <script>
export default { export default {
inject: {
context: { default: {} }
},
props: {
value: Number,
maxValue: Number,
name: String,
_id: String,
},
data() { data() {
return { return {
editing: false, editing: false,
@@ -106,12 +131,6 @@
hover: false, hover: false,
}; };
}, },
props: {
value: Number,
maxValue: Number,
name: String,
_id: String,
},
methods: { methods: {
edit() { edit() {
this.editing = true; this.editing = true;
@@ -138,7 +157,7 @@
case 'set': case 'set':
return 'forward'; return 'forward';
case 'add': case 'add':
return 'add'; return 'add';
case 'subtract': case 'subtract':
return 'remove'; return 'remove';
} }

View File

@@ -17,7 +17,7 @@
<v-btn <v-btn
icon icon
small small
:disabled="currentValue >= model.value" :disabled="currentValue >= model.value || context.editPermission === false"
@click="increment(1)" @click="increment(1)"
> >
<v-icon>arrow_drop_up</v-icon> <v-icon>arrow_drop_up</v-icon>
@@ -25,7 +25,7 @@
<v-btn <v-btn
icon icon
small small
:disabled="currentValue <= 0" :disabled="currentValue <= 0 || context.editPermission === false"
@click="increment(-1)" @click="increment(-1)"
> >
<v-icon>arrow_drop_down</v-icon> <v-icon>arrow_drop_down</v-icon>
@@ -68,6 +68,9 @@ import ComputedForCreature from '/imports/ui/components/computation/ComputedForC
export default { export default {
components: { components: {
Computed: ComputedForCreature, Computed: ComputedForCreature,
},
inject: {
context: { default: {} }
}, },
props: { props: {
model: { model: {

View File

@@ -1,37 +1,51 @@
<template lang="html"> <template lang="html">
<v-card class="resource-card layout row" :class="hover ? 'elevation-8': ''"> <v-card
<div class="buttons layout column justify-center pl-3"> class="resource-card layout row"
<v-btn icon small :disabled="currentValue >= value" @click="increment(1)"> :class="hover ? 'elevation-8': ''"
<v-icon>arrow_drop_up</v-icon> >
</v-btn> <div class="buttons layout column justify-center pl-3">
<v-btn icon small :disabled="currentValue <= 0" @click="increment(-1)"> <v-btn
<v-icon>arrow_drop_down</v-icon> icon
</v-btn> small
</div> :disabled="currentValue >= value || context.editPermission === false"
<div @click="increment(1)"
class="layout row align-center value pl-2 pr-3" >
> <v-icon>arrow_drop_up</v-icon>
<div class="display-1">{{currentValue}}</div> </v-btn>
<div class="title ml-2 max-value">/{{value}}</div> <v-btn
</div> icon
<div small
class="content layout row align-center pr-3" :disabled="currentValue <= 0 || context.editPermission === false"
@click="click" @click="increment(-1)"
@mouseover="hover = true" >
@mouseleave="hover = false" <v-icon>arrow_drop_down</v-icon>
> </v-btn>
<div class="text-truncate "> </div>
{{name}} <div
</div> class="layout row align-center value pl-2 pr-3"
</div> >
</v-card> <div class="display-1">
{{ currentValue }}
</div>
<div class="title ml-2 max-value">
/{{ value }}
</div>
</div>
<div
class="content layout row align-center pr-3"
@click="click"
@mouseover="hover = true"
@mouseleave="hover = false"
>
<div class="text-truncate ">
{{ name }}
</div>
</div>
</v-card>
</template> </template>
<script> <script>
export default { export default {
data(){ return{
hover: false,
}},
props: { props: {
_id: String, _id: String,
name: String, name: String,
@@ -39,6 +53,12 @@
value: Number, value: Number,
damage: Number, damage: Number,
}, },
data(){ return{
hover: false,
}},
inject: {
context: { default: {} }
},
computed: { computed: {
currentValue(){ currentValue(){
return this.value - (this.damage || 0); return this.value - (this.damage || 0);

View File

@@ -1,61 +1,92 @@
<template lang="html"> <template lang="html">
<v-list-tile class="spell-slot-list-tile" :class="{hover}"> <v-list-tile
class="spell-slot-list-tile"
:class="{hover}"
>
<v-list-tile-action>
<div
v-if="value > 4"
class="layout row align-center"
>
<div class="buttons layout column justify-center">
<v-btn
icon
small
:disabled="
currentValue >= value ||
context.editPermission === false
"
@click="increment(1)"
>
<v-icon>arrow_drop_up</v-icon>
</v-btn>
<v-btn
icon
small
:disabled="
currentValue <= 0 ||
context.editPermission === false
"
@click="increment(-1)"
>
<v-icon>arrow_drop_down</v-icon>
</v-btn>
</div>
<div
class="layout row value"
style="align-items: baseline;"
>
<div class="display-1">
{{ currentValue }}
</div>
<div class="title ml-2 max-value">
/{{ value }}
</div>
</div>
</div>
<v-list-tile-action> <div
v-else
class="layout row align-center justify-end slot-buttons"
>
<v-btn
v-for="i in value"
:key="i"
icon
small
:disabled="
!(i === currentValue || i === currentValue + 1) ||
context.editPermission === false
"
@click="increment(i > currentValue ? 1 : -1)"
>
<v-icon>
{{
i > currentValue ?
'radio_button_unchecked' :
'radio_button_checked'
}}
</v-icon>
</v-btn>
</div>
</v-list-tile-action>
<div class="layout row align-center" v-if="value > 4"> <v-list-tile-content
<div class="buttons layout column justify-center"> class="content ml-2"
<v-btn icon small :disabled="currentValue >= value" @click="increment(1)"> @click="click"
<v-icon>arrow_drop_up</v-icon> @mouseover="hover = true"
</v-btn> @mouseleave="hover = false"
<v-btn icon small :disabled="currentValue <= 0" @click="increment(-1)"> >
<v-icon>arrow_drop_down</v-icon> <v-list-tile-title>
</v-btn> {{ name }}
</div> </v-list-tile-title>
<div class="layout row value" style="align-items: baseline;"> </v-list-tile-content>
<div class="display-1">{{currentValue}}</div> </v-list-tile>
<div class="title ml-2 max-value">/{{value}}</div>
</div>
</div>
<div class="layout row align-center justify-end slot-buttons" v-else>
<v-btn
icon
small
v-for="i in value"
:disabled="!(i === currentValue || i === currentValue + 1)"
:key="i"
@click="increment(i > currentValue ? 1 : -1)"
>
<v-icon>{{
i > currentValue ?
'radio_button_unchecked' :
'radio_button_checked'
}}</v-icon>
</v-btn>
</div>
</v-list-tile-action>
<v-list-tile-content
class="content ml-2"
@click="click"
@mouseover="hover = true"
@mouseleave="hover = false"
>
<v-list-tile-title>
{{name}}
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</template> </template>
<script> <script>
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js'; import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
export default { export default {
data(){ return{
hover: false,
}},
props: { props: {
_id: String, _id: String,
name: String, name: String,
@@ -66,6 +97,12 @@ export default {
default: 0, default: 0,
}, },
}, },
data(){ return{
hover: false,
}},
inject: {
context: { default: {} }
},
computed: { computed: {
currentValue(){ currentValue(){
return this.value - this.damage; return this.value - this.damage;